summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Source/Panels.h87
-rw-r--r--Source/Randomizer.cpp286
-rw-r--r--Source/Randomizer.h168
-rw-r--r--Source/RandomizerCore.cpp119
-rw-r--r--Source/RandomizerCore.h155
5 files changed, 428 insertions, 387 deletions
diff --git a/Source/Panels.h b/Source/Panels.h index e070005..b3a7791 100644 --- a/Source/Panels.h +++ b/Source/Panels.h
@@ -17,50 +17,6 @@ std::vector<int> lasers = {
17 0x19650, // Shadows 17 0x19650, // Shadows
18}; 18};
19 19
20// Note: Some of these (non-desert) are duplicated elsewhere
21std::vector<int> burnablePanels = {
22 0x17D9C, // Treehouse Yellow 7
23 0x17DC2, // Treehouse Yellow 8
24 0x17DC4, // Treehouse Yellow 9
25 0x00999, // Swamp Discontinuous 1
26 0x0099D, // Swamp Discontinuous 2
27 0x009A0, // Swamp Discontinuous 3
28 0x009A1, // Swamp Discontinuous 4
29 0x00007, // Swamp Rotation Tutorial 1
30 0x00008, // Swamp Rotation Tutorial 2
31 0x00009, // Swamp Rotation Tutorial 3
32 0x0000A, // Swamp Rotation Tutorial 4
33 0x28AC7, // Town Blue 1
34 0x28AC8, // Town Blue 2
35 0x28ACA, // Town Blue 3
36 0x28ACB, // Town Blue 4
37 0x28ACC, // Town Blue 5
38 0x17CF0, // Mill Discard
39
40 0x00698, // Desert Surface 1
41 0x0048F, // Desert Surface 2
42 0x09F92, // Desert Surface 3
43 0x0A036, // Desert Surface 4
44 0x09DA6, // Desert Surface 5
45 0x0A049, // Desert Surface 6
46 0x0A053, // Desert Surface 7
47 0x09F94, // Desert Surface 8
48 0x00422, // Desert Light 1
49 0x006E3, // Desert Light 2
50 0x0A02D, // Desert Light 3
51 0x00C72, // Desert Pond 1
52 0x0129D, // Desert Pond 2
53 0x008BB, // Desert Pond 3
54 0x0078D, // Desert Pond 4
55 0x18313, // Desert Pond 5
56 0x04D18, // Desert Flood 1
57 0x01205, // Desert Flood 2
58 0x181AB, // Desert Flood 3
59 0x0117A, // Desert Flood 4
60 0x17ECA, // Desert Flood 5
61 0x012D7, // Desert Final Far
62};
63
64// Note: Some of these (non-controls) are duplicated elsewhere 20// Note: Some of these (non-controls) are duplicated elsewhere
65// TODO: Gave up 21// TODO: Gave up
66std::vector<int> leftRightPanels = { 22std::vector<int> leftRightPanels = {
@@ -105,10 +61,10 @@ std::vector<int> upDownPanels = {
105 61
106// Note: Some of these (non-controls) are duplicated elsewhere 62// Note: Some of these (non-controls) are duplicated elsewhere
107std::vector<int> leftForwardRightPanels = { 63std::vector<int> leftForwardRightPanels = {
108// 0x00075, // Symmetry Island Colored Dots 3 64 0x00075, // Symmetry Island Colored Dots 3
109// 0x288EA, // UTM Perspective 1 65 0x288EA, // UTM Perspective 1
110// 0x288FC, // UTM Perspective 2 66 0x288FC, // UTM Perspective 2
111// 0x289E7, // UTM Perspective 3 67 0x289E7, // UTM Perspective 3
112 68
113 0x17DD1, // Treehouse Left Orange 9 69 0x17DD1, // Treehouse Left Orange 9
114 0x17CE3, // Treehouse Right Orange 4 70 0x17CE3, // Treehouse Right Orange 4
@@ -458,6 +414,35 @@ std::vector<int> squarePanels = {
458 0x09E85, // Tunnels Town Shortcut 414 0x09E85, // Tunnels Town Shortcut
459}; 415};
460 416
417std::vector<int> desertPanels = {
418 0x00698, // Desert Surface 1
419 0x0048F, // Desert Surface 2
420 0x09F92, // Desert Surface 3
421 0x0A036, // Desert Surface 4
422 0x09DA6, // Desert Surface 5
423 0x0A049, // Desert Surface 6
424 0x0A053, // Desert Surface 7
425 0x09F94, // Desert Surface 8
426 0x00422, // Desert Light 1
427 0x006E3, // Desert Light 2
428 0x0A02D, // Desert Light 3
429 0x00C72, // Desert Pond 1
430 0x0129D, // Desert Pond 2
431 0x008BB, // Desert Pond 3
432 0x0078D, // Desert Pond 4
433 0x18313, // Desert Pond 5
434 0x04D18, // Desert Flood 1
435 0x01205, // Desert Flood 2
436 0x181AB, // Desert Flood 3
437 0x0117A, // Desert Flood 4
438 0x17ECA, // Desert Flood 5
439// 0x18076, // Desert Flood Exit
440// 0x0A15C, // Desert Final Left Convex
441// 0x09FFF, // Desert Final Left Concave
442// 0x0A15F, // Desert Final Near
443 0x012D7, // Desert Final Far
444};
445
461std::vector<int> shadowsPanels = { 446std::vector<int> shadowsPanels = {
462 0x198B5, // Shadows Tutorial 1 447 0x198B5, // Shadows Tutorial 1
463 0x198BD, // Shadows Tutorial 2 448 0x198BD, // Shadows Tutorial 2
@@ -485,8 +470,8 @@ std::vector<int> shadowsPanels = {
485 470
486std::vector<int> monasteryPanels = { 471std::vector<int> monasteryPanels = {
487 0x00B10, // Monastery Left Door 472 0x00B10, // Monastery Left Door
488 0x00290, // Monastery Exterior 1
489 0x00C92, // Monastery Right Door 473 0x00C92, // Monastery Right Door
474 0x00290, // Monastery Exterior 1
490 0x00038, // Monastery Exterior 2 475 0x00038, // Monastery Exterior 2
491 0x00037, // Monastery Exterior 3 476 0x00037, // Monastery Exterior 3
492// 0x09D9B, // Monastery Bonsai 477// 0x09D9B, // Monastery Bonsai
@@ -616,10 +601,6 @@ std::vector<int> nothingPanels = {
616 0x0C335, // Tutorial Pillar 601 0x0C335, // Tutorial Pillar
617 0x0C373, // Tutorial Patio floor 602 0x0C373, // Tutorial Patio floor
618 0x1C349, // Symmetry Island Door 2 - Collision fails here, sadly 603 0x1C349, // Symmetry Island Door 2 - Collision fails here, sadly
619 0x18076, // Desert Flood Exit - I am doing something with this -- but it's a very unique panel.
620 0x0A15C, // Desert Final Left Convex
621 0x09FFF, // Desert Final Left Concave
622 0x0A15F, // Desert Final Near
623 0x033EA, // Keep Yellow Pressure Plates 604 0x033EA, // Keep Yellow Pressure Plates
624 0x0A3A8, // Keep Yellow Reset 605 0x0A3A8, // Keep Yellow Reset
625 0x01BE9, // Keep Purple Pressure Plates 606 0x01BE9, // Keep Purple Pressure Plates
diff --git a/Source/Randomizer.cpp b/Source/Randomizer.cpp index b8462e5..8c4297d 100644 --- a/Source/Randomizer.cpp +++ b/Source/Randomizer.cpp
@@ -2,15 +2,10 @@
2 * TODO: Split out main() logic into another file, and move into separate functions for easier testing. Then write tests. 2 * TODO: Split out main() logic into another file, and move into separate functions for easier testing. Then write tests.
3 * BUGS: 3 * BUGS:
4 * Shipwreck vault fails, possibly because of dot_reflection? Sometimes? 4 * Shipwreck vault fails, possibly because of dot_reflection? Sometimes?
5 * Treehouse pivots *should* work, but I need to not copy style_flags.
6 This seems to cause crashes when pivots appear elsewhere in the world.
7 * Some panels are impossible casually: (idc, I think) 5 * Some panels are impossible casually: (idc, I think)
8 ** Town Stars, Invisible dots 6 ** Town Stars, Invisible dots
9 * Something is wrong with jungle re: softlocks
10 * FEATURES: 7 * FEATURES:
11 * SWAP_TARGETS should still require the full panel sequence (and have ways to prevent softlocks?) 8 * SWAP_TARGETS should still require the full panel sequence (and have ways to prevent softlocks?)
12 ** Think about: Jungle
13 ** Hard: Monastery
14 ** Do: Challenge 9 ** Do: Challenge
15 * Randomize audio logs 10 * Randomize audio logs
16 * Swap sounds in jungle (along with panels) -- maybe impossible 11 * Swap sounds in jungle (along with panels) -- maybe impossible
@@ -28,212 +23,139 @@
28#include <chrono> 23#include <chrono>
29 24
30template <class T> 25template <class T>
31size_t find(const std::vector<T> &data, T search, size_t startIndex = 0) { 26int find(const std::vector<T> &data, T search, size_t startIndex = 0) {
32 for (size_t i=startIndex ; i<data.size(); i++) { 27 for (size_t i=startIndex ; i<data.size(); i++) {
33 if (data[i] == search) return i; 28 if (data[i] == search) return static_cast<int>(i);
34 } 29 }
35 std::cout << "Couldn't find " << search << " in data!" << std::endl; 30 std::cout << "Couldn't find " << search << " in data!" << std::endl;
36 exit(-1); 31 exit(-1);
37} 32}
38 33
39void Randomizer::Randomize(int seed) 34void Randomizer::Randomize()
40{ 35{
41 // Content swaps -- must happen before squarePanels 36 // Content swaps -- must happen before squarePanels
42 Randomize(tallUpDownPanels, SWAP_LINES | SWAP_STYLE); 37 _core.Randomize(tallUpDownPanels, SWAP_LINES|SWAP_LINES);
43 Randomize(upDownPanels, SWAP_LINES | SWAP_STYLE); 38 _core.Randomize(upDownPanels, SWAP_LINES|SWAP_LINES);
44 Randomize(leftForwardRightPanels, SWAP_LINES); 39 _core.Randomize(leftForwardRightPanels, SWAP_LINES|SWAP_LINES);
45 40
46 Randomize(squarePanels, SWAP_LINES | SWAP_STYLE); 41 _core.Randomize(squarePanels, SWAP_LINES|SWAP_LINES);
47 42
48 // Frame swaps -- must happen after squarePanels 43 // Individual area modifications
49 Randomize(burnablePanels, SWAP_LINES | SWAP_STYLE); 44 RandomizeTutorial();
45 RandomizeSymmetry();
46 RandomizeDesert();
47 RandomizeQuarry();
48 RandomizeTreehouse();
49 RandomizeKeep();
50 RandomizeShadows();
51 RandomizeTown();
52 RandomizeMonastery();
53 RandomizeBunker();
54 RandomizeJungle();
55 RandomizeSwamp();
56 RandomizeMountain();
57}
50 58
51 // Target swaps, can happen whenever 59void Randomizer::RandomizeTutorial() {
52 Randomize(lasers, SWAP_TARGETS); 60 // Disable tutorial cursor speed modifications (not working?)
53 // Read the target of keep front laser, and write it to keep back laser. 61 _core.WritePanelData<float>(0x00295, CURSOR_SPEED_SCALE, {1.0});
54 std::vector<int> keepFrontLaserTarget = ReadPanelData<int>(0x0360E, TARGET, 1); 62 _core.WritePanelData<float>(0x0C373, CURSOR_SPEED_SCALE, {1.0});
55 WritePanelData<int>(0x03317, TARGET, keepFrontLaserTarget); 63 _core.WritePanelData<float>(0x00293, CURSOR_SPEED_SCALE, {1.0});
64 _core.WritePanelData<float>(0x002C2, CURSOR_SPEED_SCALE, {1.0});
65}
56 66
57 std::vector<int> randomOrder; 67void Randomizer::RandomizeSymmetry() {
68}
58 69
59 /* Jungle 70void Randomizer::RandomizeDesert() {
60 randomOrder = std::vector(junglePanels.size(), 0); 71 _core.Randomize(desertPanels, SWAP_LINES|SWAP_LINES);
61 std::iota(randomOrder.begin(), randomOrder.end(), 0);
62 // Randomize Waves 2-7
63 // Waves 1 cannot be randomized, since no other panel can start on
64 randomizer.RandomizeRange(randomOrder, SWAP_NONE, 1, 7);
65 // Randomize Pitches 1-6 onto themselves
66 randomizer.RandomizeRange(randomOrder, SWAP_NONE, 7, 13);
67 randomizer.ReassignTargets(junglePanels, randomOrder);
68 */
69 72
70 /* Bunker */ 73 // Turn off desert surface 8
71 randomOrder = std::vector(bunkerPanels.size(), 0); 74 _core.WritePanelData<float>(0x09F94, POWER, {0.0, 0.0});
72 std::iota(randomOrder.begin(), randomOrder.end(), 0); 75 // Turn off desert flood final
73 // Randomize Tutorial 2-Advanced Tutorial 4 + Glass 1 76 _core.WritePanelData<float>(0x18076, POWER, {0.0, 0.0});
74 // Tutorial 1 cannot be randomized, since no other panel can start on 77 // Change desert floating target to desert flood final
75 // Glass 1 will become door + glass 1, due to the targetting system 78 _core.WritePanelData<int>(0x17ECA, TARGET, {0x18077});
76 RandomizeRange(randomOrder, SWAP_NONE, 1, 10); 79}
77 // Randomize Glass 1-3 into everything after the door
78 const size_t glassDoorIndex = find(randomOrder, 9) + 1;
79 RandomizeRange(randomOrder, SWAP_NONE, glassDoorIndex, 12);
80 ReassignTargets(bunkerPanels, randomOrder);
81
82 /* Shadows */
83 randomOrder = std::vector(shadowsPanels.size(), 0);
84 std::iota(randomOrder.begin(), randomOrder.end(), 0);
85 RandomizeRange(randomOrder, SWAP_NONE, 0, 8); // Tutorial
86 RandomizeRange(randomOrder, SWAP_NONE, 8, 16); // Avoid
87 RandomizeRange(randomOrder, SWAP_NONE, 16, 21); // Follow
88 ReassignTargets(shadowsPanels, randomOrder);
89 // Turn off original starting panel
90 WritePanelData<float>(shadowsPanels[0], POWER, {0.0f, 0.0f});
91 // Turn on new starting panel
92 WritePanelData<float>(shadowsPanels[randomOrder[0]], POWER, {1.0f, 1.0f});
93 80
94 /* Monastery 81void Randomizer::RandomizeQuarry() {
95 randomOrder = std::vector(monasteryPanels.size(), 0); 82}
96 std::iota(randomOrder.begin(), randomOrder.end(), 0);
97 randomizer.RandomizeRange(randomOrder, SWAP_NONE, 2, 6); // outer 2 & 3, inner 1
98 // Once outer 3 and right door are solved, inner 2-4 are accessible
99 int innerPanelsIndex = max(find(randomOrder, 2), find(randomOrder, 4));
100 randomizer.RandomizeRange(randomOrder, SWAP_NONE, innerPanelsIndex, 9); // Inner 2-4
101 83
102 randomizer.ReassignTargets(monasteryPanels, randomOrder); 84void Randomizer::RandomizeTreehouse() {
103 */ 85 // Ensure that whatever pivot panels we have are flagged as "pivotable"
86 _core.WritePanelData<int>(0x17DD1, STYLE_FLAGS, {0x8000});
87 _core.WritePanelData<int>(0x17CE3, STYLE_FLAGS, {0x8000});
88 _core.WritePanelData<int>(0x17DB7, STYLE_FLAGS, {0x8000});
89 _core.WritePanelData<int>(0x17E52, STYLE_FLAGS, {0x8000});
104} 90}
105 91
106Randomizer::Randomizer() 92void Randomizer::RandomizeKeep() {
107{ 93}
108 // Turn off desert surface 8
109 WritePanelData<float>(0x09F94, POWER, {0.0, 0.0});
110 // Turn off desert flood final
111 WritePanelData<float>(0x18076, POWER, {0.0, 0.0});
112 // Change desert floating target to desert flood final
113 WritePanelData<int>(0x17ECA, TARGET, {0x18077});
114 94
95void Randomizer::RandomizeShadows() {
115 // Distance-gate shadows laser to prevent sniping through the bars 96 // Distance-gate shadows laser to prevent sniping through the bars
116 WritePanelData<float>(0x19650, MAX_BROADCAST_DISTANCE, {2.5}); 97 _core.WritePanelData<float>(0x19650, MAX_BROADCAST_DISTANCE, {2.5});
117 // Change the shadows tutorial cable to only activate avoid 98 // Change the shadows tutorial cable to only activate avoid
118 WritePanelData<int>(0x319A8, CABLE_TARGET_2, {0}); 99 _core.WritePanelData<int>(0x319A8, CABLE_TARGET_2, {0});
119 // Change shadows avoid 8 to power shadows follow 100 // Change shadows avoid 8 to power shadows follow
120 WritePanelData<int>(0x1972F, TARGET, {0x1C34C}); 101 _core.WritePanelData<int>(0x1972F, TARGET, {0x1C34C});
121
122 // Distance-gate swamp snipe 1 to prevent RNG swamp snipe
123 WritePanelData<float>(0x17C05, MAX_BROADCAST_DISTANCE, {5.0});
124 102
125 // Disable tutorial cursor speed modifications (not working?) 103 std::vector<int> randomOrder(shadowsPanels.size(), 0);
126 WritePanelData<float>(0x00295, CURSOR_SPEED_SCALE, {1.0}); 104 std::iota(randomOrder.begin(), randomOrder.end(), 0);
127 WritePanelData<float>(0x0C373, CURSOR_SPEED_SCALE, {1.0}); 105 _core.RandomizeRange(randomOrder, SWAP_NONE, 0, 8); // Tutorial
128 WritePanelData<float>(0x00293, CURSOR_SPEED_SCALE, {1.0}); 106 _core.RandomizeRange(randomOrder, SWAP_NONE, 8, 16); // Avoid
129 WritePanelData<float>(0x002C2, CURSOR_SPEED_SCALE, {1.0}); 107 _core.RandomizeRange(randomOrder, SWAP_NONE, 16, 21); // Follow
108 _core.ReassignTargets(shadowsPanels, randomOrder);
109 // Turn off original starting panel
110 _core.WritePanelData<float>(shadowsPanels[0], POWER, {0.0f, 0.0f});
111 // Turn on new starting panel
112 _core.WritePanelData<float>(shadowsPanels[randomOrder[0]], POWER, {1.0f, 1.0f});
130} 113}
131 114
132void Randomizer::Randomize(std::vector<int>& panels, int flags) { 115void Randomizer::RandomizeTown() {
133 return RandomizeRange(panels, flags, 0, panels.size());
134} 116}
135 117
136// Range is [start, end) 118void Randomizer::RandomizeMonastery() {
137void Randomizer::RandomizeRange(std::vector<int> &panels, int flags, size_t startIndex, size_t endIndex) { 119 std::vector<int> randomOrder(monasteryPanels.size(), 0);
138 if (panels.size() == 0) return; 120 std::iota(randomOrder.begin(), randomOrder.end(), 0);
139 if (startIndex >= endIndex) return; 121 _core.RandomizeRange(randomOrder, SWAP_NONE, 3, 9); // Outer 2 & 3, Inner 1-4
140 if (endIndex >= panels.size()) endIndex = panels.size(); 122 _core.ReassignTargets(monasteryPanels, randomOrder);
141 for (size_t i = endIndex-1; i > startIndex+1; i--) {
142 const size_t target = rand() % (i - startIndex) + startIndex;
143 if (i != target) {
144 // std::cout << "Swapping panels " << std::hex << panels[i] << " and " << std::hex << panels[target] << std::endl;
145 SwapPanels(panels[i], panels[target], flags);
146 std::swap(panels[i], panels[target]); // Panel indices in the array
147 }
148 }
149} 123}
150 124
151void Randomizer::SwapPanels(int panel1, int panel2, int flags) { 125void Randomizer::RandomizeBunker() {
152 std::map<int, int> offsets; 126 std::vector<int> randomOrder(bunkerPanels.size(), 0);
127 std::iota(randomOrder.begin(), randomOrder.end(), 0);
128 // Randomize Tutorial 2-Advanced Tutorial 4 + Glass 1
129 // Tutorial 1 cannot be randomized, since no other panel can start on
130 // Glass 1 will become door + glass 1, due to the targetting system
131 _core.RandomizeRange(randomOrder, SWAP_NONE, 1, 10);
132 // Randomize Glass 1-3 into everything after the door/glass 1
133 const size_t glass1Index = find(randomOrder, 9);
134 _core.RandomizeRange(randomOrder, SWAP_NONE, glass1Index + 1, 12);
135 _core.ReassignTargets(bunkerPanels, randomOrder);
136}
153 137
154 if (flags & SWAP_TARGETS) { 138void Randomizer::RandomizeJungle() {
155 offsets[TARGET] = sizeof(int); 139 std::vector<int> randomOrder(junglePanels.size(), 0);
156 } 140 std::iota(randomOrder.begin(), randomOrder.end(), 0);
157 if (flags & SWAP_STYLE) { 141 // Randomize Waves 2-7
158 offsets[STYLE_FLAGS] = sizeof(int); 142 // Waves 1 cannot be randomized, since no other panel can start on
159 } 143 _core.RandomizeRange(randomOrder, SWAP_NONE, 1, 7);
160 if (flags & SWAP_LINES) { 144 // Randomize Pitches 1-6 onto themselves
161 offsets[PATH_COLOR] = 16; 145 _core.RandomizeRange(randomOrder, SWAP_NONE, 8, 13);
162 offsets[REFLECTION_PATH_COLOR] = 16; 146 _core.ReassignTargets(junglePanels, randomOrder);
163 offsets[DOT_COLOR] = 16; 147}
164 offsets[ACTIVE_COLOR] = 16;
165 offsets[BACKGROUND_REGION_COLOR] = 16;
166 offsets[SUCCESS_COLOR_A] = 16;
167 offsets[SUCCESS_COLOR_B] = 16;
168 offsets[STROBE_COLOR_A] = 16;
169 offsets[STROBE_COLOR_B] = 16;
170 offsets[ERROR_COLOR] = 16;
171 offsets[PATTERN_POINT_COLOR] = 16;
172 offsets[PATTERN_POINT_COLOR_A] = 16;
173 offsets[PATTERN_POINT_COLOR_B] = 16;
174 offsets[SYMBOL_A] = 16;
175 offsets[SYMBOL_B] = 16;
176 offsets[SYMBOL_C] = 16;
177 offsets[SYMBOL_D] = 16;
178 offsets[SYMBOL_E] = 16;
179 offsets[PUSH_SYMBOL_COLORS] = sizeof(int);
180 offsets[OUTER_BACKGROUND] = 16;
181 offsets[OUTER_BACKGROUND_MODE] = sizeof(int);
182 offsets[TRACED_EDGES] = 16;
183 offsets[AUDIO_PREFIX] = sizeof(void*);
184// offsets[IS_CYLINDER] = sizeof(int);
185// offsets[CYLINDER_Z0] = sizeof(float);
186// offsets[CYLINDER_Z1] = sizeof(float);
187// offsets[CYLINDER_RADIUS] = sizeof(float);
188 offsets[SPECULAR_ADD] = sizeof(float);
189 offsets[SPECULAR_POWER] = sizeof(int);
190 offsets[PATH_WIDTH_SCALE] = sizeof(float);
191 offsets[STARTPOINT_SCALE] = sizeof(float);
192 offsets[NUM_DOTS] = sizeof(int);
193 offsets[NUM_CONNECTIONS] = sizeof(int);
194 offsets[DOT_POSITIONS] = sizeof(void*);
195 offsets[DOT_FLAGS] = sizeof(void*);
196 offsets[DOT_CONNECTION_A] = sizeof(void*);
197 offsets[DOT_CONNECTION_B] = sizeof(void*);
198 offsets[DECORATIONS] = sizeof(void*);
199 offsets[DECORATION_FLAGS] = sizeof(void*);
200 offsets[DECORATION_COLORS] = sizeof(void*);
201 offsets[NUM_DECORATIONS] = sizeof(int);
202 offsets[REFLECTION_DATA] = sizeof(void*);
203 offsets[GRID_SIZE_X] = sizeof(int);
204 offsets[GRID_SIZE_Y] = sizeof(int);
205 offsets[SEQUENCE_LEN] = sizeof(int);
206 offsets[SEQUENCE] = sizeof(void*);
207 offsets[DOT_SEQUENCE_LEN] = sizeof(int);
208 offsets[DOT_SEQUENCE] = sizeof(void*);
209 offsets[DOT_SEQUENCE_LEN_REFLECTION] = sizeof(int);
210 offsets[DOT_SEQUENCE_REFLECTION] = sizeof(void*);
211 offsets[NUM_COLORED_REGIONS] = sizeof(int);
212 offsets[COLORED_REGIONS] = sizeof(void*);
213 offsets[PANEL_TARGET] = sizeof(void*);
214 offsets[SPECULAR_TEXTURE] = sizeof(void*);
215 }
216 148
217 for (auto const& [offset, size] : offsets) { 149void Randomizer::RandomizeSwamp() {
218 std::vector<byte> panel1data = ReadPanelData<byte>(panel1, offset, size); 150 // Distance-gate swamp snipe 1 to prevent RNG swamp snipe
219 std::vector<byte> panel2data = ReadPanelData<byte>(panel2, offset, size); 151 _core.WritePanelData<float>(0x17C05, MAX_BROADCAST_DISTANCE, {15.0});
220 WritePanelData<byte>(panel2, offset, panel1data);
221 WritePanelData<byte>(panel1, offset, panel2data);
222 }
223} 152}
224 153
225void Randomizer::ReassignTargets(const std::vector<int>& panels, const std::vector<int>& order) { 154void Randomizer::RandomizeMountain() {
226 // This list is offset by 1, so the target of the Nth panel is in position N (aka the N+1th element) 155 _core.Randomize(lasers, SWAP_TARGETS);
227 // The first panel may not have a wire to power it, so we use the panel ID itself. 156 _core.Randomize(pillars, SWAP_LINES|SWAP_LINES);
228 std::vector<int> targetToActivatePanel = {panels[0] + 1};
229 for (const int panel : panels) {
230 int target = ReadPanelData<int>(panel, TARGET, 1)[0];
231 targetToActivatePanel.push_back(target);
232 }
233 157
234 for (size_t i=0; i<order.size() - 1; i++) { 158 // Read the target of keep front laser, and write it to keep back laser.
235 // Set the target of order[i] to order[i+1], using the "real" target as determined above. 159 std::vector<int> keepFrontLaserTarget = _core.ReadPanelData<int>(0x0360E, TARGET, 1);
236 const int panelTarget = targetToActivatePanel[order[i+1]]; 160 _core.WritePanelData<int>(0x03317, TARGET, keepFrontLaserTarget);
237 WritePanelData<int>(panels[order[i]], TARGET, {panelTarget}); 161} \ No newline at end of file
238 }
239}
diff --git a/Source/Randomizer.h b/Source/Randomizer.h index 6615e31..861f5a2 100644 --- a/Source/Randomizer.h +++ b/Source/Randomizer.h
@@ -1,159 +1,23 @@
1#pragma once 1#pragma once
2#include "Memory.h" 2#include "RandomizerCore.h"
3
4// #define GLOBALS 0x5B28C0
5#define GLOBALS 0x62A080
6
7__declspec(selectany) int SWAP_NONE = 0x0;
8__declspec(selectany) int SWAP_TARGETS = 0x1;
9__declspec(selectany) int SWAP_LINES = 0x2;
10__declspec(selectany) int SWAP_STYLE = 0x4;
11 3
12class Randomizer { 4class Randomizer {
13public: 5public:
14 Randomizer(); 6 void Randomize();
15
16 void Randomize(int seed);
17
18 void Randomize(std::vector<int>& panels, int flags);
19 void RandomizeRange(std::vector<int> &panels, int flags, size_t startIndex, size_t endIndex);
20 void SwapPanels(int panel1, int panel2, int flags);
21 void ReassignTargets(const std::vector<int>& panels, const std::vector<int>& order);
22
23 template <class T>
24 std::vector<T> ReadPanelData(int panel, int offset, size_t size) {
25 return _memory.ReadData<T>({GLOBALS, 0x18, panel*8, offset}, size);
26 }
27
28 template <class T>
29 void WritePanelData(int panel, int offset, const std::vector<T>& data) {
30 _memory.WriteData<T>({GLOBALS, 0x18, panel*8, offset}, data);
31 }
32 7
33private: 8private:
34 Memory _memory = Memory("witness64_d3d11.exe"); 9 RandomizerCore _core;
10 void RandomizeTutorial();
11 void RandomizeSymmetry();
12 void RandomizeDesert();
13 void RandomizeQuarry();
14 void RandomizeTreehouse();
15 void RandomizeKeep();
16 void RandomizeShadows();
17 void RandomizeTown();
18 void RandomizeMonastery();
19 void RandomizeBunker();
20 void RandomizeJungle();
21 void RandomizeSwamp();
22 void RandomizeMountain();
35}; 23};
36
37#if GLOBALS == 0x5B28C0
38#define PATH_COLOR 0xC8
39#define REFLECTION_PATH_COLOR 0xD8
40#define DOT_COLOR 0xF8
41#define ACTIVE_COLOR 0x108
42#define BACKGROUND_REGION_COLOR 0x118
43#define SUCCESS_COLOR_A 0x128
44#define SUCCESS_COLOR_B 0x138
45#define STROBE_COLOR_A 0x148
46#define STROBE_COLOR_B 0x158
47#define ERROR_COLOR 0x168
48#define PATTERN_POINT_COLOR 0x188
49#define PATTERN_POINT_COLOR_A 0x198
50#define PATTERN_POINT_COLOR_B 0x1A8
51#define SYMBOL_A 0x1B8
52#define SYMBOL_B 0x1C8
53#define SYMBOL_C 0x1D8
54#define SYMBOL_D 0x1E8
55#define SYMBOL_E 0x1F8
56#define PUSH_SYMBOL_COLORS 0x208
57#define OUTER_BACKGROUND 0x20C
58#define OUTER_BACKGROUND_MODE 0x21C
59#define TRACED_EDGES 0x230
60#define AUDIO_PREFIX 0x278
61#define POWER 0x2A8
62#define TARGET 0x2BC
63#define IS_CYLINDER 0x2FC
64#define CYLINDER_Z0 0x300
65#define CYLINDER_Z1 0x304
66#define CYLINDER_RADIUS 0x308
67#define CURSOR_SPEED_SCALE 0x358
68#define SPECULAR_ADD 0x398
69#define SPECULAR_POWER 0x39C
70#define PATH_WIDTH_SCALE 0x3A4
71#define STARTPOINT_SCALE 0x3A8
72#define NUM_DOTS 0x3B8
73#define NUM_CONNECTIONS 0x3BC
74#define MAX_BROADCAST_DISTANCE 0x3C0
75#define DOT_POSITIONS 0x3C8
76#define DOT_FLAGS 0x3D0
77#define DOT_CONNECTION_A 0x3D8
78#define DOT_CONNECTION_B 0x3E0
79#define DECORATIONS 0x420
80#define DECORATION_FLAGS 0x428
81#define DECORATION_COLORS 0x430
82#define NUM_DECORATIONS 0x438
83#define REFLECTION_DATA 0x440
84#define GRID_SIZE_X 0x448
85#define GRID_SIZE_Y 0x44C
86#define STYLE_FLAGS 0x450
87#define SEQUENCE_LEN 0x45C
88#define SEQUENCE 0x460
89#define DOT_SEQUENCE_LEN 0x468
90#define DOT_SEQUENCE 0x470
91#define DOT_SEQUENCE_LEN_REFLECTION 0x478
92#define DOT_SEQUENCE_REFLECTION 0x480
93#define NUM_COLORED_REGIONS 0x4A0
94#define COLORED_REGIONS 0x4A8
95#define PANEL_TARGET 0x4B0
96#define SPECULAR_TEXTURE 0x4D8
97#define CABLE_TARGET_2 0xD8
98#elif GLOBALS == 0x62A080
99#define PATH_COLOR 0xC0
100#define REFLECTION_PATH_COLOR 0xD0
101#define DOT_COLOR 0xF0
102#define ACTIVE_COLOR 0x100
103#define BACKGROUND_REGION_COLOR 0x110
104#define SUCCESS_COLOR_A 0x120
105#define SUCCESS_COLOR_B 0x130
106#define STROBE_COLOR_A 0x140
107#define STROBE_COLOR_B 0x150
108#define ERROR_COLOR 0x160
109#define PATTERN_POINT_COLOR 0x180
110#define PATTERN_POINT_COLOR_A 0x190
111#define PATTERN_POINT_COLOR_B 0x1A0
112#define SYMBOL_A 0x1B0
113#define SYMBOL_B 0x1C0
114#define SYMBOL_C 0x1D0
115#define SYMBOL_D 0x1E0
116#define SYMBOL_E 0x1F0
117#define PUSH_SYMBOL_COLORS 0x200
118#define OUTER_BACKGROUND 0x204
119#define OUTER_BACKGROUND_MODE 0x214
120#define TRACED_EDGES 0x228
121#define AUDIO_PREFIX 0x270
122#define POWER 0x2A0
123#define TARGET 0x2B4
124#define IS_CYLINDER 0x2F4
125#define CYLINDER_Z0 0x2F8
126#define CYLINDER_Z1 0x2FC
127#define CYLINDER_RADIUS 0x300
128#define CURSOR_SPEED_SCALE 0x350
129#define SPECULAR_ADD 0x38C
130#define SPECULAR_POWER 0x390
131#define PATH_WIDTH_SCALE 0x39C
132#define STARTPOINT_SCALE 0x3A0
133#define NUM_DOTS 0x3B4
134#define NUM_CONNECTIONS 0x3B8
135#define MAX_BROADCAST_DISTANCE 0x3BC
136#define DOT_POSITIONS 0x3C0
137#define DOT_FLAGS 0x3C8
138#define DOT_CONNECTION_A 0x3D0
139#define DOT_CONNECTION_B 0x3D8
140#define DECORATIONS 0x418
141#define DECORATION_FLAGS 0x420
142#define DECORATION_COLORS 0x428
143#define NUM_DECORATIONS 0x430
144#define REFLECTION_DATA 0x438
145#define GRID_SIZE_X 0x440
146#define GRID_SIZE_Y 0x444
147#define STYLE_FLAGS 0x448
148#define SEQUENCE_LEN 0x454
149#define SEQUENCE 0x458
150#define DOT_SEQUENCE_LEN 0x460
151#define DOT_SEQUENCE 0x468
152#define DOT_SEQUENCE_LEN_REFLECTION 0x470
153#define DOT_SEQUENCE_REFLECTION 0x478
154#define NUM_COLORED_REGIONS 0x498
155#define COLORED_REGIONS 0x4A0
156#define PANEL_TARGET 0x4A8
157#define SPECULAR_TEXTURE 0x4D0
158#define CABLE_TARGET_2 0xD0
159#endif \ No newline at end of file
diff --git a/Source/RandomizerCore.cpp b/Source/RandomizerCore.cpp new file mode 100644 index 0000000..ef0e6e6 --- /dev/null +++ b/Source/RandomizerCore.cpp
@@ -0,0 +1,119 @@
1#include "RandomizerCore.h"
2#include "Memory.h"
3#include <sstream>
4
5void RandomizerCore::Randomize(std::vector<int>& panels, int flags) {
6 return RandomizeRange(panels, flags, 0, panels.size());
7}
8
9// Range is [start, end)
10void RandomizerCore::RandomizeRange(std::vector<int> &panels, int flags, size_t startIndex, size_t endIndex) {
11 if (panels.size() == 0) return;
12 if (startIndex >= endIndex) return;
13 if (endIndex >= panels.size()) endIndex = panels.size();
14 for (size_t i = endIndex-1; i > startIndex; i--) {
15 const size_t target = rand() % (i - startIndex) + startIndex;
16 if (i != target) {
17 // std::cout << "Swapping panels " << std::hex << panels[i] << " and " << std::hex << panels[target] << std::endl;
18 SwapPanels(panels[i], panels[target], flags);
19 std::swap(panels[i], panels[target]); // Panel indices in the array
20 }
21 }
22}
23
24void RandomizerCore::SwapPanels(int panel1, int panel2, int flags) {
25 std::map<int, int> offsets;
26
27 if (flags & SWAP_TARGETS) {
28 offsets[TARGET] = sizeof(int);
29 }
30 if (flags & SWAP_LINES) {
31 offsets[PATH_COLOR] = 16;
32 offsets[REFLECTION_PATH_COLOR] = 16;
33 offsets[DOT_COLOR] = 16;
34 offsets[ACTIVE_COLOR] = 16;
35 offsets[BACKGROUND_REGION_COLOR] = 16;
36 offsets[SUCCESS_COLOR_A] = 16;
37 offsets[SUCCESS_COLOR_B] = 16;
38 offsets[STROBE_COLOR_A] = 16;
39 offsets[STROBE_COLOR_B] = 16;
40 offsets[ERROR_COLOR] = 16;
41 offsets[PATTERN_POINT_COLOR] = 16;
42 offsets[PATTERN_POINT_COLOR_A] = 16;
43 offsets[PATTERN_POINT_COLOR_B] = 16;
44 offsets[SYMBOL_A] = 16;
45 offsets[SYMBOL_B] = 16;
46 offsets[SYMBOL_C] = 16;
47 offsets[SYMBOL_D] = 16;
48 offsets[SYMBOL_E] = 16;
49 offsets[PUSH_SYMBOL_COLORS] = sizeof(int);
50 offsets[OUTER_BACKGROUND] = 16;
51 offsets[OUTER_BACKGROUND_MODE] = sizeof(int);
52 offsets[TRACED_EDGES] = 16;
53 offsets[AUDIO_PREFIX] = sizeof(void*);
54// offsets[IS_CYLINDER] = sizeof(int);
55// offsets[CYLINDER_Z0] = sizeof(float);
56// offsets[CYLINDER_Z1] = sizeof(float);
57// offsets[CYLINDER_RADIUS] = sizeof(float);
58 offsets[SPECULAR_ADD] = sizeof(float);
59 offsets[SPECULAR_POWER] = sizeof(int);
60 offsets[PATH_WIDTH_SCALE] = sizeof(float);
61 offsets[STARTPOINT_SCALE] = sizeof(float);
62 offsets[NUM_DOTS] = sizeof(int);
63 offsets[NUM_CONNECTIONS] = sizeof(int);
64 offsets[DOT_POSITIONS] = sizeof(void*);
65 offsets[DOT_FLAGS] = sizeof(void*);
66 offsets[DOT_CONNECTION_A] = sizeof(void*);
67 offsets[DOT_CONNECTION_B] = sizeof(void*);
68 offsets[DECORATIONS] = sizeof(void*);
69 offsets[DECORATION_FLAGS] = sizeof(void*);
70 offsets[DECORATION_COLORS] = sizeof(void*);
71 offsets[NUM_DECORATIONS] = sizeof(int);
72 offsets[REFLECTION_DATA] = sizeof(void*);
73 offsets[GRID_SIZE_X] = sizeof(int);
74 offsets[GRID_SIZE_Y] = sizeof(int);
75 offsets[STYLE_FLAGS] = sizeof(int);
76 offsets[SEQUENCE_LEN] = sizeof(int);
77 offsets[SEQUENCE] = sizeof(void*);
78 offsets[DOT_SEQUENCE_LEN] = sizeof(int);
79 offsets[DOT_SEQUENCE] = sizeof(void*);
80 offsets[DOT_SEQUENCE_LEN_REFLECTION] = sizeof(int);
81 offsets[DOT_SEQUENCE_REFLECTION] = sizeof(void*);
82 offsets[NUM_COLORED_REGIONS] = sizeof(int);
83 offsets[COLORED_REGIONS] = sizeof(void*);
84 offsets[PANEL_TARGET] = sizeof(void*);
85 offsets[SPECULAR_TEXTURE] = sizeof(void*);
86 }
87
88 for (auto const& [offset, size] : offsets) {
89 std::vector<byte> panel1data = ReadPanelData<byte>(panel1, offset, size);
90 std::vector<byte> panel2data = ReadPanelData<byte>(panel2, offset, size);
91 WritePanelData<byte>(panel2, offset, panel1data);
92 WritePanelData<byte>(panel1, offset, panel2data);
93 }
94}
95
96void RandomizerCore::ReassignTargets(const std::vector<int>& panels, const std::vector<int>& order) {
97 // This list is offset by 1, so the target of the Nth panel is in position N (aka the N+1th element)
98 // The first panel may not have a wire to power it, so we use the panel ID itself.
99 std::vector<int> targetToActivatePanel = {panels[0] + 1};
100 for (const int panel : panels) {
101 int target = ReadPanelData<int>(panel, TARGET, 1)[0];
102 targetToActivatePanel.push_back(target);
103 }
104
105 for (size_t i=0; i<order.size() - 1; i++) {
106 // Set the target of order[i] to order[i+1], using the "real" target as determined above.
107 const int panelTarget = targetToActivatePanel[order[i+1]];
108
109 std::stringstream message;
110 message << "i=" << i;
111 message << " order[i]=" << order[i];
112 message << " order[i+1]=" << order[i+1];
113 message << " panels[order[i]]=0x" << std::hex << panels[order[i]];
114 message << " panels[order[i+1]]=0x" << std::hex << panels[order[i+1]];
115 message << " panelTarget=0x" << std::hex << panelTarget << std::endl;
116 OutputDebugStringA(message.str().c_str());
117 WritePanelData<int>(panels[order[i]], TARGET, {panelTarget});
118 }
119}
diff --git a/Source/RandomizerCore.h b/Source/RandomizerCore.h new file mode 100644 index 0000000..4002611 --- /dev/null +++ b/Source/RandomizerCore.h
@@ -0,0 +1,155 @@
1#pragma once
2#include "Memory.h"
3
4// #define GLOBALS 0x5B28C0
5#define GLOBALS 0x62A080
6
7__declspec(selectany) int SWAP_NONE = 0x0;
8__declspec(selectany) int SWAP_TARGETS = 0x1;
9__declspec(selectany) int SWAP_LINES = 0x2;
10
11class RandomizerCore
12{
13public:
14 void Randomize(std::vector<int>& panels, int flags);
15 void RandomizeRange(std::vector<int> &panels, int flags, size_t startIndex, size_t endIndex);
16 void SwapPanels(int panel1, int panel2, int flags);
17 void ReassignTargets(const std::vector<int>& panels, const std::vector<int>& order);
18
19 template <class T>
20 std::vector<T> ReadPanelData(int panel, int offset, size_t size) {
21 return _memory.ReadData<T>({GLOBALS, 0x18, panel*8, offset}, size);
22 }
23
24 template <class T>
25 void WritePanelData(int panel, int offset, const std::vector<T>& data) {
26 _memory.WriteData<T>({GLOBALS, 0x18, panel*8, offset}, data);
27 }
28
29private:
30 Memory _memory = Memory("witness64_d3d11.exe");
31};
32
33#if GLOBALS == 0x5B28C0
34#define PATH_COLOR 0xC8
35#define REFLECTION_PATH_COLOR 0xD8
36#define DOT_COLOR 0xF8
37#define ACTIVE_COLOR 0x108
38#define BACKGROUND_REGION_COLOR 0x118
39#define SUCCESS_COLOR_A 0x128
40#define SUCCESS_COLOR_B 0x138
41#define STROBE_COLOR_A 0x148
42#define STROBE_COLOR_B 0x158
43#define ERROR_COLOR 0x168
44#define PATTERN_POINT_COLOR 0x188
45#define PATTERN_POINT_COLOR_A 0x198
46#define PATTERN_POINT_COLOR_B 0x1A8
47#define SYMBOL_A 0x1B8
48#define SYMBOL_B 0x1C8
49#define SYMBOL_C 0x1D8
50#define SYMBOL_D 0x1E8
51#define SYMBOL_E 0x1F8
52#define PUSH_SYMBOL_COLORS 0x208
53#define OUTER_BACKGROUND 0x20C
54#define OUTER_BACKGROUND_MODE 0x21C
55#define TRACED_EDGES 0x230
56#define AUDIO_PREFIX 0x278
57#define POWER 0x2A8
58#define TARGET 0x2BC
59#define IS_CYLINDER 0x2FC
60#define CYLINDER_Z0 0x300
61#define CYLINDER_Z1 0x304
62#define CYLINDER_RADIUS 0x308
63#define CURSOR_SPEED_SCALE 0x358
64#define SPECULAR_ADD 0x398
65#define SPECULAR_POWER 0x39C
66#define PATH_WIDTH_SCALE 0x3A4
67#define STARTPOINT_SCALE 0x3A8
68#define NUM_DOTS 0x3B8
69#define NUM_CONNECTIONS 0x3BC
70#define MAX_BROADCAST_DISTANCE 0x3C0
71#define DOT_POSITIONS 0x3C8
72#define DOT_FLAGS 0x3D0
73#define DOT_CONNECTION_A 0x3D8
74#define DOT_CONNECTION_B 0x3E0
75#define DECORATIONS 0x420
76#define DECORATION_FLAGS 0x428
77#define DECORATION_COLORS 0x430
78#define NUM_DECORATIONS 0x438
79#define REFLECTION_DATA 0x440
80#define GRID_SIZE_X 0x448
81#define GRID_SIZE_Y 0x44C
82#define STYLE_FLAGS 0x450
83#define SEQUENCE_LEN 0x45C
84#define SEQUENCE 0x460
85#define DOT_SEQUENCE_LEN 0x468
86#define DOT_SEQUENCE 0x470
87#define DOT_SEQUENCE_LEN_REFLECTION 0x478
88#define DOT_SEQUENCE_REFLECTION 0x480
89#define NUM_COLORED_REGIONS 0x4A0
90#define COLORED_REGIONS 0x4A8
91#define PANEL_TARGET 0x4B0
92#define SPECULAR_TEXTURE 0x4D8
93#define CABLE_TARGET_2 0xD8
94#elif GLOBALS == 0x62A080
95#define PATH_COLOR 0xC0
96#define REFLECTION_PATH_COLOR 0xD0
97#define DOT_COLOR 0xF0
98#define ACTIVE_COLOR 0x100
99#define BACKGROUND_REGION_COLOR 0x110
100#define SUCCESS_COLOR_A 0x120
101#define SUCCESS_COLOR_B 0x130
102#define STROBE_COLOR_A 0x140
103#define STROBE_COLOR_B 0x150
104#define ERROR_COLOR 0x160
105#define PATTERN_POINT_COLOR 0x180
106#define PATTERN_POINT_COLOR_A 0x190
107#define PATTERN_POINT_COLOR_B 0x1A0
108#define SYMBOL_A 0x1B0
109#define SYMBOL_B 0x1C0
110#define SYMBOL_C 0x1D0
111#define SYMBOL_D 0x1E0
112#define SYMBOL_E 0x1F0
113#define PUSH_SYMBOL_COLORS 0x200
114#define OUTER_BACKGROUND 0x204
115#define OUTER_BACKGROUND_MODE 0x214
116#define TRACED_EDGES 0x228
117#define AUDIO_PREFIX 0x270
118#define POWER 0x2A0
119#define TARGET 0x2B4
120#define IS_CYLINDER 0x2F4
121#define CYLINDER_Z0 0x2F8
122#define CYLINDER_Z1 0x2FC
123#define CYLINDER_RADIUS 0x300
124#define CURSOR_SPEED_SCALE 0x350
125#define SPECULAR_ADD 0x38C
126#define SPECULAR_POWER 0x390
127#define PATH_WIDTH_SCALE 0x39C
128#define STARTPOINT_SCALE 0x3A0
129#define NUM_DOTS 0x3B4
130#define NUM_CONNECTIONS 0x3B8
131#define MAX_BROADCAST_DISTANCE 0x3BC
132#define DOT_POSITIONS 0x3C0
133#define DOT_FLAGS 0x3C8
134#define DOT_CONNECTION_A 0x3D0
135#define DOT_CONNECTION_B 0x3D8
136#define DECORATIONS 0x418
137#define DECORATION_FLAGS 0x420
138#define DECORATION_COLORS 0x428
139#define NUM_DECORATIONS 0x430
140#define REFLECTION_DATA 0x438
141#define GRID_SIZE_X 0x440
142#define GRID_SIZE_Y 0x444
143#define STYLE_FLAGS 0x448
144#define SEQUENCE_LEN 0x454
145#define SEQUENCE 0x458
146#define DOT_SEQUENCE_LEN 0x460
147#define DOT_SEQUENCE 0x468
148#define DOT_SEQUENCE_LEN_REFLECTION 0x470
149#define DOT_SEQUENCE_REFLECTION 0x478
150#define NUM_COLORED_REGIONS 0x498
151#define COLORED_REGIONS 0x4A0
152#define PANEL_TARGET 0x4A8
153#define SPECULAR_TEXTURE 0x4D0
154#define CABLE_TARGET_2 0xD0
155#endif \ No newline at end of file