diff options
-rw-r--r-- | App/Main.cpp | 53 | ||||
-rw-r--r-- | App/Version.h | 2 | ||||
-rw-r--r-- | Source/Memory.h | 2 | ||||
-rw-r--r-- | Source/Randomizer.cpp | 106 | ||||
-rw-r--r-- | Source/Randomizer.h | 8 | ||||
-rw-r--r-- | Source/RandomizerCore.cpp | 39 | ||||
-rw-r--r-- | Source/RandomizerCore.h | 8 |
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 | ||
20 | HWND hwndSeed, hwndRandomize; | 21 | HWND hwndSeed, hwndRandomize; |
21 | int panel = 0x18AF; | 22 | int panel = 0x18AF; |
22 | // int panel = 0x33D4; | 23 | // int panel = 0x33D4; |
23 | std::shared_ptr<Panel> _panel; | 24 | std::shared_ptr<Panel> _panel; |
25 | std::shared_ptr<Randomizer> randomizer = std::make_shared<Randomizer>(); | ||
24 | 26 | ||
25 | LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | 27 | LRESULT 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 | |||
67 | private: | 69 | private: |
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 | ||
32 | short Randomizer::Randomize(int seed) | 29 | bool 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 | |||
40 | void 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 | ||
67 | void Randomizer::AdjustSpeed() { | 69 | void 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 | ||
76 | void Randomizer::RandomizeTutorial() { | 78 | void 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 | ||
84 | void Randomizer::RandomizeSymmetry() { | 86 | void 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 | ||
98 | void Randomizer::RandomizeQuarry() { | 100 | void Randomizer::RandomizeQuarry() { |
@@ -100,14 +102,14 @@ void Randomizer::RandomizeQuarry() { | |||
100 | 102 | ||
101 | void Randomizer::RandomizeTreehouse() { | 103 | void 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 | ||
113 | void Randomizer::RandomizeKeep() { | 115 | void Randomizer::RandomizeKeep() { |
@@ -115,11 +117,11 @@ void Randomizer::RandomizeKeep() { | |||
115 | 117 | ||
116 | void Randomizer::RandomizeShadows() { | 118 | void 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 | ||
136 | void Randomizer::RandomizeTown() { | 138 | void Randomizer::RandomizeTown() { |
@@ -167,7 +169,7 @@ void Randomizer::RandomizeJungle() { | |||
167 | 169 | ||
168 | void Randomizer::RandomizeSwamp() { | 170 | void 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 | ||
173 | void Randomizer::RandomizeMountain() { | 175 | void 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 | ||
203 | void Randomizer::RandomizeChallenge() { | 205 | void 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 | ||
4 | class Randomizer { | 4 | class Randomizer { |
5 | public: | 5 | public: |
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 | |||
9 | private: | 13 | private: |
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 | ||
6 | static int lastKnownFrame = 1 << 30; | ||
7 | |||
8 | RandomizerCore::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 | |||
17 | void RandomizerCore::Randomize(std::vector<int>& panels, int flags) { | 6 | void 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 | ||
129 | void RandomizerCore::ReassignNames(const std::vector<int>& panels, const std::vector<int>& order) { | 118 | void 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 | ||
140 | short RandomizerCore::ReadMetadata() { | 129 | short RandomizerCore::ReadMetadata() { |
141 | return _memory.ReadData<short>({GLOBALS + METADATA}, 1)[0]; | 130 | return _memory->ReadData<short>({GLOBALS + METADATA}, 1)[0]; |
142 | } | 131 | } |
143 | 132 | ||
144 | void RandomizerCore::WriteMetadata(short metadata) { | 133 | void 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 | |||
137 | int 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; | |||
9 | class RandomizerCore | 10 | class RandomizerCore |
10 | { | 11 | { |
11 | public: | 12 | public: |
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 |