about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--App/Main.cpp16
-rw-r--r--Installer/Installer.vdproj6
-rw-r--r--Source/ChallengeRandomizer.cpp145
-rw-r--r--Source/ChallengeRandomizer.h12
-rw-r--r--Source/Memory.h5
-rw-r--r--Source/Randomizer.cpp17
-rw-r--r--Source/Source.vcxproj2
-rw-r--r--Test/Temp.cpp4
8 files changed, 188 insertions, 19 deletions
diff --git a/App/Main.cpp b/App/Main.cpp index 7a8e7f3..7e802e9 100644 --- a/App/Main.cpp +++ b/App/Main.cpp
@@ -2,6 +2,7 @@
2#include <Richedit.h> 2#include <Richedit.h>
3 3
4#include <string> 4#include <string>
5#include <sstream>
5 6
6#include "Version.h" 7#include "Version.h"
7#include "Random.h" 8#include "Random.h"
@@ -18,7 +19,7 @@
18#define IDC_DUMP 0x408 19#define IDC_DUMP 0x408
19#define IDT_RANDOMIZED 0x409 20#define IDT_RANDOMIZED 0x409
20 21
21HWND hwndSeed, hwndRandomize; 22HWND hwndSeed, hwndRandomize, hwndDebug;
22// int panel = 0x18AF; 23// int panel = 0x18AF;
23int panel = 0x33D4; 24int panel = 0x33D4;
24std::shared_ptr<Panel> _panel; 25std::shared_ptr<Panel> _panel;
@@ -68,12 +69,21 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
68 */ 69 */
69 if (randomizer->GameIsRandomized()) break; 70 if (randomizer->GameIsRandomized()) break;
70 Random::SetSeed(seed); 71 Random::SetSeed(seed);
72
73
74 std::wstringstream debug;
75
71 std::wstring seedString = std::to_wstring(seed); 76 std::wstring seedString = std::to_wstring(seed);
72 SetWindowText(hwndRandomize, L"Randomizing..."); 77 SetWindowText(hwndRandomize, L"Randomizing...");
73 SetWindowText(hwndSeed, seedString.c_str()); 78 SetWindowText(hwndSeed, seedString.c_str());
74 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW); 79 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
75 80
76 randomizer->Randomize(); 81 randomizer->Randomize();
82 debug << Random::RandInt(0, 1000) << " ";
83 debug << Random::RandInt(0, 1000) << "\n";
84 debug << Random::RandInt(0, 1000) << " ";
85 debug << Random::RandInt(0, 1000);
86 SetWindowText(hwndDebug, debug.str().c_str());
77 if (IsDlgButtonChecked(hwnd, IDC_TOGGLESPEED)) { 87 if (IsDlgButtonChecked(hwnd, IDC_TOGGLESPEED)) {
78 randomizer->AdjustSpeed(); 88 randomizer->AdjustSpeed();
79 } 89 }
@@ -163,6 +173,10 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmd
163 WS_TABSTOP | WS_VISIBLE | WS_CHILD | SS_LEFT, 173 WS_TABSTOP | WS_VISIBLE | WS_CHILD | SS_LEFT,
164 27, 50, 205, 16, hwnd, NULL, hInstance, NULL); 174 27, 50, 205, 16, hwnd, NULL, hInstance, NULL);
165 175
176 hwndDebug = CreateWindow(L"STATIC", L"",
177 WS_TABSTOP | WS_VISIBLE | WS_CHILD | SS_LEFT,
178 200, 200, 100, 100, hwnd, NULL, hInstance, NULL);
179
166 /* 180 /*
167 CreateWindow(L"BUTTON", L"", 181 CreateWindow(L"BUTTON", L"",
168 WS_VISIBLE | WS_CHILD | BS_CHECKBOX, 182 WS_VISIBLE | WS_CHILD | BS_CHECKBOX,
diff --git a/Installer/Installer.vdproj b/Installer/Installer.vdproj index 384523f..cd1c976 100644 --- a/Installer/Installer.vdproj +++ b/Installer/Installer.vdproj
@@ -162,15 +162,15 @@
162 { 162 {
163 "Name" = "8:Microsoft Visual Studio" 163 "Name" = "8:Microsoft Visual Studio"
164 "ProductName" = "8:Witness Randomizer" 164 "ProductName" = "8:Witness Randomizer"
165 "ProductCode" = "8:{F734652B-1189-42EB-8C54-74AB360F0718}" 165 "ProductCode" = "8:{ED6B3515-B039-4560-B97F-A61695CCDE5F}"
166 "PackageCode" = "8:{9AFF1832-7FC0-41C8-BC56-5F628694A1FF}" 166 "PackageCode" = "8:{4C062EDD-4A06-4DC6-9C37-82A2BD37A0B5}"
167 "UpgradeCode" = "8:{4CB5496B-A47E-41D3-B4A7-677E29AB7513}" 167 "UpgradeCode" = "8:{4CB5496B-A47E-41D3-B4A7-677E29AB7513}"
168 "AspNetVersion" = "8:2.0.50727.0" 168 "AspNetVersion" = "8:2.0.50727.0"
169 "RestartWWWService" = "11:FALSE" 169 "RestartWWWService" = "11:FALSE"
170 "RemovePreviousVersions" = "11:FALSE" 170 "RemovePreviousVersions" = "11:FALSE"
171 "DetectNewerInstalledVersion" = "11:TRUE" 171 "DetectNewerInstalledVersion" = "11:TRUE"
172 "InstallAllUsers" = "11:FALSE" 172 "InstallAllUsers" = "11:FALSE"
173 "ProductVersion" = "8:4.0.6" 173 "ProductVersion" = "8:4.0.8"
174 "Manufacturer" = "8:jbzdarkid" 174 "Manufacturer" = "8:jbzdarkid"
175 "ARPHELPTELEPHONE" = "8:" 175 "ARPHELPTELEPHONE" = "8:"
176 "ARPHELPLINK" = "8:https://www.github.com/jbzdarkid/witness-randomizer/issues" 176 "ARPHELPLINK" = "8:https://www.github.com/jbzdarkid/witness-randomizer/issues"
diff --git a/Source/ChallengeRandomizer.cpp b/Source/ChallengeRandomizer.cpp new file mode 100644 index 0000000..b9b54e0 --- /dev/null +++ b/Source/ChallengeRandomizer.cpp
@@ -0,0 +1,145 @@
1#include "ChallengeRandomizer.h"
2#include <iostream>
3
4int find(const std::vector<byte> &data, const std::vector<byte>& search, size_t startIndex = 0) {
5 for (size_t i=startIndex; i<data.size() - search.size(); i++) {
6 bool match = true;
7 for (size_t j=0; j<search.size(); j++) {
8 if (data[i+j] == search[j]) {
9 continue;
10 }
11 match = false;
12 break;
13 }
14 if (match) return static_cast<int>(i);
15 }
16 return -1;
17}
18
19void ChallengeRandomizer::AdjustRng(int offset) {
20 int currentRng = _memory->ReadData<int>({offset}, 0x1)[0];
21 _memory->WriteData<int>({offset}, {currentRng + 0x20});
22}
23
24ChallengeRandomizer::ChallengeRandomizer(const std::shared_ptr<Memory>& memory, int seed) : _memory(memory)
25{
26 int RNG_ADDR = _memory->ReadData<int>({GLOBALS + 0x10}, 1)[0];
27 int RNG2_ADDR = _memory->ReadData<int>({GLOBALS + 0x30}, 1)[0];
28 _memory->WriteData<int>({GLOBALS + 0x30}, {RNG_ADDR + 4});
29 if (RNG2_ADDR == RNG_ADDR + 4) return; // Already applied hack
30
31 int shuffle_integers = -1;
32 int cut_random_edges = -1;
33 int get_empty_decoration_slot = -1;
34 int get_empty_dot_spot = -1;
35 int add_exactly_this_many_bisection_dots = -1;
36 int make_a_shaper = -1;
37 int init_pattern_data_lotus = -1;
38 int reroll_lotus_eater_stuff = -1;
39 int do_lotus_minutes = -1;
40 int do_lotus_eighths = -1;
41 int do_success_side_effects = -1;
42
43 for (int i=0; i<0x200000; i+=0x1000) {
44 std::vector<byte> data = _memory->ReadData<byte>({i}, 0x1100);
45 std::cout << data.size() << std::endl;
46
47 if (shuffle_integers == -1) {
48 int index = find(data, {0x48, 0x89, 0x5C, 0x24, 0x10, 0x56, 0x48, 0x83, 0xEC, 0x20, 0x48, 0x63, 0xDA, 0x48, 0x8B, 0xF1, 0x83, 0xFB, 0x01});
49 if (index != -1) {
50 shuffle_integers = i + index;
51 AdjustRng(shuffle_integers + 0x23);
52 }
53 }
54 if (cut_random_edges == -1) {
55 int index = find(data, {0x8B, 0x80, 0xBC, 0x03, 0x00, 0x00, 0x89, 0x44, 0x24, 0x3C, 0x33, 0xC0});
56 if (index != -1) {
57 cut_random_edges = i + index - 0x1C;
58 AdjustRng(cut_random_edges + 0x5D);
59 }
60 }
61 if (get_empty_decoration_slot == -1) {
62 int index = find(data, {0x57, 0x48, 0x83, 0xEC, 0x20, 0x8B, 0xB9, 0x38, 0x04});
63 if (index != -1) {
64 get_empty_decoration_slot = i + index - 0x5;
65 AdjustRng(get_empty_decoration_slot + 0x16);
66 }
67 }
68 if (get_empty_dot_spot == -1) {
69 int index = find(data, {0xF7, 0xF3, 0x85, 0xD2, 0x74, 0xEC});
70 if (index != -1) {
71 get_empty_dot_spot = i + index - 0x2E;
72 AdjustRng(get_empty_dot_spot + 0x23);
73 }
74 }
75 if (add_exactly_this_many_bisection_dots == -1) {
76 int index = find(data, {0x48, 0x8B, 0xB4, 0x24, 0xB8, 0x00, 0x00, 0x00, 0x48, 0x8B, 0xBC, 0x24, 0xB0, 0x00, 0x00, 0x00});
77 if (index != -1) {
78 add_exactly_this_many_bisection_dots = i + index - 0x20;
79 AdjustRng(add_exactly_this_many_bisection_dots + 0x1C);
80 }
81 }
82 if (make_a_shaper == -1) {
83 int index = find(data, {0xF7, 0xE3, 0xD1, 0xEA, 0x8D, 0x0C, 0x52});
84 if (index != -1) {
85 make_a_shaper = i + index - 0x19;
86 AdjustRng(make_a_shaper + 0x9);
87 AdjustRng(make_a_shaper + 0x35);
88 AdjustRng(make_a_shaper + 0x62);
89 }
90 }
91 if (/*Entity_Machine_Panel::*/init_pattern_data_lotus == -1) {
92 int index = find(data, {0x40, 0x55, 0x56, 0x48, 0x8D, 0x6C, 0x24, 0xB1});
93 if (index != -1) {
94 init_pattern_data_lotus = i + index;
95 AdjustRng(init_pattern_data_lotus + 0x433);
96 AdjustRng(init_pattern_data_lotus + 0x45B);
97 AdjustRng(init_pattern_data_lotus + 0x5A7);
98 AdjustRng(init_pattern_data_lotus + 0x5D6);
99 AdjustRng(init_pattern_data_lotus + 0x6F6);
100 AdjustRng(init_pattern_data_lotus + 0xD17);
101 AdjustRng(init_pattern_data_lotus + 0xFDA);
102 }
103 }
104 if (/*Entity_Record_Player::*/reroll_lotus_eater_stuff == -1) {
105 int index = find(data, {0xB8, 0xAB, 0xAA, 0xAA, 0xAA, 0x41, 0xC1, 0xE8});
106 if (index != -1) {
107 reroll_lotus_eater_stuff = i + index - 0x37;
108 AdjustRng(reroll_lotus_eater_stuff + 0x24);
109 AdjustRng(reroll_lotus_eater_stuff + 0x6B);
110 }
111 }
112 // These disable the random locations on timer panels, which would otherwise increment the RNG.
113 if (do_lotus_minutes == -1) {
114 int index = find(data, {0x0F, 0xBE, 0x6C, 0x08, 0xFF, 0x45});
115 if (index != -1) {
116 do_lotus_minutes = i + index - 0x2B;
117 _memory->WriteData<byte>({do_lotus_minutes + 0x43B}, {0x31, 0xC0, 0x90, 0x90, 0x90}); // xor eax, eax ;RNG returns 0
118 _memory->WriteData<byte>({do_lotus_minutes + 0x5B3}, {0x31, 0xC0, 0x90, 0x90, 0x90}); // xor eax, eax ;RNG returns 0
119 }
120 }
121 if (do_lotus_eighths == -1) {
122 int index = find(data, {0x75, 0xF5, 0x0F, 0xBE, 0x44, 0x08, 0xFF});
123 if (index != -1) {
124 do_lotus_eighths = i + index - 0x39;
125 _memory->WriteData<byte>({do_lotus_eighths + 0x1E7}, {0x31, 0xC0, 0x90, 0x90, 0x90}); // xor eax, eax ;RNG returns 0
126 }
127 }
128 // This injection ensures that the seed is set every time the challenge is started.
129 if (do_success_side_effects == -1) {
130 int index = find(data, {0x85, 0xC0, 0x7E, 0x2C, 0x48, 0x6B, 0xC8, 0x34});
131 if (index != -1) {
132 do_success_side_effects = i + index;
133 _memory->WriteData<byte>({do_success_side_effects}, {
134 0x8B, 0x0D, 0x00, 0x00, 0x00, 0x00, // mov ecx, [] ;This is going to be the address of the custom RNG
135 0x67, 0xC7, 0x01, 0x00, 0x00, 0x00, 0x00, // mov dword ptr ds:[ecx], 0x0 ;This is going to be the seed value
136 0x48, 0x83, 0xF8, 0x02, // cmp rax, 0x2 ;This is the short solve on the record player (which turns it off)
137 0x90, 0x90, 0x90 // nop nop nop
138 });
139 int target = (GLOBALS + 0x30) - (do_success_side_effects + 0x6); // +6 is for the length of the line
140 _memory->WriteData<int>({do_success_side_effects + 0x2}, {target});
141 _memory->WriteData<int>({do_success_side_effects + 0x9}, {seed});
142 }
143 }
144 }
145}
diff --git a/Source/ChallengeRandomizer.h b/Source/ChallengeRandomizer.h new file mode 100644 index 0000000..267c5cb --- /dev/null +++ b/Source/ChallengeRandomizer.h
@@ -0,0 +1,12 @@
1#pragma once
2#include "Memory.h"
3#include <memory>
4
5class ChallengeRandomizer {
6public:
7 ChallengeRandomizer(const std::shared_ptr<Memory>& memory, int seed);
8
9private:
10 void AdjustRng(int offset);
11 std::shared_ptr<Memory> _memory;
12};
diff --git a/Source/Memory.h b/Source/Memory.h index 23f6388..278ce36 100644 --- a/Source/Memory.h +++ b/Source/Memory.h
@@ -3,8 +3,8 @@
3#include <map> 3#include <map>
4#include <windows.h> 4#include <windows.h>
5 5
6// #define GLOBALS 0x5B28C0 6#define GLOBALS 0x5B28C0
7#define GLOBALS 0x62A080 7// #define GLOBALS 0x62A080
8 8
9// https://github.com/erayarslan/WriteProcessMemory-Example 9// https://github.com/erayarslan/WriteProcessMemory-Example
10// http://stackoverflow.com/q/32798185 10// http://stackoverflow.com/q/32798185
@@ -77,4 +77,5 @@ private:
77 HANDLE _handle = nullptr; 77 HANDLE _handle = nullptr;
78 78
79 friend class Temp; 79 friend class Temp;
80 friend class ChallengeRandomizer;
80}; \ No newline at end of file 81}; \ No newline at end of file
diff --git a/Source/Randomizer.cpp b/Source/Randomizer.cpp index 1f2c0cc..2f3e72a 100644 --- a/Source/Randomizer.cpp +++ b/Source/Randomizer.cpp
@@ -13,7 +13,6 @@
13 * Swap sounds in jungle (along with panels) -- maybe impossible 13 * Swap sounds in jungle (along with panels) -- maybe impossible
14 * Make orange 7 (all of oranges?) hard. Like big = hard. (See: HARD_MODE) 14 * Make orange 7 (all of oranges?) hard. Like big = hard. (See: HARD_MODE)
15 * Add a setting for "disable wonkavator and hotel", so that 100% runs are possible 15 * Add a setting for "disable wonkavator and hotel", so that 100% runs are possible
16 * Try to stabilize challenge/doors RNG
17 * I probably can randomize targets in bunker UV 16 * I probably can randomize targets in bunker UV
18 * Random *rotation* of desert laser redirect? 17 * Random *rotation* of desert laser redirect?
19 * Add setting to disable laser randomization 18 * Add setting to disable laser randomization
@@ -23,6 +22,7 @@
23*/ 22*/
24#include "Memory.h" 23#include "Memory.h"
25#include "Randomizer.h" 24#include "Randomizer.h"
25#include "ChallengeRandomizer.h"
26#include "Panels.h" 26#include "Panels.h"
27#include "Random.h" 27#include "Random.h"
28#include <string> 28#include <string>
@@ -54,6 +54,9 @@ void Randomizer::Randomize()
54 if (GameIsRandomized()) return; // Nice sanity check, but should be unnecessary (since Main checks anyways) 54 if (GameIsRandomized()) return; // Nice sanity check, but should be unnecessary (since Main checks anyways)
55 _lastRandomizedFrame = _memory->GetCurrentFrame(); 55 _lastRandomizedFrame = _memory->GetCurrentFrame();
56 56
57 // Seed challenge first for future-proofing (?)
58 RandomizeChallenge();
59
57 // Content swaps -- must happen before squarePanels 60 // Content swaps -- must happen before squarePanels
58 Randomize(upDownPanels, SWAP::LINES); 61 Randomize(upDownPanels, SWAP::LINES);
59 Randomize(leftForwardRightPanels, SWAP::LINES); 62 Randomize(leftForwardRightPanels, SWAP::LINES);
@@ -74,7 +77,6 @@ void Randomizer::Randomize()
74 RandomizeJungle(); 77 RandomizeJungle();
75 RandomizeSwamp(); 78 RandomizeSwamp();
76 RandomizeMountain(); 79 RandomizeMountain();
77 // RandomizeChallenge();
78 // RandomizeAudioLogs(); 80 // RandomizeAudioLogs();
79} 81}
80 82
@@ -215,16 +217,7 @@ void Randomizer::RandomizeMountain() {
215} 217}
216 218
217void Randomizer::RandomizeChallenge() { 219void Randomizer::RandomizeChallenge() {
218 std::vector<int> randomOrder(challengePanels.size(), 0); 220 ChallengeRandomizer cr(_memory, Random::RandInt(1, 0x1000));
219 std::iota(randomOrder.begin(), randomOrder.end(), 0);
220 RandomizeRange(randomOrder, SWAP::NONE, 1, 9); // Easy maze - Triple 2
221 std::vector<int> triple1Target = _memory->ReadPanelData<int>(0x00C80, TARGET, 1);
222 _memory->WritePanelData<int>(0x00CA1, TARGET, triple1Target);
223 _memory->WritePanelData<int>(0x00CB9, TARGET, triple1Target);
224 std::vector<int> triple2Target = _memory->ReadPanelData<int>(0x00C22, TARGET, 1);
225 _memory->WritePanelData<int>(0x00C59, TARGET, triple2Target);
226 _memory->WritePanelData<int>(0x00C68, TARGET, triple2Target);
227 ReassignTargets(challengePanels, randomOrder);
228} 221}
229 222
230void Randomizer::RandomizeAudioLogs() { 223void Randomizer::RandomizeAudioLogs() {
diff --git a/Source/Source.vcxproj b/Source/Source.vcxproj index 85ce6e1..cf6756a 100644 --- a/Source/Source.vcxproj +++ b/Source/Source.vcxproj
@@ -157,6 +157,7 @@
157 </Link> 157 </Link>
158 </ItemDefinitionGroup> 158 </ItemDefinitionGroup>
159 <ItemGroup> 159 <ItemGroup>
160 <ClInclude Include="ChallengeRandomizer.h" />
160 <ClInclude Include="json.hpp" /> 161 <ClInclude Include="json.hpp" />
161 <ClInclude Include="Memory.h" /> 162 <ClInclude Include="Memory.h" />
162 <ClInclude Include="Panel.h" /> 163 <ClInclude Include="Panel.h" />
@@ -165,6 +166,7 @@
165 <ClInclude Include="Randomizer.h" /> 166 <ClInclude Include="Randomizer.h" />
166 </ItemGroup> 167 </ItemGroup>
167 <ItemGroup> 168 <ItemGroup>
169 <ClCompile Include="ChallengeRandomizer.cpp" />
168 <ClCompile Include="Memory.cpp" /> 170 <ClCompile Include="Memory.cpp" />
169 <ClCompile Include="Panel.cpp" /> 171 <ClCompile Include="Panel.cpp" />
170 <ClCompile Include="Random.cpp" /> 172 <ClCompile Include="Random.cpp" />
diff --git a/Test/Temp.cpp b/Test/Temp.cpp index 6ccaeff..6a45140 100644 --- a/Test/Temp.cpp +++ b/Test/Temp.cpp
@@ -32,6 +32,7 @@ TEST(SwapTests, Shipwreck) {
32 32
33} 33}
34 34
35/*
35TEST_F(Temp, Extract) { 36TEST_F(Temp, Extract) {
36// std::vector<byte> data = ReadSubtitles(166480); 37// std::vector<byte> data = ReadSubtitles(166480);
37 std::vector<char> data = ReadSubtitles(166480); 38 std::vector<char> data = ReadSubtitles(166480);
@@ -45,4 +46,5 @@ TEST_F(Temp, Extract) {
45 46
46 } 47 }
47 file.close(); 48 file.close();
48} \ No newline at end of file 49}
50*/ \ No newline at end of file