summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--App/Main.cpp53
-rw-r--r--App/Version.h2
-rw-r--r--Source/Memory.h2
-rw-r--r--Source/Randomizer.cpp106
-rw-r--r--Source/Randomizer.h8
-rw-r--r--Source/RandomizerCore.cpp39
-rw-r--r--Source/RandomizerCore.h8
7 files changed, 122 insertions, 96 deletions
diff --git a/App/Main.cpp b/App/Main.cpp index 48cb93d..ab3e88a 100644 --- a/App/Main.cpp +++ b/App/Main.cpp
@@ -16,19 +16,26 @@
16#define IDC_RANDOM 0x406 16#define IDC_RANDOM 0x406
17#define IDC_WRITE 0x407 17#define IDC_WRITE 0x407
18#define IDC_DUMP 0x408 18#define IDC_DUMP 0x408
19#define IDT_RANDOMIZED 0x409
19 20
20HWND hwndSeed, hwndRandomize; 21HWND hwndSeed, hwndRandomize;
21int panel = 0x18AF; 22int panel = 0x18AF;
22// int panel = 0x33D4; 23// int panel = 0x33D4;
23std::shared_ptr<Panel> _panel; 24std::shared_ptr<Panel> _panel;
25std::shared_ptr<Randomizer> randomizer = std::make_shared<Randomizer>();
24 26
25LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 27LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
26{ 28{
27 static bool wasSeedRandomlyGenerated; 29 static bool seedIsRNG = false;
28 30
29 if (message == WM_DESTROY) { 31 if (message == WM_DESTROY) {
30 PostQuitMessage(0); 32 PostQuitMessage(0);
31 } else if (message == WM_COMMAND) { 33 } else if (message == WM_COMMAND || message == WM_TIMER) {
34 switch (HIWORD(wParam)) {
35 // Seed contents changed
36 case EN_CHANGE:
37 seedIsRNG = false;
38 }
32 switch (LOWORD(wParam)) { 39 switch (LOWORD(wParam)) {
33 // Speed checkbox 40 // Speed checkbox
34 case IDC_TOGGLESPEED: 41 case IDC_TOGGLESPEED:
@@ -42,29 +49,41 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
42 // Randomize button 49 // Randomize button
43 case IDC_RANDOMIZE: 50 case IDC_RANDOMIZE:
44 { 51 {
45 std::wstring text(100, '\0'); 52 std::wstring text;
53 text.reserve(100);
46 GetWindowText(hwndSeed, &text[0], 100); 54 GetWindowText(hwndSeed, &text[0], 100);
47 int seed = 0; 55 int seed = _wtoi(text.c_str());
48 if (wasSeedRandomlyGenerated || wcslen(text.c_str()) == 0) { 56
57 if (seedIsRNG || text.empty()) {
49 seed = Random::RandInt(0, 100000); 58 seed = Random::RandInt(0, 100000);
50 wasSeedRandomlyGenerated = true; 59 seedIsRNG = true;
51 } else {
52 seed = _wtoi(text.c_str());
53 wasSeedRandomlyGenerated = false;
54 } 60 }
55 61
56 Randomizer randomizer; 62 randomizer->ClearOffsets();
57 short metadata = randomizer.Randomize(seed); 63 /* TODO:
58 if (metadata & 0x1) break; // Was already randomized 64 if (!randomizer->GameIsRunning()) {
59 65 randomizer->StartGame(); // Try: CreateProcess(L"/path/to/TW.exe", ...);
66 }
67 */
68 if (randomizer->GameIsRandomized()) break;
69 Random::SetSeed(seed);
60 std::wstring seedString = std::to_wstring(seed); 70 std::wstring seedString = std::to_wstring(seed);
71 SetWindowText(hwndRandomize, L"Randomizing...");
61 SetWindowText(hwndSeed, seedString.c_str()); 72 SetWindowText(hwndSeed, seedString.c_str());
62 if (IsDlgButtonChecked(hwnd, IDC_TOGGLESPEED)) { 73 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
63 randomizer.AdjustSpeed(); 74
75 randomizer->Randomize();
76 if (IsDlgButtonChecked(hwnd, IDC_TOGGLESPEED)) {
77 randomizer->AdjustSpeed();
64 } 78 }
65 SetWindowText(hwndRandomize, L"Randomized!"); 79 SetWindowText(hwndRandomize, L"Randomized!");
80 SetTimer(hwnd, IDT_RANDOMIZED, 10000, NULL);
66 break; 81 break;
67 } 82 }
83
84 case IDT_RANDOMIZED:
85 SetWindowText(hwndRandomize, L"Randomize");
86 break;
68 case IDC_READ: 87 case IDC_READ:
69 _panel = std::make_shared<Panel>(panel); 88 _panel = std::make_shared<Panel>(panel);
70 break; 89 break;
@@ -115,9 +134,11 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmd
115 hwndSeed = CreateWindow(MSFTEDIT_CLASS, L"", 134 hwndSeed = CreateWindow(MSFTEDIT_CLASS, L"",
116 WS_TABSTOP | WS_VISIBLE | WS_CHILD | WS_BORDER, 135 WS_TABSTOP | WS_VISIBLE | WS_CHILD | WS_BORDER,
117 100, 10, 50, 26, hwnd, NULL, hInstance, NULL); 136 100, 10, 50, 26, hwnd, NULL, hInstance, NULL);
137 SendMessage(hwndSeed, EM_SETEVENTMASK, NULL, ENM_CHANGE); // Notify on text change
138
118 hwndRandomize = CreateWindow(L"BUTTON", L"Randomize", 139 hwndRandomize = CreateWindow(L"BUTTON", L"Randomize",
119 WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 140 WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
120 160, 10, 100, 26, hwnd, (HMENU)IDC_RANDOMIZE, hInstance, NULL); 141 160, 10, 110, 26, hwnd, (HMENU)IDC_RANDOMIZE, hInstance, NULL);
121 142
122#if GLOBALS == 0x5B28C0 143#if GLOBALS == 0x5B28C0
123 CreateWindow(L"BUTTON", L"READ", 144 CreateWindow(L"BUTTON", L"READ",
diff --git a/App/Version.h b/App/Version.h index 05696d6..8029020 100644 --- a/App/Version.h +++ b/App/Version.h
@@ -5,7 +5,7 @@
5 5
6#define MAJOR 4 6#define MAJOR 4
7#define MINOR 0 7#define MINOR 0
8#define PATCH 0 8#define PATCH 4
9 9
10#define VERSION_STR TO_STRING(MAJOR) L"." TO_STRING(MINOR) L"." TO_STRING(PATCH) 10#define VERSION_STR TO_STRING(MAJOR) L"." TO_STRING(MINOR) L"." TO_STRING(PATCH)
11#define VERSION MAJOR, MINOR, PATCH 11#define VERSION MAJOR, MINOR, PATCH
diff --git a/Source/Memory.h b/Source/Memory.h index d2ab50e..4c79d7c 100644 --- a/Source/Memory.h +++ b/Source/Memory.h
@@ -64,6 +64,8 @@ public:
64 ThrowError(); 64 ThrowError();
65 } 65 }
66 66
67 void ClearOffsets() {_computedAddresses = std::map<uintptr_t, uintptr_t>();}
68
67private: 69private:
68 70
69 void ThrowError(); 71 void ThrowError();
diff --git a/Source/Randomizer.cpp b/Source/Randomizer.cpp index 8833078..3cc2712 100644 --- a/Source/Randomizer.cpp +++ b/Source/Randomizer.cpp
@@ -1,16 +1,13 @@
1/* 1/*
2 * BUGS: 2 * BUGS:
3 * Shipwreck vault is solved reversed? 3 * Shipwreck vault is solved reversed? -> Not reversed, just "half", you can normally solve orange. Seems to need pattern name.
4 * Swamp <-> symmetry has non-invisible background 4 * Tutorial sounds don't always play -> Unsure. Not controlled by pattern name.
5 * Tutorial sounds don't always play
6 * FEATURES: 5 * FEATURES:
7 * Clear "Randomized" button after short delay
8 * Randomize audio logs -- Hard, seem to be unloaded some times? 6 * Randomize audio logs -- Hard, seem to be unloaded some times?
9 * Swap sounds in jungle (along with panels) -- maybe impossible 7 * Swap sounds in jungle (along with panels) -- maybe impossible
10 * Make orange 7 (all of oranges?) hard. Like big = hard. 8 * Make orange 7 (all of oranges?) hard. Like big = hard. (See: HARD_MODE)
11 * Start the game if it isn't running? 9 * Start the game if it isn't running?
12 * Stop swapping colors in desert 10 * Stop swapping colors in desert
13 * Allow users to enter seed after randomly generating seed (aka detect user input in the text box)
14*/ 11*/
15#include "Memory.h" 12#include "Memory.h"
16#include "Randomizer.h" 13#include "Randomizer.h"
@@ -29,15 +26,21 @@ int find(const std::vector<T> &data, T search, size_t startIndex = 0) {
29 exit(-1); 26 exit(-1);
30} 27}
31 28
32short Randomizer::Randomize(int seed) 29bool Randomizer::GameIsRandomized() {
33{ 30 int currentFrame = _core.GetCurrentFrame();
34 short metadata = _core.ReadMetadata(); 31 if (currentFrame >= _lastRandomizedFrame) {
35 if (metadata & 0x1) { 32 // Time went forwards, presumably we're still on the same save
36 // Already randomized -- exit. 33 _lastRandomizedFrame = currentFrame;
37 return metadata; 34 return true;
38 } 35 }
39 _core.WriteMetadata(metadata | 0x1); 36 // Otherwise, time has gone backwards, so assume new game
40 Random::SetSeed(seed); 37 return false;
38}
39
40void Randomizer::Randomize()
41{
42 if (GameIsRandomized()) return; // Nice sanity check, but should be unnecessary (since Main checks anyways)
43 _lastRandomizedFrame = _core.GetCurrentFrame();
41 44
42 // Content swaps -- must happen before squarePanels 45 // Content swaps -- must happen before squarePanels
43 _core.Randomize(upDownPanels, SWAP_LINES); 46 _core.Randomize(upDownPanels, SWAP_LINES);
@@ -61,24 +64,23 @@ short Randomizer::Randomize(int seed)
61 RandomizeMountain(); 64 RandomizeMountain();
62 // RandomizeChallenge(); 65 // RandomizeChallenge();
63 // RandomizeAudioLogs(); 66 // RandomizeAudioLogs();
64 return metadata;
65} 67}
66 68
67void Randomizer::AdjustSpeed() { 69void Randomizer::AdjustSpeed() {
68 // Desert Surface Final Control 70 // Desert Surface Final Control
69 _core._memory.WritePanelData<float>(0x09F95, OPEN_RATE, {0.04f}); // 4x 71 _core._memory->WritePanelData<float>(0x09F95, OPEN_RATE, {0.04f}); // 4x
70 // Swamp Sliding Bridge 72 // Swamp Sliding Bridge
71 _core._memory.WritePanelData<float>(0x0061A, OPEN_RATE, {0.1f}); // 4x 73 _core._memory->WritePanelData<float>(0x0061A, OPEN_RATE, {0.1f}); // 4x
72 // Mountain 2 Elevator 74 // Mountain 2 Elevator
73 _core._memory.WritePanelData<float>(0x09EEC, OPEN_RATE, {0.075f}); // 3x 75 _core._memory->WritePanelData<float>(0x09EEC, OPEN_RATE, {0.075f}); // 3x
74} 76}
75 77
76void Randomizer::RandomizeTutorial() { 78void Randomizer::RandomizeTutorial() {
77 // Disable tutorial cursor speed modifications (not working?) 79 // Disable tutorial cursor speed modifications (not working?)
78 _core._memory.WritePanelData<float>(0x00295, CURSOR_SPEED_SCALE, {1.0}); 80 _core._memory->WritePanelData<float>(0x00295, CURSOR_SPEED_SCALE, {1.0});
79 _core._memory.WritePanelData<float>(0x0C373, CURSOR_SPEED_SCALE, {1.0}); 81 _core._memory->WritePanelData<float>(0x0C373, CURSOR_SPEED_SCALE, {1.0});
80 _core._memory.WritePanelData<float>(0x00293, CURSOR_SPEED_SCALE, {1.0}); 82 _core._memory->WritePanelData<float>(0x00293, CURSOR_SPEED_SCALE, {1.0});
81 _core._memory.WritePanelData<float>(0x002C2, CURSOR_SPEED_SCALE, {1.0}); 83 _core._memory->WritePanelData<float>(0x002C2, CURSOR_SPEED_SCALE, {1.0});
82} 84}
83 85
84void Randomizer::RandomizeSymmetry() { 86void Randomizer::RandomizeSymmetry() {
@@ -88,11 +90,11 @@ void Randomizer::RandomizeDesert() {
88 _core.Randomize(desertPanels, SWAP_LINES); 90 _core.Randomize(desertPanels, SWAP_LINES);
89 91
90 // Turn off desert surface 8 92 // Turn off desert surface 8
91 _core._memory.WritePanelData<float>(0x09F94, POWER, {0.0, 0.0}); 93 _core._memory->WritePanelData<float>(0x09F94, POWER, {0.0, 0.0});
92 // Turn off desert flood final 94 // Turn off desert flood final
93 _core._memory.WritePanelData<float>(0x18076, POWER, {0.0, 0.0}); 95 _core._memory->WritePanelData<float>(0x18076, POWER, {0.0, 0.0});
94 // Change desert floating target to desert flood final 96 // Change desert floating target to desert flood final
95 _core._memory.WritePanelData<int>(0x17ECA, TARGET, {0x18077}); 97 _core._memory->WritePanelData<int>(0x17ECA, TARGET, {0x18077});
96} 98}
97 99
98void Randomizer::RandomizeQuarry() { 100void Randomizer::RandomizeQuarry() {
@@ -100,14 +102,14 @@ void Randomizer::RandomizeQuarry() {
100 102
101void Randomizer::RandomizeTreehouse() { 103void Randomizer::RandomizeTreehouse() {
102 // Ensure that whatever pivot panels we have are flagged as "pivotable" 104 // Ensure that whatever pivot panels we have are flagged as "pivotable"
103 int panelFlags = _core._memory.ReadPanelData<int>(0x17DD1, STYLE_FLAGS, 1)[0]; 105 int panelFlags = _core._memory->ReadPanelData<int>(0x17DD1, STYLE_FLAGS, 1)[0];
104 _core._memory.WritePanelData<int>(0x17DD1, STYLE_FLAGS, {panelFlags | 0x8000}); 106 _core._memory->WritePanelData<int>(0x17DD1, STYLE_FLAGS, {panelFlags | 0x8000});
105 panelFlags = _core._memory.ReadPanelData<int>(0x17CE3, STYLE_FLAGS, 1)[0]; 107 panelFlags = _core._memory->ReadPanelData<int>(0x17CE3, STYLE_FLAGS, 1)[0];
106 _core._memory.WritePanelData<int>(0x17CE3, STYLE_FLAGS, {panelFlags | 0x8000}); 108 _core._memory->WritePanelData<int>(0x17CE3, STYLE_FLAGS, {panelFlags | 0x8000});
107 panelFlags = _core._memory.ReadPanelData<int>(0x17DB7, STYLE_FLAGS, 1)[0]; 109 panelFlags = _core._memory->ReadPanelData<int>(0x17DB7, STYLE_FLAGS, 1)[0];
108 _core._memory.WritePanelData<int>(0x17DB7, STYLE_FLAGS, {panelFlags | 0x8000}); 110 _core._memory->WritePanelData<int>(0x17DB7, STYLE_FLAGS, {panelFlags | 0x8000});
109 panelFlags = _core._memory.ReadPanelData<int>(0x17E52, STYLE_FLAGS, 1)[0]; 111 panelFlags = _core._memory->ReadPanelData<int>(0x17E52, STYLE_FLAGS, 1)[0];
110 _core._memory.WritePanelData<int>(0x17E52, STYLE_FLAGS, {panelFlags | 0x8000}); 112 _core._memory->WritePanelData<int>(0x17E52, STYLE_FLAGS, {panelFlags | 0x8000});
111} 113}
112 114
113void Randomizer::RandomizeKeep() { 115void Randomizer::RandomizeKeep() {
@@ -115,11 +117,11 @@ void Randomizer::RandomizeKeep() {
115 117
116void Randomizer::RandomizeShadows() { 118void Randomizer::RandomizeShadows() {
117 // Distance-gate shadows laser to prevent sniping through the bars 119 // Distance-gate shadows laser to prevent sniping through the bars
118 _core._memory.WritePanelData<float>(0x19650, MAX_BROADCAST_DISTANCE, {2.5}); 120 _core._memory->WritePanelData<float>(0x19650, MAX_BROADCAST_DISTANCE, {2.5});
119 // Change the shadows tutorial cable to only activate avoid 121 // Change the shadows tutorial cable to only activate avoid
120 _core._memory.WritePanelData<int>(0x319A8, CABLE_TARGET_2, {0}); 122 _core._memory->WritePanelData<int>(0x319A8, CABLE_TARGET_2, {0});
121 // Change shadows avoid 8 to power shadows follow 123 // Change shadows avoid 8 to power shadows follow
122 _core._memory.WritePanelData<int>(0x1972F, TARGET, {0x1C34C}); 124 _core._memory->WritePanelData<int>(0x1972F, TARGET, {0x1C34C});
123 125
124 std::vector<int> randomOrder(shadowsPanels.size(), 0); 126 std::vector<int> randomOrder(shadowsPanels.size(), 0);
125 std::iota(randomOrder.begin(), randomOrder.end(), 0); 127 std::iota(randomOrder.begin(), randomOrder.end(), 0);
@@ -128,9 +130,9 @@ void Randomizer::RandomizeShadows() {
128 _core.RandomizeRange(randomOrder, SWAP_NONE, 16, 21); // Follow 130 _core.RandomizeRange(randomOrder, SWAP_NONE, 16, 21); // Follow
129 _core.ReassignTargets(shadowsPanels, randomOrder); 131 _core.ReassignTargets(shadowsPanels, randomOrder);
130 // Turn off original starting panel 132 // Turn off original starting panel
131 _core._memory.WritePanelData<float>(shadowsPanels[0], POWER, {0.0f, 0.0f}); 133 _core._memory->WritePanelData<float>(shadowsPanels[0], POWER, {0.0f, 0.0f});
132 // Turn on new starting panel 134 // Turn on new starting panel
133 _core._memory.WritePanelData<float>(shadowsPanels[randomOrder[0]], POWER, {1.0f, 1.0f}); 135 _core._memory->WritePanelData<float>(shadowsPanels[randomOrder[0]], POWER, {1.0f, 1.0f});
134} 136}
135 137
136void Randomizer::RandomizeTown() { 138void Randomizer::RandomizeTown() {
@@ -167,7 +169,7 @@ void Randomizer::RandomizeJungle() {
167 169
168void Randomizer::RandomizeSwamp() { 170void Randomizer::RandomizeSwamp() {
169 // Distance-gate swamp snipe 1 to prevent RNG swamp snipe 171 // Distance-gate swamp snipe 1 to prevent RNG swamp snipe
170 _core._memory.WritePanelData<float>(0x17C05, MAX_BROADCAST_DISTANCE, {15.0}); 172 _core._memory->WritePanelData<float>(0x17C05, MAX_BROADCAST_DISTANCE, {15.0});
171} 173}
172 174
173void Randomizer::RandomizeMountain() { 175void Randomizer::RandomizeMountain() {
@@ -178,7 +180,7 @@ void Randomizer::RandomizeMountain() {
178 // Randomize final pillars order 180 // Randomize final pillars order
179 std::vector<int> targets = {pillars[0] + 1}; 181 std::vector<int> targets = {pillars[0] + 1};
180 for (const int pillar : pillars) { 182 for (const int pillar : pillars) {
181 int target = _core._memory.ReadPanelData<int>(pillar, TARGET, 1)[0]; 183 int target = _core._memory->ReadPanelData<int>(pillar, TARGET, 1)[0];
182 targets.push_back(target); 184 targets.push_back(target);
183 } 185 }
184 targets[5] = pillars[5] + 1; 186 targets[5] = pillars[5] + 1;
@@ -189,27 +191,27 @@ void Randomizer::RandomizeMountain() {
189 _core.RandomizeRange(randomOrder, SWAP_NONE, 5, 9); // Right Pillars 1-4 191 _core.RandomizeRange(randomOrder, SWAP_NONE, 5, 9); // Right Pillars 1-4
190 _core.ReassignTargets(pillars, randomOrder, targets); 192 _core.ReassignTargets(pillars, randomOrder, targets);
191 // Turn off original starting panels 193 // Turn off original starting panels
192 _core._memory.WritePanelData<float>(pillars[0], POWER, {0.0f, 0.0f}); 194 _core._memory->WritePanelData<float>(pillars[0], POWER, {0.0f, 0.0f});
193 _core._memory.WritePanelData<float>(pillars[5], POWER, {0.0f, 0.0f}); 195 _core._memory->WritePanelData<float>(pillars[5], POWER, {0.0f, 0.0f});
194 // Turn on new starting panels 196 // Turn on new starting panels
195 _core._memory.WritePanelData<float>(pillars[randomOrder[0]], POWER, {1.0f, 1.0f}); 197 _core._memory->WritePanelData<float>(pillars[randomOrder[0]], POWER, {1.0f, 1.0f});
196 _core._memory.WritePanelData<float>(pillars[randomOrder[5]], POWER, {1.0f, 1.0f}); 198 _core._memory->WritePanelData<float>(pillars[randomOrder[5]], POWER, {1.0f, 1.0f});
197 199
198 // Read the target of keep front laser, and write it to keep back laser. 200 // Read the target of keep front laser, and write it to keep back laser.
199 std::vector<int> keepFrontLaserTarget = _core._memory.ReadPanelData<int>(0x0360E, TARGET, 1); 201 std::vector<int> keepFrontLaserTarget = _core._memory->ReadPanelData<int>(0x0360E, TARGET, 1);
200 _core._memory.WritePanelData<int>(0x03317, TARGET, keepFrontLaserTarget); 202 _core._memory->WritePanelData<int>(0x03317, TARGET, keepFrontLaserTarget);
201} 203}
202 204
203void Randomizer::RandomizeChallenge() { 205void Randomizer::RandomizeChallenge() {
204 std::vector<int> randomOrder(challengePanels.size(), 0); 206 std::vector<int> randomOrder(challengePanels.size(), 0);
205 std::iota(randomOrder.begin(), randomOrder.end(), 0); 207 std::iota(randomOrder.begin(), randomOrder.end(), 0);
206 _core.RandomizeRange(randomOrder, SWAP_NONE, 1, 9); // Easy maze - Triple 2 208 _core.RandomizeRange(randomOrder, SWAP_NONE, 1, 9); // Easy maze - Triple 2
207 std::vector<int> triple1Target = _core._memory.ReadPanelData<int>(0x00C80, TARGET, 1); 209 std::vector<int> triple1Target = _core._memory->ReadPanelData<int>(0x00C80, TARGET, 1);
208 _core._memory.WritePanelData<int>(0x00CA1, TARGET, triple1Target); 210 _core._memory->WritePanelData<int>(0x00CA1, TARGET, triple1Target);
209 _core._memory.WritePanelData<int>(0x00CB9, TARGET, triple1Target); 211 _core._memory->WritePanelData<int>(0x00CB9, TARGET, triple1Target);
210 std::vector<int> triple2Target = _core._memory.ReadPanelData<int>(0x00C22, TARGET, 1); 212 std::vector<int> triple2Target = _core._memory->ReadPanelData<int>(0x00C22, TARGET, 1);
211 _core._memory.WritePanelData<int>(0x00C59, TARGET, triple2Target); 213 _core._memory->WritePanelData<int>(0x00C59, TARGET, triple2Target);
212 _core._memory.WritePanelData<int>(0x00C68, TARGET, triple2Target); 214 _core._memory->WritePanelData<int>(0x00C68, TARGET, triple2Target);
213 _core.ReassignTargets(challengePanels, randomOrder); 215 _core.ReassignTargets(challengePanels, randomOrder);
214} 216}
215 217
diff --git a/Source/Randomizer.h b/Source/Randomizer.h index 8c332b0..ea05975 100644 --- a/Source/Randomizer.h +++ b/Source/Randomizer.h
@@ -3,10 +3,16 @@
3 3
4class Randomizer { 4class Randomizer {
5public: 5public:
6 short Randomize(int seed); 6 void Randomize();
7 bool GameIsRandomized();
8
7 void AdjustSpeed(); 9 void AdjustSpeed();
8 10
11 void ClearOffsets() {_core.ClearOffsets();}
12
9private: 13private:
14
15 int _lastRandomizedFrame = 1 << 30;
10 void RandomizeTutorial(); 16 void RandomizeTutorial();
11 void RandomizeSymmetry(); 17 void RandomizeSymmetry();
12 void RandomizeDesert(); 18 void RandomizeDesert();
diff --git a/Source/RandomizerCore.cpp b/Source/RandomizerCore.cpp index d4aadef..f00dacd 100644 --- a/Source/RandomizerCore.cpp +++ b/Source/RandomizerCore.cpp
@@ -3,17 +3,6 @@
3#include "Random.h" 3#include "Random.h"
4#include <sstream> 4#include <sstream>
5 5
6static int lastKnownFrame = 1 << 30;
7
8RandomizerCore::RandomizerCore() {
9 int currentFrame = _memory.ReadData<int>({SCRIPT_FRAMES}, 1)[0];
10 if (currentFrame < lastKnownFrame) {
11 // Time went backwards, indicates new game
12 WriteMetadata(0);
13 }
14 lastKnownFrame = currentFrame;
15}
16
17void RandomizerCore::Randomize(std::vector<int>& panels, int flags) { 6void RandomizerCore::Randomize(std::vector<int>& panels, int flags) {
18 return RandomizeRange(panels, flags, 0, panels.size()); 7 return RandomizeRange(panels, flags, 0, panels.size());
19} 8}
@@ -47,7 +36,7 @@ void RandomizerCore::SwapPanels(int panel1, int panel2, int flags) {
47 offsets[REFLECTION_PATH_COLOR] = 16; 36 offsets[REFLECTION_PATH_COLOR] = 16;
48 offsets[DOT_COLOR] = 16; 37 offsets[DOT_COLOR] = 16;
49 offsets[ACTIVE_COLOR] = 16; 38 offsets[ACTIVE_COLOR] = 16;
50 offsets[BACKGROUND_REGION_COLOR] = 16; 39 offsets[BACKGROUND_REGION_COLOR] = 12; // Not copying alpha to preserve transparency.
51 offsets[SUCCESS_COLOR_A] = 16; 40 offsets[SUCCESS_COLOR_A] = 16;
52 offsets[SUCCESS_COLOR_B] = 16; 41 offsets[SUCCESS_COLOR_B] = 16;
53 offsets[STROBE_COLOR_A] = 16; 42 offsets[STROBE_COLOR_A] = 16;
@@ -101,10 +90,10 @@ void RandomizerCore::SwapPanels(int panel1, int panel2, int flags) {
101 } 90 }
102 91
103 for (auto const& [offset, size] : offsets) { 92 for (auto const& [offset, size] : offsets) {
104 std::vector<byte> panel1data = _memory.ReadPanelData<byte>(panel1, offset, size); 93 std::vector<byte> panel1data = _memory->ReadPanelData<byte>(panel1, offset, size);
105 std::vector<byte> panel2data = _memory.ReadPanelData<byte>(panel2, offset, size); 94 std::vector<byte> panel2data = _memory->ReadPanelData<byte>(panel2, offset, size);
106 _memory.WritePanelData<byte>(panel2, offset, panel1data); 95 _memory->WritePanelData<byte>(panel2, offset, panel1data);
107 _memory.WritePanelData<byte>(panel1, offset, panel2data); 96 _memory->WritePanelData<byte>(panel1, offset, panel2data);
108 } 97 }
109} 98}
110 99
@@ -114,7 +103,7 @@ void RandomizerCore::ReassignTargets(const std::vector<int>& panels, const std::
114 // The first panel may not have a wire to power it, so we use the panel ID itself. 103 // The first panel may not have a wire to power it, so we use the panel ID itself.
115 targets = {panels[0] + 1}; 104 targets = {panels[0] + 1};
116 for (const int panel : panels) { 105 for (const int panel : panels) {
117 int target = _memory.ReadPanelData<int>(panel, TARGET, 1)[0]; 106 int target = _memory->ReadPanelData<int>(panel, TARGET, 1)[0];
118 targets.push_back(target); 107 targets.push_back(target);
119 } 108 }
120 } 109 }
@@ -122,25 +111,29 @@ void RandomizerCore::ReassignTargets(const std::vector<int>& panels, const std::
122 for (size_t i=0; i<order.size() - 1; i++) { 111 for (size_t i=0; i<order.size() - 1; i++) {
123 // Set the target of order[i] to order[i+1], using the "real" target as determined above. 112 // Set the target of order[i] to order[i+1], using the "real" target as determined above.
124 const int panelTarget = targets[order[i+1]]; 113 const int panelTarget = targets[order[i+1]];
125 _memory.WritePanelData<int>(panels[order[i]], TARGET, {panelTarget}); 114 _memory->WritePanelData<int>(panels[order[i]], TARGET, {panelTarget});
126 } 115 }
127} 116}
128 117
129void RandomizerCore::ReassignNames(const std::vector<int>& panels, const std::vector<int>& order) { 118void RandomizerCore::ReassignNames(const std::vector<int>& panels, const std::vector<int>& order) {
130 std::vector<int64_t> names; 119 std::vector<int64_t> names;
131 for (const int panel : panels) { 120 for (const int panel : panels) {
132 names.push_back(_memory.ReadPanelData<int64_t>(panel, AUDIO_LOG_NAME, 1)[0]); 121 names.push_back(_memory->ReadPanelData<int64_t>(panel, AUDIO_LOG_NAME, 1)[0]);
133 } 122 }
134 123
135 for (int i=0; i<panels.size(); i++) { 124 for (int i=0; i<panels.size(); i++) {
136 _memory.WritePanelData<int64_t>(panels[i], AUDIO_LOG_NAME, {names[order[i]]}); 125 _memory->WritePanelData<int64_t>(panels[i], AUDIO_LOG_NAME, {names[order[i]]});
137 } 126 }
138} 127}
139 128
140short RandomizerCore::ReadMetadata() { 129short RandomizerCore::ReadMetadata() {
141 return _memory.ReadData<short>({GLOBALS + METADATA}, 1)[0]; 130 return _memory->ReadData<short>({GLOBALS + METADATA}, 1)[0];
142} 131}
143 132
144void RandomizerCore::WriteMetadata(short metadata) { 133void RandomizerCore::WriteMetadata(short metadata) {
145 return _memory.WriteData<short>({GLOBALS + METADATA}, {metadata}); 134 return _memory->WriteData<short>({GLOBALS + METADATA}, {metadata});
146} \ No newline at end of file 135}
136
137int RandomizerCore::GetCurrentFrame() {
138 return _memory->ReadData<int>({SCRIPT_FRAMES}, 1)[0];
139}
diff --git a/Source/RandomizerCore.h b/Source/RandomizerCore.h index 4cd4b42..7555de2 100644 --- a/Source/RandomizerCore.h +++ b/Source/RandomizerCore.h
@@ -1,5 +1,6 @@
1#pragma once 1#pragma once
2#include "Memory.h" 2#include "Memory.h"
3#include <memory>
3 4
4__declspec(selectany) int SWAP_NONE = 0x0; 5__declspec(selectany) int SWAP_NONE = 0x0;
5__declspec(selectany) int SWAP_TARGETS = 0x1; 6__declspec(selectany) int SWAP_TARGETS = 0x1;
@@ -9,8 +10,6 @@ __declspec(selectany) int SWAP_AUDIO_NAMES = 0x4;
9class RandomizerCore 10class RandomizerCore
10{ 11{
11public: 12public:
12 RandomizerCore();
13
14 void Randomize(std::vector<int>& panels, int flags); 13 void Randomize(std::vector<int>& panels, int flags);
15 void RandomizeRange(std::vector<int> &panels, int flags, size_t startIndex, size_t endIndex); 14 void RandomizeRange(std::vector<int> &panels, int flags, size_t startIndex, size_t endIndex);
16 void SwapPanels(int panel1, int panel2, int flags); 15 void SwapPanels(int panel1, int panel2, int flags);
@@ -19,9 +18,12 @@ public:
19 18
20 short ReadMetadata(); 19 short ReadMetadata();
21 void WriteMetadata(short metadata); 20 void WriteMetadata(short metadata);
21 int GetCurrentFrame();
22
23 void ClearOffsets() {_memory->ClearOffsets();}
22 24
23// private: 25// private:
24 Memory _memory = Memory("witness64_d3d11.exe"); 26 std::shared_ptr<Memory> _memory = std::make_shared<Memory>("witness64_d3d11.exe");
25}; 27};
26 28
27#if GLOBALS == 0x5B28C0 29#if GLOBALS == 0x5B28C0