diff options
Diffstat (limited to 'Source/Randomizer.cpp')
-rw-r--r-- | Source/Randomizer.cpp | 270 |
1 files changed, 203 insertions, 67 deletions
diff --git a/Source/Randomizer.cpp b/Source/Randomizer.cpp index 3cc2712..aaddf21 100644 --- a/Source/Randomizer.cpp +++ b/Source/Randomizer.cpp | |||
@@ -3,11 +3,12 @@ | |||
3 | * Shipwreck vault is solved reversed? -> Not reversed, just "half", you can normally solve orange. Seems to need pattern name. | 3 | * Shipwreck vault is solved reversed? -> Not reversed, just "half", you can normally solve orange. Seems to need pattern name. |
4 | * Tutorial sounds don't always play -> Unsure. Not controlled by pattern name. | 4 | * Tutorial sounds don't always play -> Unsure. Not controlled by pattern name. |
5 | * FEATURES: | 5 | * FEATURES: |
6 | * Start the game if it isn't running? | ||
7 | * Stop swapping colors in desert | ||
8 | * Look into valid panel swaps for keep walk-ons. | ||
6 | * Randomize audio logs -- Hard, seem to be unloaded some times? | 9 | * Randomize audio logs -- Hard, seem to be unloaded some times? |
7 | * Swap sounds in jungle (along with panels) -- maybe impossible | 10 | * Swap sounds in jungle (along with panels) -- maybe impossible |
8 | * Make orange 7 (all of oranges?) hard. Like big = hard. (See: HARD_MODE) | 11 | * Make orange 7 (all of oranges?) hard. Like big = hard. (See: HARD_MODE) |
9 | * Start the game if it isn't running? | ||
10 | * Stop swapping colors in desert | ||
11 | */ | 12 | */ |
12 | #include "Memory.h" | 13 | #include "Memory.h" |
13 | #include "Randomizer.h" | 14 | #include "Randomizer.h" |
@@ -27,7 +28,7 @@ int find(const std::vector<T> &data, T search, size_t startIndex = 0) { | |||
27 | } | 28 | } |
28 | 29 | ||
29 | bool Randomizer::GameIsRandomized() { | 30 | bool Randomizer::GameIsRandomized() { |
30 | int currentFrame = _core.GetCurrentFrame(); | 31 | int currentFrame = GetCurrentFrame(); |
31 | if (currentFrame >= _lastRandomizedFrame) { | 32 | if (currentFrame >= _lastRandomizedFrame) { |
32 | // Time went forwards, presumably we're still on the same save | 33 | // Time went forwards, presumably we're still on the same save |
33 | _lastRandomizedFrame = currentFrame; | 34 | _lastRandomizedFrame = currentFrame; |
@@ -40,13 +41,13 @@ bool Randomizer::GameIsRandomized() { | |||
40 | void Randomizer::Randomize() | 41 | void Randomizer::Randomize() |
41 | { | 42 | { |
42 | if (GameIsRandomized()) return; // Nice sanity check, but should be unnecessary (since Main checks anyways) | 43 | if (GameIsRandomized()) return; // Nice sanity check, but should be unnecessary (since Main checks anyways) |
43 | _lastRandomizedFrame = _core.GetCurrentFrame(); | 44 | _lastRandomizedFrame = GetCurrentFrame(); |
44 | 45 | ||
45 | // Content swaps -- must happen before squarePanels | 46 | // Content swaps -- must happen before squarePanels |
46 | _core.Randomize(upDownPanels, SWAP_LINES); | 47 | Randomize(upDownPanels, SWAP_LINES); |
47 | _core.Randomize(leftForwardRightPanels, SWAP_LINES); | 48 | Randomize(leftForwardRightPanels, SWAP_LINES); |
48 | 49 | ||
49 | _core.Randomize(squarePanels, SWAP_LINES); | 50 | Randomize(squarePanels, SWAP_LINES); |
50 | 51 | ||
51 | // Individual area modifications | 52 | // Individual area modifications |
52 | RandomizeTutorial(); | 53 | RandomizeTutorial(); |
@@ -68,33 +69,33 @@ void Randomizer::Randomize() | |||
68 | 69 | ||
69 | void Randomizer::AdjustSpeed() { | 70 | void Randomizer::AdjustSpeed() { |
70 | // Desert Surface Final Control | 71 | // Desert Surface Final Control |
71 | _core._memory->WritePanelData<float>(0x09F95, OPEN_RATE, {0.04f}); // 4x | 72 | _memory->WritePanelData<float>(0x09F95, OPEN_RATE, {0.04f}); // 4x |
72 | // Swamp Sliding Bridge | 73 | // Swamp Sliding Bridge |
73 | _core._memory->WritePanelData<float>(0x0061A, OPEN_RATE, {0.1f}); // 4x | 74 | _memory->WritePanelData<float>(0x0061A, OPEN_RATE, {0.1f}); // 4x |
74 | // Mountain 2 Elevator | 75 | // Mountain 2 Elevator |
75 | _core._memory->WritePanelData<float>(0x09EEC, OPEN_RATE, {0.075f}); // 3x | 76 | _memory->WritePanelData<float>(0x09EEC, OPEN_RATE, {0.075f}); // 3x |
76 | } | 77 | } |
77 | 78 | ||
78 | void Randomizer::RandomizeTutorial() { | 79 | void Randomizer::RandomizeTutorial() { |
79 | // Disable tutorial cursor speed modifications (not working?) | 80 | // Disable tutorial cursor speed modifications (not working?) |
80 | _core._memory->WritePanelData<float>(0x00295, CURSOR_SPEED_SCALE, {1.0}); | 81 | _memory->WritePanelData<float>(0x00295, CURSOR_SPEED_SCALE, {1.0}); |
81 | _core._memory->WritePanelData<float>(0x0C373, CURSOR_SPEED_SCALE, {1.0}); | 82 | _memory->WritePanelData<float>(0x0C373, CURSOR_SPEED_SCALE, {1.0}); |
82 | _core._memory->WritePanelData<float>(0x00293, CURSOR_SPEED_SCALE, {1.0}); | 83 | _memory->WritePanelData<float>(0x00293, CURSOR_SPEED_SCALE, {1.0}); |
83 | _core._memory->WritePanelData<float>(0x002C2, CURSOR_SPEED_SCALE, {1.0}); | 84 | _memory->WritePanelData<float>(0x002C2, CURSOR_SPEED_SCALE, {1.0}); |
84 | } | 85 | } |
85 | 86 | ||
86 | void Randomizer::RandomizeSymmetry() { | 87 | void Randomizer::RandomizeSymmetry() { |
87 | } | 88 | } |
88 | 89 | ||
89 | void Randomizer::RandomizeDesert() { | 90 | void Randomizer::RandomizeDesert() { |
90 | _core.Randomize(desertPanels, SWAP_LINES); | 91 | Randomize(desertPanels, SWAP_LINES); |
91 | 92 | ||
92 | // Turn off desert surface 8 | 93 | // Turn off desert surface 8 |
93 | _core._memory->WritePanelData<float>(0x09F94, POWER, {0.0, 0.0}); | 94 | _memory->WritePanelData<float>(0x09F94, POWER, {0.0, 0.0}); |
94 | // Turn off desert flood final | 95 | // Turn off desert flood final |
95 | _core._memory->WritePanelData<float>(0x18076, POWER, {0.0, 0.0}); | 96 | _memory->WritePanelData<float>(0x18076, POWER, {0.0, 0.0}); |
96 | // Change desert floating target to desert flood final | 97 | // Change desert floating target to desert flood final |
97 | _core._memory->WritePanelData<int>(0x17ECA, TARGET, {0x18077}); | 98 | _memory->WritePanelData<int>(0x17ECA, TARGET, {0x18077}); |
98 | } | 99 | } |
99 | 100 | ||
100 | void Randomizer::RandomizeQuarry() { | 101 | void Randomizer::RandomizeQuarry() { |
@@ -102,14 +103,14 @@ void Randomizer::RandomizeQuarry() { | |||
102 | 103 | ||
103 | void Randomizer::RandomizeTreehouse() { | 104 | void Randomizer::RandomizeTreehouse() { |
104 | // Ensure that whatever pivot panels we have are flagged as "pivotable" | 105 | // Ensure that whatever pivot panels we have are flagged as "pivotable" |
105 | int panelFlags = _core._memory->ReadPanelData<int>(0x17DD1, STYLE_FLAGS, 1)[0]; | 106 | int panelFlags = _memory->ReadPanelData<int>(0x17DD1, STYLE_FLAGS, 1)[0]; |
106 | _core._memory->WritePanelData<int>(0x17DD1, STYLE_FLAGS, {panelFlags | 0x8000}); | 107 | _memory->WritePanelData<int>(0x17DD1, STYLE_FLAGS, {panelFlags | 0x8000}); |
107 | panelFlags = _core._memory->ReadPanelData<int>(0x17CE3, STYLE_FLAGS, 1)[0]; | 108 | panelFlags = _memory->ReadPanelData<int>(0x17CE3, STYLE_FLAGS, 1)[0]; |
108 | _core._memory->WritePanelData<int>(0x17CE3, STYLE_FLAGS, {panelFlags | 0x8000}); | 109 | _memory->WritePanelData<int>(0x17CE3, STYLE_FLAGS, {panelFlags | 0x8000}); |
109 | panelFlags = _core._memory->ReadPanelData<int>(0x17DB7, STYLE_FLAGS, 1)[0]; | 110 | panelFlags = _memory->ReadPanelData<int>(0x17DB7, STYLE_FLAGS, 1)[0]; |
110 | _core._memory->WritePanelData<int>(0x17DB7, STYLE_FLAGS, {panelFlags | 0x8000}); | 111 | _memory->WritePanelData<int>(0x17DB7, STYLE_FLAGS, {panelFlags | 0x8000}); |
111 | panelFlags = _core._memory->ReadPanelData<int>(0x17E52, STYLE_FLAGS, 1)[0]; | 112 | panelFlags = _memory->ReadPanelData<int>(0x17E52, STYLE_FLAGS, 1)[0]; |
112 | _core._memory->WritePanelData<int>(0x17E52, STYLE_FLAGS, {panelFlags | 0x8000}); | 113 | _memory->WritePanelData<int>(0x17E52, STYLE_FLAGS, {panelFlags | 0x8000}); |
113 | } | 114 | } |
114 | 115 | ||
115 | void Randomizer::RandomizeKeep() { | 116 | void Randomizer::RandomizeKeep() { |
@@ -117,22 +118,22 @@ void Randomizer::RandomizeKeep() { | |||
117 | 118 | ||
118 | void Randomizer::RandomizeShadows() { | 119 | void Randomizer::RandomizeShadows() { |
119 | // Distance-gate shadows laser to prevent sniping through the bars | 120 | // Distance-gate shadows laser to prevent sniping through the bars |
120 | _core._memory->WritePanelData<float>(0x19650, MAX_BROADCAST_DISTANCE, {2.5}); | 121 | _memory->WritePanelData<float>(0x19650, MAX_BROADCAST_DISTANCE, {2.5}); |
121 | // Change the shadows tutorial cable to only activate avoid | 122 | // Change the shadows tutorial cable to only activate avoid |
122 | _core._memory->WritePanelData<int>(0x319A8, CABLE_TARGET_2, {0}); | 123 | _memory->WritePanelData<int>(0x319A8, CABLE_TARGET_2, {0}); |
123 | // Change shadows avoid 8 to power shadows follow | 124 | // Change shadows avoid 8 to power shadows follow |
124 | _core._memory->WritePanelData<int>(0x1972F, TARGET, {0x1C34C}); | 125 | _memory->WritePanelData<int>(0x1972F, TARGET, {0x1C34C}); |
125 | 126 | ||
126 | std::vector<int> randomOrder(shadowsPanels.size(), 0); | 127 | std::vector<int> randomOrder(shadowsPanels.size(), 0); |
127 | std::iota(randomOrder.begin(), randomOrder.end(), 0); | 128 | std::iota(randomOrder.begin(), randomOrder.end(), 0); |
128 | _core.RandomizeRange(randomOrder, SWAP_NONE, 0, 8); // Tutorial | 129 | RandomizeRange(randomOrder, SWAP_NONE, 0, 8); // Tutorial |
129 | _core.RandomizeRange(randomOrder, SWAP_NONE, 8, 16); // Avoid | 130 | RandomizeRange(randomOrder, SWAP_NONE, 8, 16); // Avoid |
130 | _core.RandomizeRange(randomOrder, SWAP_NONE, 16, 21); // Follow | 131 | RandomizeRange(randomOrder, SWAP_NONE, 16, 21); // Follow |
131 | _core.ReassignTargets(shadowsPanels, randomOrder); | 132 | ReassignTargets(shadowsPanels, randomOrder); |
132 | // Turn off original starting panel | 133 | // Turn off original starting panel |
133 | _core._memory->WritePanelData<float>(shadowsPanels[0], POWER, {0.0f, 0.0f}); | 134 | _memory->WritePanelData<float>(shadowsPanels[0], POWER, {0.0f, 0.0f}); |
134 | // Turn on new starting panel | 135 | // Turn on new starting panel |
135 | _core._memory->WritePanelData<float>(shadowsPanels[randomOrder[0]], POWER, {1.0f, 1.0f}); | 136 | _memory->WritePanelData<float>(shadowsPanels[randomOrder[0]], POWER, {1.0f, 1.0f}); |
136 | } | 137 | } |
137 | 138 | ||
138 | void Randomizer::RandomizeTown() { | 139 | void Randomizer::RandomizeTown() { |
@@ -141,8 +142,8 @@ void Randomizer::RandomizeTown() { | |||
141 | void Randomizer::RandomizeMonastery() { | 142 | void Randomizer::RandomizeMonastery() { |
142 | std::vector<int> randomOrder(monasteryPanels.size(), 0); | 143 | std::vector<int> randomOrder(monasteryPanels.size(), 0); |
143 | std::iota(randomOrder.begin(), randomOrder.end(), 0); | 144 | std::iota(randomOrder.begin(), randomOrder.end(), 0); |
144 | _core.RandomizeRange(randomOrder, SWAP_NONE, 3, 9); // Outer 2 & 3, Inner 1-4 | 145 | RandomizeRange(randomOrder, SWAP_NONE, 3, 9); // Outer 2 & 3, Inner 1-4 |
145 | _core.ReassignTargets(monasteryPanels, randomOrder); | 146 | ReassignTargets(monasteryPanels, randomOrder); |
146 | } | 147 | } |
147 | 148 | ||
148 | void Randomizer::RandomizeBunker() { | 149 | void Randomizer::RandomizeBunker() { |
@@ -151,73 +152,208 @@ void Randomizer::RandomizeBunker() { | |||
151 | // Randomize Tutorial 2-Advanced Tutorial 4 + Glass 1 | 152 | // Randomize Tutorial 2-Advanced Tutorial 4 + Glass 1 |
152 | // Tutorial 1 cannot be randomized, since no other panel can start on | 153 | // Tutorial 1 cannot be randomized, since no other panel can start on |
153 | // Glass 1 will become door + glass 1, due to the targetting system | 154 | // Glass 1 will become door + glass 1, due to the targetting system |
154 | _core.RandomizeRange(randomOrder, SWAP_NONE, 1, 10); | 155 | RandomizeRange(randomOrder, SWAP_NONE, 1, 10); |
155 | // Randomize Glass 1-3 into everything after the door/glass 1 | 156 | // Randomize Glass 1-3 into everything after the door/glass 1 |
156 | const size_t glass1Index = find(randomOrder, 9); | 157 | const size_t glass1Index = find(randomOrder, 9); |
157 | _core.RandomizeRange(randomOrder, SWAP_NONE, glass1Index + 1, 12); | 158 | RandomizeRange(randomOrder, SWAP_NONE, glass1Index + 1, 12); |
158 | _core.ReassignTargets(bunkerPanels, randomOrder); | 159 | ReassignTargets(bunkerPanels, randomOrder); |
159 | } | 160 | } |
160 | 161 | ||
161 | void Randomizer::RandomizeJungle() { | 162 | void Randomizer::RandomizeJungle() { |
162 | std::vector<int> randomOrder(junglePanels.size(), 0); | 163 | std::vector<int> randomOrder(junglePanels.size(), 0); |
163 | std::iota(randomOrder.begin(), randomOrder.end(), 0); | 164 | std::iota(randomOrder.begin(), randomOrder.end(), 0); |
164 | // Waves 1 cannot be randomized, since no other panel can start on | 165 | // Waves 1 cannot be randomized, since no other panel can start on |
165 | _core.RandomizeRange(randomOrder, SWAP_NONE, 1, 7); // Waves 2-7 | 166 | RandomizeRange(randomOrder, SWAP_NONE, 1, 7); // Waves 2-7 |
166 | _core.RandomizeRange(randomOrder, SWAP_NONE, 8, 13); // Pitches 1-6 | 167 | RandomizeRange(randomOrder, SWAP_NONE, 8, 13); // Pitches 1-6 |
167 | _core.ReassignTargets(junglePanels, randomOrder); | 168 | ReassignTargets(junglePanels, randomOrder); |
168 | } | 169 | } |
169 | 170 | ||
170 | void Randomizer::RandomizeSwamp() { | 171 | void Randomizer::RandomizeSwamp() { |
171 | // Distance-gate swamp snipe 1 to prevent RNG swamp snipe | 172 | // Distance-gate swamp snipe 1 to prevent RNG swamp snipe |
172 | _core._memory->WritePanelData<float>(0x17C05, MAX_BROADCAST_DISTANCE, {15.0}); | 173 | _memory->WritePanelData<float>(0x17C05, MAX_BROADCAST_DISTANCE, {15.0}); |
173 | } | 174 | } |
174 | 175 | ||
175 | void Randomizer::RandomizeMountain() { | 176 | void Randomizer::RandomizeMountain() { |
176 | // Randomize lasers & some of mountain | 177 | // Randomize lasers & some of mountain |
177 | _core.Randomize(lasers, SWAP_TARGETS); | 178 | Randomize(lasers, SWAP_TARGETS); |
178 | _core.Randomize(mountainMultipanel, SWAP_LINES); | 179 | Randomize(mountainMultipanel, SWAP_LINES); |
179 | 180 | ||
180 | // Randomize final pillars order | 181 | // Randomize final pillars order |
181 | std::vector<int> targets = {pillars[0] + 1}; | 182 | std::vector<int> targets = {pillars[0] + 1}; |
182 | for (const int pillar : pillars) { | 183 | for (const int pillar : pillars) { |
183 | int target = _core._memory->ReadPanelData<int>(pillar, TARGET, 1)[0]; | 184 | int target = _memory->ReadPanelData<int>(pillar, TARGET, 1)[0]; |
184 | targets.push_back(target); | 185 | targets.push_back(target); |
185 | } | 186 | } |
186 | targets[5] = pillars[5] + 1; | 187 | targets[5] = pillars[5] + 1; |
187 | 188 | ||
188 | std::vector<int> randomOrder(pillars.size(), 0); | 189 | std::vector<int> randomOrder(pillars.size(), 0); |
189 | std::iota(randomOrder.begin(), randomOrder.end(), 0); | 190 | std::iota(randomOrder.begin(), randomOrder.end(), 0); |
190 | _core.RandomizeRange(randomOrder, SWAP_NONE, 0, 4); // Left Pillars 1-4 | 191 | RandomizeRange(randomOrder, SWAP_NONE, 0, 4); // Left Pillars 1-4 |
191 | _core.RandomizeRange(randomOrder, SWAP_NONE, 5, 9); // Right Pillars 1-4 | 192 | RandomizeRange(randomOrder, SWAP_NONE, 5, 9); // Right Pillars 1-4 |
192 | _core.ReassignTargets(pillars, randomOrder, targets); | 193 | ReassignTargets(pillars, randomOrder, targets); |
193 | // Turn off original starting panels | 194 | // Turn off original starting panels |
194 | _core._memory->WritePanelData<float>(pillars[0], POWER, {0.0f, 0.0f}); | 195 | _memory->WritePanelData<float>(pillars[0], POWER, {0.0f, 0.0f}); |
195 | _core._memory->WritePanelData<float>(pillars[5], POWER, {0.0f, 0.0f}); | 196 | _memory->WritePanelData<float>(pillars[5], POWER, {0.0f, 0.0f}); |
196 | // Turn on new starting panels | 197 | // Turn on new starting panels |
197 | _core._memory->WritePanelData<float>(pillars[randomOrder[0]], POWER, {1.0f, 1.0f}); | 198 | _memory->WritePanelData<float>(pillars[randomOrder[0]], POWER, {1.0f, 1.0f}); |
198 | _core._memory->WritePanelData<float>(pillars[randomOrder[5]], POWER, {1.0f, 1.0f}); | 199 | _memory->WritePanelData<float>(pillars[randomOrder[5]], POWER, {1.0f, 1.0f}); |
199 | 200 | ||
200 | // Read the target of keep front laser, and write it to keep back laser. | 201 | // Read the target of keep front laser, and write it to keep back laser. |
201 | std::vector<int> keepFrontLaserTarget = _core._memory->ReadPanelData<int>(0x0360E, TARGET, 1); | 202 | std::vector<int> keepFrontLaserTarget = _memory->ReadPanelData<int>(0x0360E, TARGET, 1); |
202 | _core._memory->WritePanelData<int>(0x03317, TARGET, keepFrontLaserTarget); | 203 | _memory->WritePanelData<int>(0x03317, TARGET, keepFrontLaserTarget); |
203 | } | 204 | } |
204 | 205 | ||
205 | void Randomizer::RandomizeChallenge() { | 206 | void Randomizer::RandomizeChallenge() { |
206 | std::vector<int> randomOrder(challengePanels.size(), 0); | 207 | std::vector<int> randomOrder(challengePanels.size(), 0); |
207 | std::iota(randomOrder.begin(), randomOrder.end(), 0); | 208 | std::iota(randomOrder.begin(), randomOrder.end(), 0); |
208 | _core.RandomizeRange(randomOrder, SWAP_NONE, 1, 9); // Easy maze - Triple 2 | 209 | RandomizeRange(randomOrder, SWAP_NONE, 1, 9); // Easy maze - Triple 2 |
209 | std::vector<int> triple1Target = _core._memory->ReadPanelData<int>(0x00C80, TARGET, 1); | 210 | std::vector<int> triple1Target = _memory->ReadPanelData<int>(0x00C80, TARGET, 1); |
210 | _core._memory->WritePanelData<int>(0x00CA1, TARGET, triple1Target); | 211 | _memory->WritePanelData<int>(0x00CA1, TARGET, triple1Target); |
211 | _core._memory->WritePanelData<int>(0x00CB9, TARGET, triple1Target); | 212 | _memory->WritePanelData<int>(0x00CB9, TARGET, triple1Target); |
212 | std::vector<int> triple2Target = _core._memory->ReadPanelData<int>(0x00C22, TARGET, 1); | 213 | std::vector<int> triple2Target = _memory->ReadPanelData<int>(0x00C22, TARGET, 1); |
213 | _core._memory->WritePanelData<int>(0x00C59, TARGET, triple2Target); | 214 | _memory->WritePanelData<int>(0x00C59, TARGET, triple2Target); |
214 | _core._memory->WritePanelData<int>(0x00C68, TARGET, triple2Target); | 215 | _memory->WritePanelData<int>(0x00C68, TARGET, triple2Target); |
215 | _core.ReassignTargets(challengePanels, randomOrder); | 216 | ReassignTargets(challengePanels, randomOrder); |
216 | } | 217 | } |
217 | 218 | ||
218 | void Randomizer::RandomizeAudioLogs() { | 219 | void Randomizer::RandomizeAudioLogs() { |
219 | std::vector<int> randomOrder(audiologs.size(), 0); | 220 | std::vector<int> randomOrder(audiologs.size(), 0); |
220 | std::iota(randomOrder.begin(), randomOrder.end(), 0); | 221 | std::iota(randomOrder.begin(), randomOrder.end(), 0); |
221 | _core.Randomize(randomOrder, SWAP_NONE); | 222 | Randomize(randomOrder, SWAP_NONE); |
222 | _core.ReassignNames(audiologs, randomOrder); | 223 | ReassignNames(audiologs, randomOrder); |
223 | } \ No newline at end of file | 224 | } |
225 | |||
226 | void Randomizer::Randomize(std::vector<int>& panels, int flags) { | ||
227 | return RandomizeRange(panels, flags, 0, panels.size()); | ||
228 | } | ||
229 | |||
230 | // Range is [start, end) | ||
231 | void Randomizer::RandomizeRange(std::vector<int> &panels, int flags, size_t startIndex, size_t endIndex) { | ||
232 | if (panels.size() == 0) return; | ||
233 | if (startIndex >= endIndex) return; | ||
234 | if (endIndex >= panels.size()) endIndex = panels.size(); | ||
235 | for (size_t i = endIndex-1; i > startIndex; i--) { | ||
236 | const size_t target = Random::RandInt(startIndex, i); | ||
237 | if (i != target) { | ||
238 | // std::cout << "Swapping panels " << std::hex << panels[i] << " and " << std::hex << panels[target] << std::endl; | ||
239 | SwapPanels(panels[i], panels[target], flags); | ||
240 | std::swap(panels[i], panels[target]); // Panel indices in the array | ||
241 | } | ||
242 | } | ||
243 | } | ||
244 | |||
245 | void Randomizer::SwapPanels(int panel1, int panel2, int flags) { | ||
246 | std::map<int, int> offsets; | ||
247 | |||
248 | if (flags & SWAP_TARGETS) { | ||
249 | offsets[TARGET] = sizeof(int); | ||
250 | } | ||
251 | if (flags & SWAP_AUDIO_NAMES) { | ||
252 | offsets[AUDIO_LOG_NAME] = sizeof(void*); | ||
253 | } | ||
254 | if (flags & SWAP_LINES) { | ||
255 | offsets[PATH_COLOR] = 16; | ||
256 | offsets[REFLECTION_PATH_COLOR] = 16; | ||
257 | offsets[DOT_COLOR] = 16; | ||
258 | offsets[ACTIVE_COLOR] = 16; | ||
259 | offsets[BACKGROUND_REGION_COLOR] = 12; // Not copying alpha to preserve transparency. | ||
260 | offsets[SUCCESS_COLOR_A] = 16; | ||
261 | offsets[SUCCESS_COLOR_B] = 16; | ||
262 | offsets[STROBE_COLOR_A] = 16; | ||
263 | offsets[STROBE_COLOR_B] = 16; | ||
264 | offsets[ERROR_COLOR] = 16; | ||
265 | offsets[PATTERN_POINT_COLOR] = 16; | ||
266 | offsets[PATTERN_POINT_COLOR_A] = 16; | ||
267 | offsets[PATTERN_POINT_COLOR_B] = 16; | ||
268 | offsets[SYMBOL_A] = 16; | ||
269 | offsets[SYMBOL_B] = 16; | ||
270 | offsets[SYMBOL_C] = 16; | ||
271 | offsets[SYMBOL_D] = 16; | ||
272 | offsets[SYMBOL_E] = 16; | ||
273 | offsets[PUSH_SYMBOL_COLORS] = sizeof(int); | ||
274 | offsets[OUTER_BACKGROUND] = 16; | ||
275 | offsets[OUTER_BACKGROUND_MODE] = sizeof(int); | ||
276 | offsets[TRACED_EDGES] = 16; | ||
277 | offsets[AUDIO_PREFIX] = sizeof(void*); | ||
278 | // offsets[IS_CYLINDER] = sizeof(int); | ||
279 | // offsets[CYLINDER_Z0] = sizeof(float); | ||
280 | // offsets[CYLINDER_Z1] = sizeof(float); | ||
281 | // offsets[CYLINDER_RADIUS] = sizeof(float); | ||
282 | offsets[SPECULAR_ADD] = sizeof(float); | ||
283 | offsets[SPECULAR_POWER] = sizeof(int); | ||
284 | offsets[PATH_WIDTH_SCALE] = sizeof(float); | ||
285 | offsets[STARTPOINT_SCALE] = sizeof(float); | ||
286 | offsets[NUM_DOTS] = sizeof(int); | ||
287 | offsets[NUM_CONNECTIONS] = sizeof(int); | ||
288 | offsets[DOT_POSITIONS] = sizeof(void*); | ||
289 | offsets[DOT_FLAGS] = sizeof(void*); | ||
290 | offsets[DOT_CONNECTION_A] = sizeof(void*); | ||
291 | offsets[DOT_CONNECTION_B] = sizeof(void*); | ||
292 | offsets[DECORATIONS] = sizeof(void*); | ||
293 | offsets[DECORATION_FLAGS] = sizeof(void*); | ||
294 | offsets[DECORATION_COLORS] = sizeof(void*); | ||
295 | offsets[NUM_DECORATIONS] = sizeof(int); | ||
296 | offsets[REFLECTION_DATA] = sizeof(void*); | ||
297 | offsets[GRID_SIZE_X] = sizeof(int); | ||
298 | offsets[GRID_SIZE_Y] = sizeof(int); | ||
299 | offsets[STYLE_FLAGS] = sizeof(int); | ||
300 | offsets[SEQUENCE_LEN] = sizeof(int); | ||
301 | offsets[SEQUENCE] = sizeof(void*); | ||
302 | offsets[DOT_SEQUENCE_LEN] = sizeof(int); | ||
303 | offsets[DOT_SEQUENCE] = sizeof(void*); | ||
304 | offsets[DOT_SEQUENCE_LEN_REFLECTION] = sizeof(int); | ||
305 | offsets[DOT_SEQUENCE_REFLECTION] = sizeof(void*); | ||
306 | offsets[NUM_COLORED_REGIONS] = sizeof(int); | ||
307 | offsets[COLORED_REGIONS] = sizeof(void*); | ||
308 | offsets[PANEL_TARGET] = sizeof(void*); | ||
309 | offsets[SPECULAR_TEXTURE] = sizeof(void*); | ||
310 | } | ||
311 | |||
312 | for (auto const& [offset, size] : offsets) { | ||
313 | std::vector<byte> panel1data = _memory->ReadPanelData<byte>(panel1, offset, size); | ||
314 | std::vector<byte> panel2data = _memory->ReadPanelData<byte>(panel2, offset, size); | ||
315 | _memory->WritePanelData<byte>(panel2, offset, panel1data); | ||
316 | _memory->WritePanelData<byte>(panel1, offset, panel2data); | ||
317 | } | ||
318 | } | ||
319 | |||
320 | void Randomizer::ReassignTargets(const std::vector<int>& panels, const std::vector<int>& order, std::vector<int> targets) { | ||
321 | if (targets.empty()) { | ||
322 | // This list is offset by 1, so the target of the Nth panel is in position N (aka the N+1th element) | ||
323 | // The first panel may not have a wire to power it, so we use the panel ID itself. | ||
324 | targets = {panels[0] + 1}; | ||
325 | for (const int panel : panels) { | ||
326 | int target = _memory->ReadPanelData<int>(panel, TARGET, 1)[0]; | ||
327 | targets.push_back(target); | ||
328 | } | ||
329 | } | ||
330 | |||
331 | for (size_t i=0; i<order.size() - 1; i++) { | ||
332 | // Set the target of order[i] to order[i+1], using the "real" target as determined above. | ||
333 | const int panelTarget = targets[order[i+1]]; | ||
334 | _memory->WritePanelData<int>(panels[order[i]], TARGET, {panelTarget}); | ||
335 | } | ||
336 | } | ||
337 | |||
338 | void Randomizer::ReassignNames(const std::vector<int>& panels, const std::vector<int>& order) { | ||
339 | std::vector<int64_t> names; | ||
340 | for (const int panel : panels) { | ||
341 | names.push_back(_memory->ReadPanelData<int64_t>(panel, AUDIO_LOG_NAME, 1)[0]); | ||
342 | } | ||
343 | |||
344 | for (int i=0; i<panels.size(); i++) { | ||
345 | _memory->WritePanelData<int64_t>(panels[i], AUDIO_LOG_NAME, {names[order[i]]}); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | short Randomizer::ReadMetadata() { | ||
350 | return _memory->ReadData<short>({GLOBALS + METADATA}, 1)[0]; | ||
351 | } | ||
352 | |||
353 | void Randomizer::WriteMetadata(short metadata) { | ||
354 | return _memory->WriteData<short>({GLOBALS + METADATA}, {metadata}); | ||
355 | } | ||
356 | |||
357 | int Randomizer::GetCurrentFrame() { | ||
358 | return _memory->ReadData<int>({SCRIPT_FRAMES}, 1)[0]; | ||
359 | } | ||