about summary refs log tree commit diff stats
path: root/Source/Randomizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Randomizer.cpp')
-rw-r--r--Source/Randomizer.cpp534
1 files changed, 267 insertions, 267 deletions
diff --git a/Source/Randomizer.cpp b/Source/Randomizer.cpp index 2545c8f..13f381a 100644 --- a/Source/Randomizer.cpp +++ b/Source/Randomizer.cpp
@@ -102,356 +102,356 @@ Things to do for V2:
102 102
103template <class T> 103template <class T>
104int find(const std::vector<T> &data, T search, size_t startIndex = 0) { 104int find(const std::vector<T> &data, T search, size_t startIndex = 0) {
105 for (size_t i=startIndex ; i<data.size(); i++) { 105 for (size_t i=startIndex ; i<data.size(); i++) {
106 if (data[i] == search) return static_cast<int>(i); 106 if (data[i] == search) return static_cast<int>(i);
107 } 107 }
108 std::cout << "Couldn't find " << search << " in data!" << std::endl; 108 std::cout << "Couldn't find " << search << " in data!" << std::endl;
109 throw std::exception("Couldn't find value in data!"); 109 throw std::exception("Couldn't find value in data!");
110} 110}
111 111
112Randomizer::Randomizer(const std::shared_ptr<Memory>& memory) : _memory(memory) {} 112Randomizer::Randomizer(const std::shared_ptr<Memory>& memory) : _memory(memory) {}
113 113
114void Randomizer::Randomize() { 114void Randomizer::Randomize() {
115 // reveal_exit_hall - Prevent actually ending the game (EEE) 115 // reveal_exit_hall - Prevent actually ending the game (EEE)
116 _memory->AddSigScan({0x45, 0x8B, 0xF7, 0x48, 0x8B, 0x4D}, [&](int index){ 116 _memory->AddSigScan({0x45, 0x8B, 0xF7, 0x48, 0x8B, 0x4D}, [&](int index){
117 _memory->WriteData<byte>({index + 0x15}, {0xEB}); // jz -> jmp 117 _memory->WriteData<byte>({index + 0x15}, {0xEB}); // jz -> jmp
118 }); 118 });
119 119
120 // begin_endgame_1 - Prevent actually ending the game (Wonkavator) 120 // begin_endgame_1 - Prevent actually ending the game (Wonkavator)
121 _memory->AddSigScan({0x83, 0x7C, 0x01, 0xD0, 0x04}, [&](int index){ 121 _memory->AddSigScan({0x83, 0x7C, 0x01, 0xD0, 0x04}, [&](int index){
122 if (GLOBALS == 0x5B28C0) { // Version differences. 122 if (GLOBALS == 0x5B28C0) { // Version differences.
123 index += 0x75; 123 index += 0x75;
124 } else if (GLOBALS == 0x62D0A0) { 124 } else if (GLOBALS == 0x62D0A0) {
125 index += 0x86; 125 index += 0x86;
126 } 126 }
127 _memory->WriteData<byte>({index}, {0xEB}); // jz -> jmp 127 _memory->WriteData<byte>({index}, {0xEB}); // jz -> jmp
128 }); 128 });
129 // Sig scans will be run during challenge randomization. 129 // Sig scans will be run during challenge randomization.
130 130
131 // Seed challenge first for future-proofing 131 // Seed challenge first for future-proofing
132 RandomizeChallenge(); 132 RandomizeChallenge();
133 133
134 // Content swaps -- must happen before squarePanels 134 // Content swaps -- must happen before squarePanels
135 Randomize(upDownPanels, SWAP::LINES | SWAP::COLORS); 135 Randomize(upDownPanels, SWAP::LINES | SWAP::COLORS);
136 Randomize(leftForwardRightPanels, SWAP::LINES | SWAP::COLORS); 136 Randomize(leftForwardRightPanels, SWAP::LINES | SWAP::COLORS);
137 137
138 Randomize(squarePanels, SWAP::LINES | SWAP::COLORS); 138 Randomize(squarePanels, SWAP::LINES | SWAP::COLORS);
139 139
140 // Individual area modifications 140 // Individual area modifications
141 RandomizeTutorial(); 141 RandomizeTutorial();
142 RandomizeDesert(); 142 RandomizeDesert();
143 RandomizeQuarry(); 143 RandomizeQuarry();
144 RandomizeTreehouse(); 144 RandomizeTreehouse();
145 RandomizeKeep(); 145 RandomizeKeep();
146 RandomizeShadows(); 146 RandomizeShadows();
147 RandomizeMonastery(); 147 RandomizeMonastery();
148 RandomizeBunker(); 148 RandomizeBunker();
149 RandomizeJungle(); 149 RandomizeJungle();
150 RandomizeSwamp(); 150 RandomizeSwamp();
151 RandomizeMountain(); 151 RandomizeMountain();
152 RandomizeTown(); 152 RandomizeTown();
153 RandomizeSymmetry(); 153 RandomizeSymmetry();
154 // RandomizeAudioLogs(); 154 // RandomizeAudioLogs();
155} 155}
156 156
157void Randomizer::AdjustSpeed() { 157void Randomizer::AdjustSpeed() {
158 // Desert Surface Final Control 158 // Desert Surface Final Control
159 _memory->WriteEntityData<float>(0x09F95, OPEN_RATE, {0.04f}); // 4x 159 _memory->WriteEntityData<float>(0x09F95, OPEN_RATE, {0.04f}); // 4x
160 // Swamp Sliding Bridge 160 // Swamp Sliding Bridge
161 _memory->WriteEntityData<float>(0x0061A, OPEN_RATE, {0.1f}); // 4x 161 _memory->WriteEntityData<float>(0x0061A, OPEN_RATE, {0.1f}); // 4x
162 // Mountain 2 Elevator 162 // Mountain 2 Elevator
163 _memory->WriteEntityData<float>(0x09EEC, OPEN_RATE, {0.075f}); // 3x 163 _memory->WriteEntityData<float>(0x09EEC, OPEN_RATE, {0.075f}); // 3x
164} 164}
165 165
166void Randomizer::RandomizeLasers() { 166void Randomizer::RandomizeLasers() {
167 Randomize(lasers, SWAP::TARGETS); 167 Randomize(lasers, SWAP::TARGETS);
168 // Read the target of keep front laser, and write it to keep back laser. 168 // Read the target of keep front laser, and write it to keep back laser.
169 std::vector<int> keepFrontLaserTarget = _memory->ReadEntityData<int>(0x0360E, TARGET, 1); 169 std::vector<int> keepFrontLaserTarget = _memory->ReadEntityData<int>(0x0360E, TARGET, 1);
170 _memory->WriteEntityData<int>(0x03317, TARGET, keepFrontLaserTarget); 170 _memory->WriteEntityData<int>(0x03317, TARGET, keepFrontLaserTarget);
171} 171}
172 172
173void Randomizer::PreventSnipes() 173void Randomizer::PreventSnipes()
174{ 174{
175 // Distance-gate swamp snipe 1 to prevent RNG swamp snipe 175 // Distance-gate swamp snipe 1 to prevent RNG swamp snipe
176 _memory->WriteEntityData<float>(0x17C05, MAX_BROADCAST_DISTANCE, {15.0}); 176 _memory->WriteEntityData<float>(0x17C05, MAX_BROADCAST_DISTANCE, {15.0});
177 // Distance-gate shadows laser to prevent sniping through the bars 177 // Distance-gate shadows laser to prevent sniping through the bars
178 _memory->WriteEntityData<float>(0x19650, MAX_BROADCAST_DISTANCE, {2.5}); 178 _memory->WriteEntityData<float>(0x19650, MAX_BROADCAST_DISTANCE, {2.5});
179} 179}
180 180
181// Private methods 181// Private methods
182void Randomizer::RandomizeTutorial() { 182void Randomizer::RandomizeTutorial() {
183 // Disable tutorial cursor speed modifications (not working?) 183 // Disable tutorial cursor speed modifications (not working?)
184 _memory->WriteEntityData<float>(0x00295, CURSOR_SPEED_SCALE, {1.0}); 184 _memory->WriteEntityData<float>(0x00295, CURSOR_SPEED_SCALE, {1.0});
185 _memory->WriteEntityData<float>(0x0C373, CURSOR_SPEED_SCALE, {1.0}); 185 _memory->WriteEntityData<float>(0x0C373, CURSOR_SPEED_SCALE, {1.0});
186 _memory->WriteEntityData<float>(0x00293, CURSOR_SPEED_SCALE, {1.0}); 186 _memory->WriteEntityData<float>(0x00293, CURSOR_SPEED_SCALE, {1.0});
187 _memory->WriteEntityData<float>(0x002C2, CURSOR_SPEED_SCALE, {1.0}); 187 _memory->WriteEntityData<float>(0x002C2, CURSOR_SPEED_SCALE, {1.0});
188} 188}
189 189
190void Randomizer::RandomizeSymmetry() { 190void Randomizer::RandomizeSymmetry() {
191 std::vector<int> randomOrder(transparent.size(), 0); 191 std::vector<int> randomOrder(transparent.size(), 0);
192 std::iota(randomOrder.begin(), randomOrder.end(), 0); 192 std::iota(randomOrder.begin(), randomOrder.end(), 0);
193 RandomizeRange(randomOrder, SWAP::NONE, 1, 5); 193 RandomizeRange(randomOrder, SWAP::NONE, 1, 5);
194 ReassignTargets(transparent, randomOrder); 194 ReassignTargets(transparent, randomOrder);
195} 195}
196 196
197void Randomizer::RandomizeDesert() { 197void Randomizer::RandomizeDesert() {
198 Randomize(desertPanels, SWAP::LINES); 198 Randomize(desertPanels, SWAP::LINES);
199 199
200 // Turn off desert surface 8 200 // Turn off desert surface 8
201 _memory->WriteEntityData<float>(0x09F94, POWER, {0.0, 0.0}); 201 _memory->WriteEntityData<float>(0x09F94, POWER, {0.0, 0.0});
202 // Turn off desert flood final 202 // Turn off desert flood final
203 _memory->WriteEntityData<float>(0x18076, POWER, {0.0, 0.0}); 203 _memory->WriteEntityData<float>(0x18076, POWER, {0.0, 0.0});
204 // Change desert floating target to desert flood final 204 // Change desert floating target to desert flood final
205 _memory->WriteEntityData<int>(0x17ECA, TARGET, {0x18077}); 205 _memory->WriteEntityData<int>(0x17ECA, TARGET, {0x18077});
206} 206}
207 207
208void Randomizer::RandomizeQuarry() { 208void Randomizer::RandomizeQuarry() {
209} 209}
210 210
211void Randomizer::RandomizeTreehouse() { 211void Randomizer::RandomizeTreehouse() {
212 // Ensure that whatever pivot panels we have are flagged as "pivotable" 212 // Ensure that whatever pivot panels we have are flagged as "pivotable"
213 int panelFlags = _memory->ReadEntityData<int>(0x17DD1, STYLE_FLAGS, 1)[0]; 213 int panelFlags = _memory->ReadEntityData<int>(0x17DD1, STYLE_FLAGS, 1)[0];
214 _memory->WriteEntityData<int>(0x17DD1, STYLE_FLAGS, {panelFlags | 0x8000}); 214 _memory->WriteEntityData<int>(0x17DD1, STYLE_FLAGS, {panelFlags | 0x8000});
215 panelFlags = _memory->ReadEntityData<int>(0x17CE3, STYLE_FLAGS, 1)[0]; 215 panelFlags = _memory->ReadEntityData<int>(0x17CE3, STYLE_FLAGS, 1)[0];
216 _memory->WriteEntityData<int>(0x17CE3, STYLE_FLAGS, {panelFlags | 0x8000}); 216 _memory->WriteEntityData<int>(0x17CE3, STYLE_FLAGS, {panelFlags | 0x8000});
217 panelFlags = _memory->ReadEntityData<int>(0x17DB7, STYLE_FLAGS, 1)[0]; 217 panelFlags = _memory->ReadEntityData<int>(0x17DB7, STYLE_FLAGS, 1)[0];
218 _memory->WriteEntityData<int>(0x17DB7, STYLE_FLAGS, {panelFlags | 0x8000}); 218 _memory->WriteEntityData<int>(0x17DB7, STYLE_FLAGS, {panelFlags | 0x8000});
219 panelFlags = _memory->ReadEntityData<int>(0x17E52, STYLE_FLAGS, 1)[0]; 219 panelFlags = _memory->ReadEntityData<int>(0x17E52, STYLE_FLAGS, 1)[0];
220 _memory->WriteEntityData<int>(0x17E52, STYLE_FLAGS, {panelFlags | 0x8000}); 220 _memory->WriteEntityData<int>(0x17E52, STYLE_FLAGS, {panelFlags | 0x8000});
221} 221}
222 222
223void Randomizer::RandomizeKeep() { 223void Randomizer::RandomizeKeep() {
224} 224}
225 225
226void Randomizer::RandomizeShadows() { 226void Randomizer::RandomizeShadows() {
227 // Change the shadows tutorial cable to only activate avoid 227 // Change the shadows tutorial cable to only activate avoid
228 _memory->WriteEntityData<int>(0x319A8, CABLE_TARGET_2, {0}); 228 _memory->WriteEntityData<int>(0x319A8, CABLE_TARGET_2, {0});
229 // Change shadows avoid 8 to power shadows follow 229 // Change shadows avoid 8 to power shadows follow
230 _memory->WriteEntityData<int>(0x1972F, TARGET, {0x1C34C}); 230 _memory->WriteEntityData<int>(0x1972F, TARGET, {0x1C34C});
231 231
232 std::vector<int> randomOrder(shadowsPanels.size(), 0); 232 std::vector<int> randomOrder(shadowsPanels.size(), 0);
233 std::iota(randomOrder.begin(), randomOrder.end(), 0); 233 std::iota(randomOrder.begin(), randomOrder.end(), 0);
234 RandomizeRange(randomOrder, SWAP::NONE, 0, 8); // Tutorial 234 RandomizeRange(randomOrder, SWAP::NONE, 0, 8); // Tutorial
235 RandomizeRange(randomOrder, SWAP::NONE, 8, 16); // Avoid 235 RandomizeRange(randomOrder, SWAP::NONE, 8, 16); // Avoid
236 RandomizeRange(randomOrder, SWAP::NONE, 16, 21); // Follow 236 RandomizeRange(randomOrder, SWAP::NONE, 16, 21); // Follow
237 ReassignTargets(shadowsPanels, randomOrder); 237 ReassignTargets(shadowsPanels, randomOrder);
238 // Turn off original starting panel 238 // Turn off original starting panel
239 _memory->WriteEntityData<float>(shadowsPanels[0], POWER, {0.0f, 0.0f}); 239 _memory->WriteEntityData<float>(shadowsPanels[0], POWER, {0.0f, 0.0f});
240 // Turn on new starting panel 240 // Turn on new starting panel
241 _memory->WriteEntityData<float>(shadowsPanels[randomOrder[0]], POWER, {1.0f, 1.0f}); 241 _memory->WriteEntityData<float>(shadowsPanels[randomOrder[0]], POWER, {1.0f, 1.0f});
242} 242}
243 243
244void Randomizer::RandomizeTown() { 244void Randomizer::RandomizeTown() {
245 // @Hack...? To open the gate at the end 245 // @Hack...? To open the gate at the end
246 std::vector<int> randomOrder(orchard.size() + 1, 0); 246 std::vector<int> randomOrder(orchard.size() + 1, 0);
247 std::iota(randomOrder.begin(), randomOrder.end(), 0); 247 std::iota(randomOrder.begin(), randomOrder.end(), 0);
248 RandomizeRange(randomOrder, SWAP::NONE, 1, 5); 248 RandomizeRange(randomOrder, SWAP::NONE, 1, 5);
249 // Ensure that we open the gate before the final puzzle (by swapping) 249 // Ensure that we open the gate before the final puzzle (by swapping)
250 int panel3Index = find(randomOrder, 3); 250 int panel3Index = find(randomOrder, 3);
251 int panel4Index = find(randomOrder, 4); 251 int panel4Index = find(randomOrder, 4);
252 randomOrder[min(panel3Index, panel4Index)] = 3; 252 randomOrder[min(panel3Index, panel4Index)] = 3;
253 randomOrder[max(panel3Index, panel4Index)] = 4; 253 randomOrder[max(panel3Index, panel4Index)] = 4;
254 ReassignTargets(orchard, randomOrder); 254 ReassignTargets(orchard, randomOrder);
255} 255}
256 256
257void Randomizer::RandomizeMonastery() { 257void Randomizer::RandomizeMonastery() {
258 std::vector<int> randomOrder(monasteryPanels.size(), 0); 258 std::vector<int> randomOrder(monasteryPanels.size(), 0);
259 std::iota(randomOrder.begin(), randomOrder.end(), 0); 259 std::iota(randomOrder.begin(), randomOrder.end(), 0);
260 RandomizeRange(randomOrder, SWAP::NONE, 3, 9); // Outer 2 & 3, Inner 1-4 260 RandomizeRange(randomOrder, SWAP::NONE, 3, 9); // Outer 2 & 3, Inner 1-4
261 ReassignTargets(monasteryPanels, randomOrder); 261 ReassignTargets(monasteryPanels, randomOrder);
262} 262}
263 263
264void Randomizer::RandomizeBunker() { 264void Randomizer::RandomizeBunker() {
265 std::vector<int> randomOrder(bunkerPanels.size(), 0); 265 std::vector<int> randomOrder(bunkerPanels.size(), 0);
266 std::iota(randomOrder.begin(), randomOrder.end(), 0); 266 std::iota(randomOrder.begin(), randomOrder.end(), 0);
267 // Randomize Tutorial 2-Advanced Tutorial 4 + Glass 1 267 // Randomize Tutorial 2-Advanced Tutorial 4 + Glass 1
268 // Tutorial 1 cannot be randomized, since no other panel can start on 268 // Tutorial 1 cannot be randomized, since no other panel can start on
269 // Glass 1 will become door + glass 1, due to the targetting system 269 // Glass 1 will become door + glass 1, due to the targetting system
270 RandomizeRange(randomOrder, SWAP::NONE, 1, 10); 270 RandomizeRange(randomOrder, SWAP::NONE, 1, 10);
271 // Randomize Glass 1-3 into everything after the door/glass 1 271 // Randomize Glass 1-3 into everything after the door/glass 1
272 const size_t glass1Index = find(randomOrder, 9); 272 const size_t glass1Index = find(randomOrder, 9);
273 RandomizeRange(randomOrder, SWAP::NONE, glass1Index + 1, 12); 273 RandomizeRange(randomOrder, SWAP::NONE, glass1Index + 1, 12);
274 ReassignTargets(bunkerPanels, randomOrder); 274 ReassignTargets(bunkerPanels, randomOrder);
275} 275}
276 276
277void Randomizer::RandomizeJungle() { 277void Randomizer::RandomizeJungle() {
278 std::vector<int> randomOrder(junglePanels.size(), 0); 278 std::vector<int> randomOrder(junglePanels.size(), 0);
279 std::iota(randomOrder.begin(), randomOrder.end(), 0); 279 std::iota(randomOrder.begin(), randomOrder.end(), 0);
280 // Waves 1 cannot be randomized, since no other panel can start on 280 // Waves 1 cannot be randomized, since no other panel can start on
281 RandomizeRange(randomOrder, SWAP::NONE, 1, 7); // Waves 2-7 281 RandomizeRange(randomOrder, SWAP::NONE, 1, 7); // Waves 2-7
282 RandomizeRange(randomOrder, SWAP::NONE, 8, 13); // Pitches 1-6 282 RandomizeRange(randomOrder, SWAP::NONE, 8, 13); // Pitches 1-6
283 ReassignTargets(junglePanels, randomOrder); 283 ReassignTargets(junglePanels, randomOrder);
284 284
285 // Fix the wall's target to point back to the cable, and the cable to point to the pitches panel. 285 // Fix the wall's target to point back to the cable, and the cable to point to the pitches panel.
286 // auto wallTarget = _memory->ReadPanelData<int>(junglePanels[7], TARGET, 1); 286 // auto wallTarget = _memory->ReadPanelData<int>(junglePanels[7], TARGET, 1);
287 // _memory->WritePanelData<int>(junglePanels[7], TARGET, {0x3C113}); 287 // _memory->WritePanelData<int>(junglePanels[7], TARGET, {0x3C113});
288 // _memory->WritePanelData<int>(0x3C112, CABLE_TARGET_1, wallTarget); 288 // _memory->WritePanelData<int>(0x3C112, CABLE_TARGET_1, wallTarget);
289} 289}
290 290
291void Randomizer::RandomizeSwamp() { 291void Randomizer::RandomizeSwamp() {
292} 292}
293 293
294void Randomizer::RandomizeMountain() { 294void Randomizer::RandomizeMountain() {
295 // Randomize multipanel 295 // Randomize multipanel
296 Randomize(mountainMultipanel, SWAP::LINES | SWAP::COLORS); 296 Randomize(mountainMultipanel, SWAP::LINES | SWAP::COLORS);
297 297
298 // Randomize final pillars order 298 // Randomize final pillars order
299 std::vector<int> targets = {pillars[0] + 1}; 299 std::vector<int> targets = {pillars[0] + 1};
300 for (const int pillar : pillars) { 300 for (const int pillar : pillars) {
301 int target = _memory->ReadEntityData<int>(pillar, TARGET, 1)[0]; 301 int target = _memory->ReadEntityData<int>(pillar, TARGET, 1)[0];
302 targets.push_back(target); 302 targets.push_back(target);
303 } 303 }
304 targets[5] = pillars[5] + 1; 304 targets[5] = pillars[5] + 1;
305 305
306 std::vector<int> randomOrder(pillars.size(), 0); 306 std::vector<int> randomOrder(pillars.size(), 0);
307 std::iota(randomOrder.begin(), randomOrder.end(), 0); 307 std::iota(randomOrder.begin(), randomOrder.end(), 0);
308 RandomizeRange(randomOrder, SWAP::NONE, 0, 4); // Left Pillars 1-4 308 RandomizeRange(randomOrder, SWAP::NONE, 0, 4); // Left Pillars 1-4
309 RandomizeRange(randomOrder, SWAP::NONE, 5, 9); // Right Pillars 1-4 309 RandomizeRange(randomOrder, SWAP::NONE, 5, 9); // Right Pillars 1-4
310 ReassignTargets(pillars, randomOrder, targets); 310 ReassignTargets(pillars, randomOrder, targets);
311 // Turn off original starting panels 311 // Turn off original starting panels
312 _memory->WriteEntityData<float>(pillars[0], POWER, {0.0f, 0.0f}); 312 _memory->WriteEntityData<float>(pillars[0], POWER, {0.0f, 0.0f});
313 _memory->WriteEntityData<float>(pillars[5], POWER, {0.0f, 0.0f}); 313 _memory->WriteEntityData<float>(pillars[5], POWER, {0.0f, 0.0f});
314 // Turn on new starting panels 314 // Turn on new starting panels
315 _memory->WriteEntityData<float>(pillars[randomOrder[0]], POWER, {1.0f, 1.0f}); 315 _memory->WriteEntityData<float>(pillars[randomOrder[0]], POWER, {1.0f, 1.0f});
316 _memory->WriteEntityData<float>(pillars[randomOrder[5]], POWER, {1.0f, 1.0f}); 316 _memory->WriteEntityData<float>(pillars[randomOrder[5]], POWER, {1.0f, 1.0f});
317} 317}
318 318
319void Randomizer::RandomizeChallenge() { 319void Randomizer::RandomizeChallenge() {
320 ChallengeRandomizer cr(_memory, Random::RandInt(1, 0x7FFFFFFF)); // 0 will trigger an "RNG not initialized" block 320 ChallengeRandomizer cr(_memory, Random::RandInt(1, 0x7FFFFFFF)); // 0 will trigger an "RNG not initialized" block
321 for (int panel : challengePanels) { 321 for (int panel : challengePanels) {
322 _memory->WriteEntityData<int>(panel, POWER_OFF_ON_FAIL, {0}); 322 _memory->WriteEntityData<int>(panel, POWER_OFF_ON_FAIL, {0});
323 } 323 }
324} 324}
325 325
326void Randomizer::RandomizeAudioLogs() { 326void Randomizer::RandomizeAudioLogs() {
327 std::vector<int> randomOrder(audiologs.size(), 0); 327 std::vector<int> randomOrder(audiologs.size(), 0);
328 std::iota(randomOrder.begin(), randomOrder.end(), 0); 328 std::iota(randomOrder.begin(), randomOrder.end(), 0);
329 Randomize(randomOrder, SWAP::NONE); 329 Randomize(randomOrder, SWAP::NONE);
330 ReassignNames(audiologs, randomOrder); 330 ReassignNames(audiologs, randomOrder);
331} 331}
332 332
333void Randomizer::Randomize(std::vector<int>& panels, int flags) { 333void Randomizer::Randomize(std::vector<int>& panels, int flags) {
334 return RandomizeRange(panels, flags, 0, panels.size()); 334 return RandomizeRange(panels, flags, 0, panels.size());
335} 335}
336 336
337// Range is [start, end) 337// Range is [start, end)
338void Randomizer::RandomizeRange(std::vector<int> &panels, int flags, size_t startIndex, size_t endIndex) { 338void Randomizer::RandomizeRange(std::vector<int> &panels, int flags, size_t startIndex, size_t endIndex) {
339 if (panels.size() == 0) return; 339 if (panels.size() == 0) return;
340 if (startIndex >= endIndex) return; 340 if (startIndex >= endIndex) return;
341 if (endIndex >= panels.size()) endIndex = static_cast<int>(panels.size()); 341 if (endIndex >= panels.size()) endIndex = static_cast<int>(panels.size());
342 for (size_t i = endIndex-1; i > startIndex; i--) { 342 for (size_t i = endIndex-1; i > startIndex; i--) {
343 const int target = Random::RandInt(static_cast<int>(startIndex), static_cast<int>(i)); 343 const int target = Random::RandInt(static_cast<int>(startIndex), static_cast<int>(i));
344 if (i != target) { 344 if (i != target) {
345 // std::cout << "Swapping panels " << std::hex << panels[i] << " and " << std::hex << panels[target] << std::endl; 345 // std::cout << "Swapping panels " << std::hex << panels[i] << " and " << std::hex << panels[target] << std::endl;
346 SwapPanels(panels[i], panels[target], flags); 346 SwapPanels(panels[i], panels[target], flags);
347 std::swap(panels[i], panels[target]); // Panel indices in the array 347 std::swap(panels[i], panels[target]); // Panel indices in the array
348 } 348 }
349 } 349 }
350} 350}
351 351
352void Randomizer::SwapPanels(int panel1, int panel2, int flags) { 352void Randomizer::SwapPanels(int panel1, int panel2, int flags) {
353 std::map<int, int> offsets; 353 std::map<int, int> offsets;
354 354
355 if (flags & SWAP::TARGETS) { 355 if (flags & SWAP::TARGETS) {
356 offsets[TARGET] = sizeof(int); 356 offsets[TARGET] = sizeof(int);
357 } 357 }
358 if (flags & SWAP::AUDIO_NAMES) { 358 if (flags & SWAP::AUDIO_NAMES) {
359 offsets[AUDIO_LOG_NAME] = sizeof(void*); 359 offsets[AUDIO_LOG_NAME] = sizeof(void*);
360 } 360 }
361 if (flags & SWAP::COLORS) { 361 if (flags & SWAP::COLORS) {
362 offsets[PATH_COLOR] = 16; 362 offsets[PATH_COLOR] = 16;
363 offsets[REFLECTION_PATH_COLOR] = 16; 363 offsets[REFLECTION_PATH_COLOR] = 16;
364 offsets[DOT_COLOR] = 16; 364 offsets[DOT_COLOR] = 16;
365 offsets[ACTIVE_COLOR] = 16; 365 offsets[ACTIVE_COLOR] = 16;
366 offsets[BACKGROUND_REGION_COLOR] = 12; // Not copying alpha to preserve transparency. 366 offsets[BACKGROUND_REGION_COLOR] = 12; // Not copying alpha to preserve transparency.
367 offsets[SUCCESS_COLOR_A] = 16; 367 offsets[SUCCESS_COLOR_A] = 16;
368 offsets[SUCCESS_COLOR_B] = 16; 368 offsets[SUCCESS_COLOR_B] = 16;
369 offsets[STROBE_COLOR_A] = 16; 369 offsets[STROBE_COLOR_A] = 16;
370 offsets[STROBE_COLOR_B] = 16; 370 offsets[STROBE_COLOR_B] = 16;
371 offsets[ERROR_COLOR] = 16; 371 offsets[ERROR_COLOR] = 16;
372 offsets[PATTERN_POINT_COLOR] = 16; 372 offsets[PATTERN_POINT_COLOR] = 16;
373 offsets[PATTERN_POINT_COLOR_A] = 16; 373 offsets[PATTERN_POINT_COLOR_A] = 16;
374 offsets[PATTERN_POINT_COLOR_B] = 16; 374 offsets[PATTERN_POINT_COLOR_B] = 16;
375 offsets[SYMBOL_A] = 16; 375 offsets[SYMBOL_A] = 16;
376 offsets[SYMBOL_B] = 16; 376 offsets[SYMBOL_B] = 16;
377 offsets[SYMBOL_C] = 16; 377 offsets[SYMBOL_C] = 16;
378 offsets[SYMBOL_D] = 16; 378 offsets[SYMBOL_D] = 16;
379 offsets[SYMBOL_E] = 16; 379 offsets[SYMBOL_E] = 16;
380 offsets[PUSH_SYMBOL_COLORS] = sizeof(int); 380 offsets[PUSH_SYMBOL_COLORS] = sizeof(int);
381 offsets[OUTER_BACKGROUND] = 16; 381 offsets[OUTER_BACKGROUND] = 16;
382 offsets[OUTER_BACKGROUND_MODE] = sizeof(int); 382 offsets[OUTER_BACKGROUND_MODE] = sizeof(int);
383 // These two control the "burn intensity", but I can't swap out burn marks in new ver, so they should probably stay tied to each frame. 383 // These two control the "burn intensity", but I can't swap out burn marks in new ver, so they should probably stay tied to each frame.
384 // offsets[SPECULAR_ADD] = sizeof(float); 384 // offsets[SPECULAR_ADD] = sizeof(float);
385 // offsets[SPECULAR_POWER] = sizeof(int); 385 // offsets[SPECULAR_POWER] = sizeof(int);
386 offsets[NUM_COLORED_REGIONS] = sizeof(int); 386 offsets[NUM_COLORED_REGIONS] = sizeof(int);
387 offsets[COLORED_REGIONS] = sizeof(void*); 387 offsets[COLORED_REGIONS] = sizeof(void*);
388 } 388 }
389 if (flags & SWAP::LINES) { 389 if (flags & SWAP::LINES) {
390 offsets[TRACED_EDGES] = 16; 390 offsets[TRACED_EDGES] = 16;
391 offsets[AUDIO_PREFIX] = sizeof(void*); 391 offsets[AUDIO_PREFIX] = sizeof(void*);
392// offsets[IS_CYLINDER] = sizeof(int); 392// offsets[IS_CYLINDER] = sizeof(int);
393// offsets[CYLINDER_Z0] = sizeof(float); 393// offsets[CYLINDER_Z0] = sizeof(float);
394// offsets[CYLINDER_Z1] = sizeof(float); 394// offsets[CYLINDER_Z1] = sizeof(float);
395// offsets[CYLINDER_RADIUS] = sizeof(float); 395// offsets[CYLINDER_RADIUS] = sizeof(float);
396 offsets[PATH_WIDTH_SCALE] = sizeof(float); 396 offsets[PATH_WIDTH_SCALE] = sizeof(float);
397 offsets[STARTPOINT_SCALE] = sizeof(float); 397 offsets[STARTPOINT_SCALE] = sizeof(float);
398 offsets[NUM_DOTS] = sizeof(int); 398 offsets[NUM_DOTS] = sizeof(int);
399 offsets[NUM_CONNECTIONS] = sizeof(int); 399 offsets[NUM_CONNECTIONS] = sizeof(int);
400 offsets[DOT_POSITIONS] = sizeof(void*); 400 offsets[DOT_POSITIONS] = sizeof(void*);
401 offsets[DOT_FLAGS] = sizeof(void*); 401 offsets[DOT_FLAGS] = sizeof(void*);
402 offsets[DOT_CONNECTION_A] = sizeof(void*); 402 offsets[DOT_CONNECTION_A] = sizeof(void*);
403 offsets[DOT_CONNECTION_B] = sizeof(void*); 403 offsets[DOT_CONNECTION_B] = sizeof(void*);
404 offsets[DECORATIONS] = sizeof(void*); 404 offsets[DECORATIONS] = sizeof(void*);
405 offsets[DECORATION_FLAGS] = sizeof(void*); 405 offsets[DECORATION_FLAGS] = sizeof(void*);
406 offsets[DECORATION_COLORS] = sizeof(void*); 406 offsets[DECORATION_COLORS] = sizeof(void*);
407 offsets[NUM_DECORATIONS] = sizeof(int); 407 offsets[NUM_DECORATIONS] = sizeof(int);
408 offsets[REFLECTION_DATA] = sizeof(void*); 408 offsets[REFLECTION_DATA] = sizeof(void*);
409 offsets[GRID_SIZE_X] = sizeof(int); 409 offsets[GRID_SIZE_X] = sizeof(int);
410 offsets[GRID_SIZE_Y] = sizeof(int); 410 offsets[GRID_SIZE_Y] = sizeof(int);
411 offsets[STYLE_FLAGS] = sizeof(int); 411 offsets[STYLE_FLAGS] = sizeof(int);
412 offsets[SEQUENCE_LEN] = sizeof(int); 412 offsets[SEQUENCE_LEN] = sizeof(int);
413 offsets[SEQUENCE] = sizeof(void*); 413 offsets[SEQUENCE] = sizeof(void*);
414 offsets[DOT_SEQUENCE_LEN] = sizeof(int); 414 offsets[DOT_SEQUENCE_LEN] = sizeof(int);
415 offsets[DOT_SEQUENCE] = sizeof(void*); 415 offsets[DOT_SEQUENCE] = sizeof(void*);
416 offsets[DOT_SEQUENCE_LEN_REFLECTION] = sizeof(int); 416 offsets[DOT_SEQUENCE_LEN_REFLECTION] = sizeof(int);
417 offsets[DOT_SEQUENCE_REFLECTION] = sizeof(void*); 417 offsets[DOT_SEQUENCE_REFLECTION] = sizeof(void*);
418 offsets[PANEL_TARGET] = sizeof(void*); 418 offsets[PANEL_TARGET] = sizeof(void*);
419 offsets[SPECULAR_TEXTURE] = sizeof(void*); 419 offsets[SPECULAR_TEXTURE] = sizeof(void*);
420 } 420 }
421 421
422 for (auto const& [offset, size] : offsets) { 422 for (auto const& [offset, size] : offsets) {
423 std::vector<byte> panel1data = _memory->ReadEntityData<byte>(panel1, offset, size); 423 std::vector<byte> panel1data = _memory->ReadEntityData<byte>(panel1, offset, size);
424 std::vector<byte> panel2data = _memory->ReadEntityData<byte>(panel2, offset, size); 424 std::vector<byte> panel2data = _memory->ReadEntityData<byte>(panel2, offset, size);
425 _memory->WriteEntityData<byte>(panel2, offset, panel1data); 425 _memory->WriteEntityData<byte>(panel2, offset, panel1data);
426 _memory->WriteEntityData<byte>(panel1, offset, panel2data); 426 _memory->WriteEntityData<byte>(panel1, offset, panel2data);
427 } 427 }
428} 428}
429 429
430void Randomizer::ReassignTargets(const std::vector<int>& panels, const std::vector<int>& order, std::vector<int> targets) { 430void Randomizer::ReassignTargets(const std::vector<int>& panels, const std::vector<int>& order, std::vector<int> targets) {
431 if (targets.empty()) { 431 if (targets.empty()) {
432 // This list is offset by 1, so the target of the Nth panel is in position N (aka the N+1th element) 432 // This list is offset by 1, so the target of the Nth panel is in position N (aka the N+1th element)
433 // The first panel may not have a wire to power it, so we use the panel ID itself. 433 // The first panel may not have a wire to power it, so we use the panel ID itself.
434 targets = {panels[0] + 1}; 434 targets = {panels[0] + 1};
435 for (const int panel : panels) { 435 for (const int panel : panels) {
436 int target = _memory->ReadEntityData<int>(panel, TARGET, 1)[0]; 436 int target = _memory->ReadEntityData<int>(panel, TARGET, 1)[0];
437 targets.push_back(target); 437 targets.push_back(target);
438 } 438 }
439 } 439 }
440 440
441 for (size_t i=0; i<order.size() - 1; i++) { 441 for (size_t i=0; i<order.size() - 1; i++) {
442 // Set the target of order[i] to order[i+1], using the "real" target as determined above. 442 // Set the target of order[i] to order[i+1], using the "real" target as determined above.
443 const int panelTarget = targets[order[i+1]]; 443 const int panelTarget = targets[order[i+1]];
444 _memory->WriteEntityData<int>(panels[order[i]], TARGET, {panelTarget}); 444 _memory->WriteEntityData<int>(panels[order[i]], TARGET, {panelTarget});
445 } 445 }
446} 446}
447 447
448void Randomizer::ReassignNames(const std::vector<int>& panels, const std::vector<int>& order) { 448void Randomizer::ReassignNames(const std::vector<int>& panels, const std::vector<int>& order) {
449 std::vector<int64_t> names; 449 std::vector<int64_t> names;
450 for (const int panel : panels) { 450 for (const int panel : panels) {
451 names.push_back(_memory->ReadEntityData<int64_t>(panel, AUDIO_LOG_NAME, 1)[0]); 451 names.push_back(_memory->ReadEntityData<int64_t>(panel, AUDIO_LOG_NAME, 1)[0]);
452 } 452 }
453 453
454 for (int i=0; i<panels.size(); i++) { 454 for (int i=0; i<panels.size(); i++) {
455 _memory->WriteEntityData<int64_t>(panels[i], AUDIO_LOG_NAME, {names[order[i]]}); 455 _memory->WriteEntityData<int64_t>(panels[i], AUDIO_LOG_NAME, {names[order[i]]});
456 } 456 }
457} 457}