summary refs log tree commit diff stats
path: root/Source/Randomizer.cpp
diff options
context:
space:
mode:
authorjbzdarkid <jbzdarkid@gmail.com>2018-11-07 08:27:09 -0800
committerjbzdarkid <jbzdarkid@gmail.com>2018-11-07 08:27:09 -0800
commit1cad9871174728c15abbdb71ee5cbe2cf03ccf0c (patch)
tree78c9cd861667e97c65ae89fe9a5e5b9a648efb06 /Source/Randomizer.cpp
parentcff45c335b23567eb126fefd676fad7c5e88ee02 (diff)
downloadwitness-tutorializer-1cad9871174728c15abbdb71ee5cbe2cf03ccf0c.tar.gz
witness-tutorializer-1cad9871174728c15abbdb71ee5cbe2cf03ccf0c.tar.bz2
witness-tutorializer-1cad9871174728c15abbdb71ee5cbe2cf03ccf0c.zip
Cleanup before I dive further
Diffstat (limited to 'Source/Randomizer.cpp')
-rw-r--r--Source/Randomizer.cpp270
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
29bool Randomizer::GameIsRandomized() { 30bool 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() {
40void Randomizer::Randomize() 41void 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
69void Randomizer::AdjustSpeed() { 70void 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
78void Randomizer::RandomizeTutorial() { 79void 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
86void Randomizer::RandomizeSymmetry() { 87void Randomizer::RandomizeSymmetry() {
87} 88}
88 89
89void Randomizer::RandomizeDesert() { 90void 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
100void Randomizer::RandomizeQuarry() { 101void Randomizer::RandomizeQuarry() {
@@ -102,14 +103,14 @@ void Randomizer::RandomizeQuarry() {
102 103
103void Randomizer::RandomizeTreehouse() { 104void 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
115void Randomizer::RandomizeKeep() { 116void Randomizer::RandomizeKeep() {
@@ -117,22 +118,22 @@ void Randomizer::RandomizeKeep() {
117 118
118void Randomizer::RandomizeShadows() { 119void 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
138void Randomizer::RandomizeTown() { 139void Randomizer::RandomizeTown() {
@@ -141,8 +142,8 @@ void Randomizer::RandomizeTown() {
141void Randomizer::RandomizeMonastery() { 142void 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
148void Randomizer::RandomizeBunker() { 149void 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
161void Randomizer::RandomizeJungle() { 162void 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
170void Randomizer::RandomizeSwamp() { 171void 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
175void Randomizer::RandomizeMountain() { 176void 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
205void Randomizer::RandomizeChallenge() { 206void 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
218void Randomizer::RandomizeAudioLogs() { 219void 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
226void Randomizer::Randomize(std::vector<int>& panels, int flags) {
227 return RandomizeRange(panels, flags, 0, panels.size());
228}
229
230// Range is [start, end)
231void 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
245void 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
320void 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
338void 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
349short Randomizer::ReadMetadata() {
350 return _memory->ReadData<short>({GLOBALS + METADATA}, 1)[0];
351}
352
353void Randomizer::WriteMetadata(short metadata) {
354 return _memory->WriteData<short>({GLOBALS + METADATA}, {metadata});
355}
356
357int Randomizer::GetCurrentFrame() {
358 return _memory->ReadData<int>({SCRIPT_FRAMES}, 1)[0];
359}