about summary refs log tree commit diff stats
path: root/WitnessRandomizer/WitnessRandomizer.cpp
blob: 7f1ad6c206ab4faad98627dc4c59bd566c24f2fc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
/* BUGS:
 * Quarry colors are broken (specfically boathouse row 2 is translating wrong)
 * Desert flood exit isn't off properly
 * FEATURES:
 * Randomize audio logs
 * Randomize lasers
 * Tackle remaining areas (Treehouse, Keep, Shadows, Town, Monastery, Jungle, Bunker, Swamp)
 * Compile panel lists in a more reasonable way
 * Separate panels out by "square", which can probably be anywhere
 * List of panels which can be valid "Burn" (aka desert) substitutes: Prevent (or limit) panel counting
*/
#include "Memory.h"
#include "WitnessRandomizer.h"
#include <string>
#include <iostream>

int main(int argc, char** argv)
{
	WitnessRandomizer randomizer = WitnessRandomizer();

	//*
	if (argc == 2) {
		srand(atoi(argv[1])); // Seed with RNG from command line
	}

	std::vector<int> tutorialPanels = {
		// 0x0A3B5, // Back Left
		0x0A3B2, // Back Right
		0x00295, // Center Left
		0x00293, // Front Center
		0x002C2, // Front Left
		0x0C335, // Pillar
		0x0C373, // Patio floor
	};

	randomizer.Randomize(tutorialPanels, SWAP_TARGETS);

	std::vector<int> symmetryPanels = {
//		0x3C12B, // Glass Factory Discard
		0x01A54, // Glass Factory Entry
		0x00086, // Glass Factory Vertical Symmetry 1
		0x00087, // Glass Factory Vertical Symmetry 2
		0x00059, // Glass Factory Vertical Symmetry 3
		0x00062, // Glass Factory Vertical Symmetry 4
		0x0005C, // Glass Factory Vertical Symmetry 5
		// 0x17CC8, // Glass Factory Summon Boat
		0x0008D, // Glass Factory Rotational Symmetry 1
		0x00081, // Glass Factory Rotational Symmetry 2
		0x00083, // Glass Factory Rotational Symmetry 3
		0x00084, // Glass Factory Melting 1
		0x00082, // Glass Factory Melting 2
		0x0343A, // Glass Factory Melting 3

		0x000B0, // Symmetry Island Door 1
		0x00022, // Symmetry Island Black Dots 1
		0x00023, // Symmetry Island Black Dots 2
		0x00024, // Symmetry Island Black Dots 3
		0x00025, // Symmetry Island Black Dots 4
		0x00026, // Symmetry Island Black Dots 5
		0x0007C, // Symmetry Island Colored Dots 1
		0x0007E, // Symmetry Island Colored Dots 2
		0x00075, // Symmetry Island Colored Dots 3
		0x00073, // Symmetry Island Colored Dots 4
		0x00077, // Symmetry Island Colored Dots 5
		0x00079, // Symmetry Island Colored Dots 6
		0x00065, // Symmetry Island Fading Lines 1
		0x0006D, // Symmetry Island Fading Lines 2
		0x00072, // Symmetry Island Fading Lines 3
		0x0006F, // Symmetry Island Fading Lines 4
		0x00070, // Symmetry Island Fading Lines 5
		0x00071, // Symmetry Island Fading Lines 6
		0x00076, // Symmetry Island Fading Lines 7
		// 0x009B8, // Symmetry Island Transparent 1 // Too mean for right now
		// 0x003E8, // Symmetry Island Transparent 2 // Too mean for right now
		// 0x00A15, // Symmetry Island Transparent 3 // Too mean for right now
		// 0x00B53, // Symmetry Island Transparent 4 // Too mean for right now
		// 0x00B8D, // Symmetry Island Transparent 5 // Too mean for right now
		// 0x1C349, // Symmetry Island Door 2 - Collision fails here, sadly
		0x00A52, // Symmetry Island Laser Yellow 1
		0x00A57, // Symmetry Island Laser Yellow 2
		0x00A5B, // Symmetry Island Laser Yellow 3
		0x00A61, // Symmetry Island Laser Blue 1
		0x00A64, // Symmetry Island Laser Blue 2
		0x00A68, // Symmetry Island Laser Blue 3
		// 0x0360D, // Symmetry Island Laser
	};
	randomizer.Randomize(symmetryPanels, SWAP_PATHWAYS | SWAP_COLORS);



	std::vector<int> desertPanels = {
//		0x17CE7, // Desert Discard
//		0x0CC7B, // Desert Vault
//		0x0339E, // Desert Vault Box
		0x00698, // Desert Surface 1
		0x0048F, // Desert Surface 2
		0x09F92, // Desert Surface 3
//		0x09FA0, // Desert Surface 3 Control
		0x0A036, // Desert Surface 4
		0x09DA6, // Desert Surface 5
		0x0A049, // Desert Surface 6
		0x0A053, // Desert Surface 7
		0x09F94, // Desert Surface 8
//		0x09F86, // Desert Surface 8 Control
//		0x0C339, // Desert Surface Door
//		0x09FAA, // Desert Lightswitch
		0x00422, // Desert Light 1
		0x006E3, // Desert Light 2
//		0x0A02D, // Desert Light 3
		0x00C72, // Desert Pond 1
		0x0129D, // Desert Pond 2
		0x008BB, // Desert Pond 3
		0x0078D, // Desert Pond 4
		0x18313, // Desert Pond 5
//		0x0A249, // Desert Pond Exit Door
//		0x1C2DF, // Desert Flood Control Lower Far Left
//		0x1831E, // Desert Flood Control Lower Far Right
//		0x1C260, // Desert Flood Control Lower Near Left
//		0x1831C, // Desert Flood Control Lower Near Right
//		0x1C2F3, // Desert Flood Control Raise Far Left
//		0x1831D, // Desert Flood Control Raise Far Right
//		0x1C2B1, // Desert Flood Control Raise Near Left
//		0x1831B, // Desert Flood Control Raise Near Right
		0x04D18, // Desert Flood 1
		0x01205, // Desert Flood 2
		0x181AB, // Desert Flood 3
		0x0117A, // Desert Flood 4
		0x17ECA, // Desert Flood 5
//		0x18076, // Desert Flood Exit
//		0x0A15C, // Desert Final Left Convex
//		0x09FFF, // Desert Final Left Concave
//		0x0A15F, // Desert Final Near
//		0x17C31, // Desert Final Transparent
		0x012D7, // Desert Final Far
//		0x0A015, // Desert Final Far Control
//		0x03608, // Desert Laser
	};

	randomizer.Randomize(desertPanels, SWAP_PATHWAYS);

	std::vector<int> quarryPanels = {
		0x01E5A, // Mill Entry Door Left
		0x01E59, // Mill Entry Door Right
//		0x03678, // Mill Lower Ramp Contol
		0x00E0C, // Mill Lower Row 1
		0x01489, // Mill Lower Row 2
		0x0148A, // Mill Lower Row 3
		0x014D9, // Mill Lower Row 4
		0x014E7, // Mill Lower Row 5
		0x014E8, // Mill Lower Row 6
//		0x03679, // Mill Lower Lift Control
		0x00557, // Mill Upper Row 1
		0x005F1, // Mill Upper Row 2
		0x00620, // Mill Upper Row 3
		0x009F5, // Mill Upper Row 4
		0x0146C, // Mill Upper Row 5
		0x3C12D, // Mill Upper Row 6
		0x03686, // Mill Upper Row 7
		0x014E9, // Mill Upper Row 8
		0x0367C, // Mill Control Room 1
//		0x03675, // Mill Upper Lift Control
//		0x03676, // Mill Upper Ramp Control
		0x3C125, // Mill Control Room 2
//		0x275ED, // Mill EP Door
//		0x17CAC, // Mill Stairs Shortcut Door
		0x03677, // Mill Stairs Control
//		0x17CF0, // Mill Discard
//		0x17CC4, // Mill Elevator Control
		0x021D5, // Boathouse Ramp Activation Shapers
		0x034D4, // Boathouse Ramp Activation Stars
//		0x03852, // Boathouse Ramp Angle Control
		0x021B3, // Boathouse Erasers and Shapers 1
		0x021B4, // Boathouse Erasers and Shapers 2
		0x021B0, // Boathouse Erasers and Shapers 3
		0x021AF, // Boathouse Erasers and Shapers 4
		0x021AE, // Boathouse Erasers and Shapers 5
//		0x17CA6, // Boathouse Summon Boat
//		0x03858, // Boathouse Ramp Position Control
//		0x38663, // Boathouse Shortcut
		0x021B5, // Boathouse Erasers and Stars 1
		0x021B6, // Boathouse Erasers and Stars 2
		0x021B7, // Boathouse Erasers and Stars 3
		0x021BB, // Boathouse Erasers and Stars 4
		0x09DB5, // Boathouse Erasers and Stars 5
		0x09DB1, // Boathouse Erasers and Stars 6
		0x3C124, // Boathouse Erasers and Stars 7
		0x09DB3, // Boathouse Erasers Shapers and Stars 1
		0x09DB4, // Boathouse Erasers Shapers and Stars 2
		0x0A3CB, // Boathouse Erasers Shapers and Stars 3
		0x0A3CC, // Boathouse Erasers Shapers and Stars 4
		0x0A3D0, // Boathouse Erasers Shapers and Stars 5
//		0x275FA, // Boathouse Hook Control
		0x09E57, // Quarry Entry Gate 1
		0x17C09, // Quarry Entry Gate 2
//		0x03612, // Quarry Laser
	};
	randomizer.Randomize(quarryPanels, SWAP_PATHWAYS | SWAP_COLORS);


	/*/


	int MILL_L_1 = 0xE0C;
	int MILL_U_1 = 0x557;
	int QUARRY_E_1 = 0x9E57;
	int QUARRY_E_2 = 0x17C09;
	int MILL_E_1 = 0x1E5A;

	randomizer.SwapPanels(QUARRY_E_2, MILL_E_1, SWAP_PATHWAYS | SWAP_COLORS);
	//*/
}

