diff options
| author | jbzdarkid <jbzdarkid@gmail.com> | 2019-11-16 21:17:48 -0800 |
|---|---|---|
| committer | jbzdarkid <jbzdarkid@gmail.com> | 2019-11-16 21:17:48 -0800 |
| commit | 133975b5a2ceca273182829f2f11042a5276c2f0 (patch) | |
| tree | a7e3b13ffd81484b41122acef5189f060cca365c /Source/Randomizer.cpp | |
| parent | fd2fa2211dc09c9030601fde1afd2f7823b22ed8 (diff) | |
| download | witness-tutorializer-133975b5a2ceca273182829f2f11042a5276c2f0.tar.gz witness-tutorializer-133975b5a2ceca273182829f2f11042a5276c2f0.tar.bz2 witness-tutorializer-133975b5a2ceca273182829f2f11042a5276c2f0.zip | |
Tabs -> spaces everywhere
Diffstat (limited to 'Source/Randomizer.cpp')
| -rw-r--r-- | Source/Randomizer.cpp | 534 |
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 | ||
| 103 | template <class T> | 103 | template <class T> |
| 104 | int find(const std::vector<T> &data, T search, size_t startIndex = 0) { | 104 | int 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 | ||
| 112 | Randomizer::Randomizer(const std::shared_ptr<Memory>& memory) : _memory(memory) {} | 112 | Randomizer::Randomizer(const std::shared_ptr<Memory>& memory) : _memory(memory) {} |
| 113 | 113 | ||
| 114 | void Randomizer::Randomize() { | 114 | void 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 | ||
| 157 | void Randomizer::AdjustSpeed() { | 157 | void 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 | ||
| 166 | void Randomizer::RandomizeLasers() { | 166 | void 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 | ||
| 173 | void Randomizer::PreventSnipes() | 173 | void 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 |
| 182 | void Randomizer::RandomizeTutorial() { | 182 | void 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 | ||
| 190 | void Randomizer::RandomizeSymmetry() { | 190 | void 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 | ||
| 197 | void Randomizer::RandomizeDesert() { | 197 | void 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 | ||
| 208 | void Randomizer::RandomizeQuarry() { | 208 | void Randomizer::RandomizeQuarry() { |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | void Randomizer::RandomizeTreehouse() { | 211 | void 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 | ||
| 223 | void Randomizer::RandomizeKeep() { | 223 | void Randomizer::RandomizeKeep() { |
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | void Randomizer::RandomizeShadows() { | 226 | void 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 | ||
| 244 | void Randomizer::RandomizeTown() { | 244 | void 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 | ||
| 257 | void Randomizer::RandomizeMonastery() { | 257 | void 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 | ||
| 264 | void Randomizer::RandomizeBunker() { | 264 | void 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 | ||
| 277 | void Randomizer::RandomizeJungle() { | 277 | void 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 | ||
| 291 | void Randomizer::RandomizeSwamp() { | 291 | void Randomizer::RandomizeSwamp() { |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | void Randomizer::RandomizeMountain() { | 294 | void 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 | ||
| 319 | void Randomizer::RandomizeChallenge() { | 319 | void 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 | ||
| 326 | void Randomizer::RandomizeAudioLogs() { | 326 | void 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 | ||
| 333 | void Randomizer::Randomize(std::vector<int>& panels, int flags) { | 333 | void 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) |
| 338 | void Randomizer::RandomizeRange(std::vector<int> &panels, int flags, size_t startIndex, size_t endIndex) { | 338 | void 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 | ||
| 352 | void Randomizer::SwapPanels(int panel1, int panel2, int flags) { | 352 | void 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 | ||
| 430 | void Randomizer::ReassignTargets(const std::vector<int>& panels, const std::vector<int>& order, std::vector<int> targets) { | 430 | void 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 | ||
| 448 | void Randomizer::ReassignNames(const std::vector<int>& panels, const std::vector<int>& order) { | 448 | void 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 | } |