WitnessRandomizer::WitnessRandomizer() : _memory(Memory("witness64_d3d11.exe"))
{
	// Turn off desert flood final
	_memory.WriteData<float>({0x5B28C0, 0x18, 0x18076*8, 0x2A8}, {0.0f});
	// Change desert floating target to desert flood final
	_memory.WriteData<int>({0x5B28C0, 0x18, 0x17ECA*8, 0x2BC}, {0x18077});
}

void WitnessRandomizer::Randomize(std::vector<int> panels, int flags) {
	for (size_t i=panels.size() - 1; i > 1; i--) {
		int target = rand() % i;
		if (i != target) {
			std::cout << "Swapping panels " << std::hex << panels[i] << " and " << std::hex << panels[target] << std::endl;
			SwapPanels(panels[i], panels[target], flags);
			std::swap(panels[i], panels[target]); // Panel indices in the array
		}
	}
}

void WitnessRandomizer::SwapPanels(int panel1, int panel2, int flags) {
	std::map<int, int> offsets;

	if (flags & SWAP_TARGETS) {
		offsets[0x2BC] = sizeof(int);
	}
	if (flags & SWAP_PATHWAYS) {
		offsets[0x3B8] = sizeof(int); // num_dots
		offsets[0x3BC] = sizeof(int); // num_connections
		offsets[0x3C8] = sizeof(void*); // *dot_positions
		offsets[0x3D0] = sizeof(void*); // *dot_flags
		offsets[0x3D8] = sizeof(void*); // *dot_connection_a
		offsets[0x3E0] = sizeof(void*); // *dot_connection_b
		offsets[0x440] = sizeof(void*); // *reflection_data
		offsets[0x448] = sizeof(int); // grid_size_x
		offsets[0x44C] = sizeof(int); // grid_size_y
		offsets[0x450] = sizeof(int); // style_flags // This is required to not ignore dots
		offsets[0x4B0] = sizeof(void*); // *panel_target
		offsets[0x4D8] = sizeof(void*); // *specular_texture

		offsets[0x420] = sizeof(void*); // *decorations
		offsets[0x428] = sizeof(void*); // *decoration_flags
		offsets[0x438] = sizeof(int); // num_decorations

		offsets[0x45C] = sizeof(int); // sequence_len
		offsets[0x460] = sizeof(void*); // *sequence
		offsets[0x468] = sizeof(int); // dot_sequence_len
		offsets[0x470] = sizeof(void*); // *dot_sequence
		offsets[0x478] = sizeof(int); // dot_sequence_len_reflection
		offsets[0x480] = sizeof(void*); // *dot_sequence_reflection

		offsets[0x3A4] = sizeof(float); // path_width_scale
		offsets[0x3A8] = sizeof(float); // startpoint_scale


		// TODO: Try using is_cylinder to swap into tutorial pillar. If it fails, discard.
		// Probably not: Extra back distance
		// SwapPanelData(panels[i], panels[target], 0x2FC, 125); // is_cylinder through max_connections
	}
	if (flags & SWAP_STYLE) {
		// 340 - pattern_scale
		// 288 - flash_mode
	}
	if (flags & SWAP_COLORS) {
		offsets[0xC8] = 16; // path_color
		offsets[0xD8] = 16; // reflection_path_color
//		offsets[0xE8] = 16; // deprecated_finished_path_color
		offsets[0xF8] = 16; // dot_color
		offsets[0x108] = 16; // active_color
		offsets[0x118] = 16; // background_region_color
		offsets[0x128] = 16; // success_color_a
		offsets[0x138] = 16; // success_color_b
		offsets[0x148] = 16; // strobe_color_a
		offsets[0x158] = 16; // strobe_color_b
		offsets[0x168] = 16; // error_color
//		offsets[0x178] = 16; // video_status_color
		offsets[0x188] = 16; // pattern_point_color
		offsets[0x198] = 16; // pattern_point_color_a
		offsets[0x1A8] = 16; // pattern_point_color_b
		offsets[0x1B8] = 16; // symbol_a
		offsets[0x1C8] = 16; // symbol_b
		offsets[0x1D8] = 16; // symbol_c
		offsets[0x1E8] = 16; // symbol_d
		offsets[0x1F8] = 16; // symbol_e
		offsets[0x208] = sizeof(int); // push_symbol_colors
		offsets[0x20C] = 16; // outer_background
		offsets[0x21C] = sizeof(int); // outer_background_mode
		offsets[0x4A8] = sizeof(void*); // *colored_regions
	}
	if (flags & SWAP_TRACED) {
		offsets[0x230] = 16; // traced_edges
	}


	for (auto const& [offset, size] : offsets) {
		SwapPanelData(panel1, panel2, offset, size);
	}
}

void WitnessRandomizer::SwapPanelData(int panel1, int panel2, int finalOffset, int dataSize) {
	// Currently wired for old version
	std::vector<int> panel1Offset = {0x5B28C0, 0x18, panel1*8, finalOffset};
	std::vector<int> panel2Offset = {0x5B28C0, 0x18, panel2*8, finalOffset};

	std::vector<byte> panel1Data = _memory.ReadData<byte>(panel1Offset, dataSize);
	std::vector<byte> panel2Data = _memory.ReadData<byte>(panel2Offset, dataSize);

	bool failed = _memory.WriteData<byte>(panel2Offset, panel1Data);
	if (failed) {
		_memory.WriteData<byte>(panel2Offset, panel1Data);
	}
	failed = _memory.WriteData<byte>(panel1Offset, panel2Data);
	if (failed) {
		_memory.WriteData<byte>(panel1Offset, panel2Data);
	}
}