summary refs log tree commit diff stats
path: root/Source
diff options
context:
space:
mode:
authorjbzdarkid <jbzdarkid@gmail.com>2019-11-16 21:15:59 -0800
committerjbzdarkid <jbzdarkid@gmail.com>2019-11-16 21:15:59 -0800
commitfd2fa2211dc09c9030601fde1afd2f7823b22ed8 (patch)
treedfd3d3195315b69e5ccb397f7aedde115fb7e6e6 /Source
parentee426c3bde4b4c7fb1ea38a953d849e8893d8311 (diff)
downloadwitness-tutorializer-fd2fa2211dc09c9030601fde1afd2f7823b22ed8.tar.gz
witness-tutorializer-fd2fa2211dc09c9030601fde1afd2f7823b22ed8.tar.bz2
witness-tutorializer-fd2fa2211dc09c9030601fde1afd2f7823b22ed8.zip
Cleanup tabs -> spaces, actually free memory
Diffstat (limited to 'Source')
-rw-r--r--Source/Memory.cpp9
-rw-r--r--Source/Memory.h132
-rw-r--r--Source/PuzzlerSerializer.cpp280
-rw-r--r--Source/Randomizer.cpp80
-rw-r--r--Source/Randomizer2.cpp41
5 files changed, 256 insertions, 286 deletions
diff --git a/Source/Memory.cpp b/Source/Memory.cpp index e240b90..d90c402 100644 --- a/Source/Memory.cpp +++ b/Source/Memory.cpp
@@ -8,16 +8,17 @@
8#undef PROCESSENTRY32 8#undef PROCESSENTRY32
9#undef Process32Next 9#undef Process32Next
10 10
11Memory::Memory(const std::wstring& processName) : _processName(processName) { 11Memory::Memory(const std::wstring& processName) : _processName(processName) {}
12}
13 12
14Memory::~Memory() { 13Memory::~Memory() {
15 if (_threadActive) { 14 if (_threadActive) {
16 _threadActive = false; 15 _threadActive = false;
17 _thread.join(); 16 _thread.join();
18 } 17 }
18
19 if (_handle != nullptr) { 19 if (_handle != nullptr) {
20 CloseHandle(_handle); 20 for (uintptr_t addr : _allocations) VirtualFreeEx(_handle, (void*)addr, 0, MEM_RELEASE);
21 CloseHandle(_handle);
21 } 22 }
22} 23}
23 24
@@ -133,7 +134,7 @@ int Memory::ExecuteSigScans()
133{ 134{
134 for (int i=0; i<0x200000; i+=0x1000) { 135 for (int i=0; i<0x200000; i+=0x1000) {
135 std::vector<byte> data = ReadData<byte>({i}, 0x1100); 136 std::vector<byte> data = ReadData<byte>({i}, 0x1100);
136 137
137 for (auto& [scanBytes, sigScan] : _sigScans) { 138 for (auto& [scanBytes, sigScan] : _sigScans) {
138 if (sigScan.found) continue; 139 if (sigScan.found) continue;
139 int index = find(data, scanBytes); 140 int index = find(data, scanBytes);
diff --git a/Source/Memory.h b/Source/Memory.h index af4f0ae..70a271e 100644 --- a/Source/Memory.h +++ b/Source/Memory.h
@@ -19,103 +19,103 @@ enum class ProcStatus {
19// http://stackoverflow.com/q/32798185 19// http://stackoverflow.com/q/32798185
20// http://stackoverflow.com/q/36018838 20// http://stackoverflow.com/q/36018838
21// http://stackoverflow.com/q/1387064 21// http://stackoverflow.com/q/1387064
22// https://github.com/fkloiber/witness-trainer/blob/master/source/foreign_process_memory.cpp
22class Memory final : public std::enable_shared_from_this<Memory> { 23class Memory final : public std::enable_shared_from_this<Memory> {
23public: 24public:
24 Memory(const std::wstring& processName); 25 Memory(const std::wstring& processName);
25 ~Memory(); 26 ~Memory();
26 void StartHeartbeat(HWND window, std::chrono::milliseconds beat = std::chrono::milliseconds(1000)); 27 void StartHeartbeat(HWND window, std::chrono::milliseconds beat = std::chrono::milliseconds(1000));
27 28
28 Memory(const Memory& memory) = delete; 29 Memory(const Memory& memory) = delete;
29 Memory& operator=(const Memory& other) = delete; 30 Memory& operator=(const Memory& other) = delete;
30 31
31 template <class T> 32 template <class T>
32 std::vector<T> ReadArray(int panel, int offset, int size) { 33 std::vector<T> ReadArray(int id, int offset, int size) {
33 return ReadData<T>({GLOBALS, 0x18, panel*8, offset, 0}, size); 34 return ReadData<T>({GLOBALS, 0x18, id*8, offset, 0}, size);
34 } 35 }
35 36
36 template <class T> 37 template <class T>
37 void WriteArray(int panel, int offset, const std::vector<T>& data) { 38 void WriteArray(int id, int offset, const std::vector<T>& data) {
38 WriteData({GLOBALS, 0x18, panel*8, offset, 0}, data); 39 WriteData({GLOBALS, 0x18, id*8, offset, 0}, data);
39 } 40 }
40 41
41 template <class T> 42 template <class T>
42 void WriteNewArray(int panel, int offset, const std::vector<T>& data) { 43 void WriteNewArray(int id, int offset, const std::vector<T>& data) {
43 std::vector<uintptr_t> newAddr = {Allocate(data.size() * sizeof(T))}; 44 uintptr_t addr = VirtualAllocEx(_handle, nullptr, data.size() * sizeof(T), MEM_RESERVE | MEM_COMMIT, MEM_READWRITE);
44 WritePanelData(panel, offset, newAddr); 45 _allocations.emplace_back(addr);
45 WriteArray(panel, offset, data); 46 WriteEntityData(id, offset, addr);
46 } 47 WriteArray(id, offset, data);
48 }
47 49
48 template <class T> 50 template <class T>
49 std::vector<T> ReadPanelData(int panel, int offset, size_t size) { 51 std::vector<T> ReadEntityData(int id, int offset, size_t size) {
50 return ReadData<T>({GLOBALS, 0x18, panel*8, offset}, size); 52 return ReadData<T>({GLOBALS, 0x18, id*8, offset}, size);
51 } 53 }
52 54
53 template <class T> 55 template <class T>
54 void WritePanelData(int panel, int offset, const std::vector<T>& data) { 56 void WriteEntityData(int id, int offset, const std::vector<T>& data) {
55 WriteData({GLOBALS, 0x18, panel*8, offset}, data); 57 WriteData({GLOBALS, 0x18, id*8, offset}, data);
56 } 58 }
57 59
58 void AddSigScan(const std::vector<byte>& scanBytes, const std::function<void(int index)>& scanFunc); 60 void AddSigScan(const std::vector<byte>& scanBytes, const std::function<void(int index)>& scanFunc);
59 int ExecuteSigScans(); 61 int ExecuteSigScans();
60 62
61private: 63private:
62 template<class T> 64 template<class T>
63 std::vector<T> ReadData(const std::vector<int>& offsets, size_t numItems) { 65 std::vector<T> ReadData(const std::vector<int>& offsets, size_t numItems) {
64 if (numItems == 0) return {}; 66 if (numItems == 0) return {};
65 std::vector<T> data; 67 std::vector<T> data;
66 data.resize(numItems); 68 data.resize(numItems);
67 void* computedOffset = ComputeOffset(offsets); 69 void* computedOffset = ComputeOffset(offsets);
68 for (int i=0; i<5; i++) { 70 for (int i=0; i<5; i++) {
69 if (ReadProcessMemory(_handle, computedOffset, &data[0], sizeof(T) * numItems, nullptr)) { 71 if (ReadProcessMemory(_handle, computedOffset, &data[0], sizeof(T) * numItems, nullptr)) {
70 if (i != 0) { 72 if (i != 0) {
71 int k = 0; 73 int k = 0;
72 } 74 }
73 return data; 75 return data;
74 } 76 }
75 } 77 }
76 ThrowError(); 78 ThrowError();
77 return {}; 79 return {};
78 } 80 }
79 81
80 template <class T> 82 template <class T>
81 void WriteData(const std::vector<int>& offsets, const std::vector<T>& data) { 83 void WriteData(const std::vector<int>& offsets, const std::vector<T>& data) {
82 if (data.empty()) return; 84 if (data.empty()) return;
83 void* computedOffset = ComputeOffset(offsets); 85 void* computedOffset = ComputeOffset(offsets);
84 for (int i=0; i<5; i++) { 86 for (int i=0; i<5; i++) {
85 if (WriteProcessMemory(_handle, computedOffset, &data[0], sizeof(T) * data.size(), nullptr)) { 87 if (WriteProcessMemory(_handle, computedOffset, &data[0], sizeof(T) * data.size(), nullptr)) {
86 if (i != 0) { 88 if (i != 0) {
87 int k = 0; 89 int k = 0;
88 } 90 }
89 return; 91 return;
90 } 92 }
91 } 93 }
92 ThrowError(); 94 ThrowError();
93 } 95 }
94 96
95 void Heartbeat(HWND window); 97 void Heartbeat(HWND window);
96 bool Initialize(); 98 bool Initialize();
97 void ThrowError(); 99 void ThrowError();
98 void* ComputeOffset(std::vector<int> offsets); 100 void* ComputeOffset(std::vector<int> offsets);
99 uintptr_t Allocate(size_t bytes);
100 101
101 int _previousFrame = 0; 102 int _previousFrame = 0;
102 bool _threadActive = false; 103 bool _threadActive = false;
103 std::thread _thread; 104 std::thread _thread;
104 std::wstring _processName; 105 std::wstring _processName;
105 std::map<uintptr_t, uintptr_t> _computedAddresses; 106 std::map<uintptr_t, uintptr_t> _computedAddresses;
106 uintptr_t _baseAddress = 0; 107 uintptr_t _baseAddress = 0;
107 HANDLE _handle = nullptr; 108 HANDLE _handle = nullptr;
108 uintptr_t _freeMem = 0; 109 std::vector<uintptr_t> _allocations;
109 uintptr_t _freeMemEnd = 0; 110 struct SigScan {
110 struct SigScan { 111 std::function<void(int)> scanFunc;
111 std::function<void(int)> scanFunc; 112 bool found;
112 bool found; 113 };
113 }; 114 std::map<std::vector<byte>, SigScan> _sigScans;
114 std::map<std::vector<byte>, SigScan> _sigScans;
115 115
116 friend class Temp; 116 friend class Temp;
117 friend class ChallengeRandomizer; 117 friend class ChallengeRandomizer;
118 friend class Randomizer; 118 friend class Randomizer;
119}; 119};
120 120
121#if GLOBALS == 0x5B28C0 121#if GLOBALS == 0x5B28C0
diff --git a/Source/PuzzlerSerializer.cpp b/Source/PuzzlerSerializer.cpp index abdfafd..2ba0ce7 100644 --- a/Source/PuzzlerSerializer.cpp +++ b/Source/PuzzlerSerializer.cpp
@@ -7,22 +7,22 @@
7PuzzleSerializer::PuzzleSerializer(const std::shared_ptr<Memory>& memory) : _memory(memory) {} 7PuzzleSerializer::PuzzleSerializer(const std::shared_ptr<Memory>& memory) : _memory(memory) {}
8 8
9Puzzle PuzzleSerializer::ReadPuzzle(int id) { 9Puzzle PuzzleSerializer::ReadPuzzle(int id) {
10 int width = 2 * _memory->ReadPanelData<int>(id, GRID_SIZE_X, 1)[0] - 1; 10 int width = 2 * _memory->ReadEntityData<int>(id, GRID_SIZE_X, 1)[0] - 1;
11 int height = 2 * _memory->ReadPanelData<int>(id, GRID_SIZE_Y, 1)[0] - 1; 11 int height = 2 * _memory->ReadEntityData<int>(id, GRID_SIZE_Y, 1)[0] - 1;
12 if (width < 0 || height < 0) return Puzzle(); // @Error: Grid size should be always positive? Looks like the starting panels break this rule, though. 12 if (width < 0 || height < 0) return Puzzle(); // @Error: Grid size should be always positive? Looks like the starting panels break this rule, though.
13 13
14 int numIntersections = _memory->ReadPanelData<int>(id, NUM_DOTS, 1)[0]; 14 int numIntersections = _memory->ReadEntityData<int>(id, NUM_DOTS, 1)[0];
15 _intersectionFlags = _memory->ReadArray<int>(id, DOT_FLAGS, numIntersections); 15 _intersectionFlags = _memory->ReadArray<int>(id, DOT_FLAGS, numIntersections);
16 int numConnections = _memory->ReadPanelData<int>(id, NUM_CONNECTIONS, 1)[0]; 16 int numConnections = _memory->ReadEntityData<int>(id, NUM_CONNECTIONS, 1)[0];
17 _connectionsA = _memory->ReadArray<int>(id, DOT_CONNECTION_A, numConnections); 17 _connectionsA = _memory->ReadArray<int>(id, DOT_CONNECTION_A, numConnections);
18 _connectionsB = _memory->ReadArray<int>(id, DOT_CONNECTION_B, numConnections); 18 _connectionsB = _memory->ReadArray<int>(id, DOT_CONNECTION_B, numConnections);
19 _intersectionLocations = _memory->ReadArray<float>(id, DOT_POSITIONS, numIntersections*2); 19 _intersectionLocations = _memory->ReadArray<float>(id, DOT_POSITIONS, numIntersections*2);
20 20
21 Puzzle p; 21 Puzzle p;
22 p.NewGrid(width, height); 22 p.NewGrid(width, height);
23 ReadIntersections(p); 23 ReadIntersections(p);
24 ReadExtras(p); 24 ReadExtras(p);
25 ReadDecorations(p, id); 25 ReadDecorations(p, id);
26 ReadSequence(p, id); 26 ReadSequence(p, id);
27 return p; 27 return p;
28} 28}
@@ -34,28 +34,28 @@ void PuzzleSerializer::WritePuzzle(const Puzzle& p, int id) {
34 _intersectionLocations.clear(); 34 _intersectionLocations.clear();
35 35
36 MIN = 0.1f; 36 MIN = 0.1f;
37 MAX = 0.9f; 37 MAX = 0.9f;
38 WIDTH_INTERVAL = (MAX - MIN) / (p.width/2); 38 WIDTH_INTERVAL = (MAX - MIN) / (p.width/2);
39 HEIGHT_INTERVAL = (MAX - MIN) / (p.height/2); 39 HEIGHT_INTERVAL = (MAX - MIN) / (p.height/2);
40 HORIZ_GAP_SIZE = WIDTH_INTERVAL / 2; 40 HORIZ_GAP_SIZE = WIDTH_INTERVAL / 2;
41 VERTI_GAP_SIZE = HEIGHT_INTERVAL / 2; 41 VERTI_GAP_SIZE = HEIGHT_INTERVAL / 2;
42 42
43 WriteIntersections(p); 43 WriteIntersections(p);
44 WriteDots(p); 44 WriteDots(p);
45 WriteGaps(p); 45 WriteGaps(p);
46 WriteEndpoints(p); 46 WriteEndpoints(p);
47 WriteDecorations(p, id); 47 WriteDecorations(p, id);
48 WriteSequence(p, id); 48 WriteSequence(p, id);
49 49
50 _memory->WritePanelData<int>(id, GRID_SIZE_X, {(p.width + 1)/2}); 50 _memory->WriteEntityData<int>(id, GRID_SIZE_X, {(p.width + 1)/2});
51 _memory->WritePanelData<int>(id, GRID_SIZE_Y, {(p.height + 1)/2}); 51 _memory->WriteEntityData<int>(id, GRID_SIZE_Y, {(p.height + 1)/2});
52 _memory->WritePanelData<int>(id, NUM_DOTS, {static_cast<int>(_intersectionFlags.size())}); 52 _memory->WriteEntityData<int>(id, NUM_DOTS, {static_cast<int>(_intersectionFlags.size())});
53 _memory->WriteArray<float>(id, DOT_POSITIONS, _intersectionLocations); 53 _memory->WriteArray<float>(id, DOT_POSITIONS, _intersectionLocations);
54 _memory->WriteArray<int>(id, DOT_FLAGS, _intersectionFlags); 54 _memory->WriteArray<int>(id, DOT_FLAGS, _intersectionFlags);
55 _memory->WritePanelData<int>(id, NUM_CONNECTIONS, {static_cast<int>(_connectionsA.size())}); 55 _memory->WriteEntityData<int>(id, NUM_CONNECTIONS, {static_cast<int>(_connectionsA.size())});
56 _memory->WriteArray<int>(id, DOT_CONNECTION_A, _connectionsA); 56 _memory->WriteArray<int>(id, DOT_CONNECTION_A, _connectionsA);
57 _memory->WriteArray<int>(id, DOT_CONNECTION_B, _connectionsB); 57 _memory->WriteArray<int>(id, DOT_CONNECTION_B, _connectionsB);
58 _memory->WritePanelData<int>(id, NEEDS_REDRAW, {1}); 58 _memory->WriteEntityData<int>(id, NEEDS_REDRAW, {1});
59} 59}
60 60
61void PuzzleSerializer::ReadIntersections(Puzzle& p) { 61void PuzzleSerializer::ReadIntersections(Puzzle& p) {
@@ -70,78 +70,78 @@ void PuzzleSerializer::ReadIntersections(Puzzle& p) {
70 for (int j=0; j<_intersectionFlags.size(); j++) { 70 for (int j=0; j<_intersectionFlags.size(); j++) {
71 if (_intersectionFlags[_connectionsA[j]] & Flags::IS_ENDPOINT) break; 71 if (_intersectionFlags[_connectionsA[j]] & Flags::IS_ENDPOINT) break;
72 if (_intersectionFlags[_connectionsB[j]] & Flags::IS_ENDPOINT) break; 72 if (_intersectionFlags[_connectionsB[j]] & Flags::IS_ENDPOINT) break;
73 float x1 = _intersectionLocations[2*_connectionsA[j]]; 73 float x1 = _intersectionLocations[2*_connectionsA[j]];
74 float y1 = _intersectionLocations[2*_connectionsA[j]+1]; 74 float y1 = _intersectionLocations[2*_connectionsA[j]+1];
75 float x2 = _intersectionLocations[2*_connectionsB[j]]; 75 float x2 = _intersectionLocations[2*_connectionsB[j]];
76 float y2 = _intersectionLocations[2*_connectionsB[j]+1]; 76 float y2 = _intersectionLocations[2*_connectionsB[j]+1];
77 auto [x, y] = loc_to_xy(p, _connectionsA[j]); 77 auto [x, y] = loc_to_xy(p, _connectionsA[j]);
78 78
79 if (x1 < x2) x++; 79 if (x1 < x2) x++;
80 else if (x1 > x2) x--; 80 else if (x1 > x2) x--;
81 else if (y1 < y2) y--; 81 else if (y1 < y2) y--;
82 else if (y1 > y2) y++; 82 else if (y1 > y2) y++;
83 p.grid[x][y].gap = Cell::Gap::NONE; 83 p.grid[x][y].gap = Cell::Gap::NONE;
84 } 84 }
85} 85}
86 86
87void PuzzleSerializer::ReadExtras(Puzzle& p) { 87void PuzzleSerializer::ReadExtras(Puzzle& p) {
88 // This iterates bottom-top, left-right 88 // This iterates bottom-top, left-right
89 int i = 0; 89 int i = 0;
90 for (; i < _intersectionFlags.size(); i++) { 90 for (; i < _intersectionFlags.size(); i++) {
91 int flags = _intersectionFlags[i]; 91 int flags = _intersectionFlags[i];
92 auto [x, y] = loc_to_xy(p, i); 92 auto [x, y] = loc_to_xy(p, i);
93 if (y < 0) break; // This is the expected exit point 93 if (y < 0) break; // This is the expected exit point
94 if (flags & Flags::IS_STARTPOINT) { 94 if (flags & Flags::IS_STARTPOINT) {
95 p.grid[x][y].start = true; 95 p.grid[x][y].start = true;
96 } 96 }
97 p.grid[x][y].dot = FlagsToDot(flags); 97 p.grid[x][y].dot = FlagsToDot(flags);
98 if (flags & Flags::HAS_NO_CONN) { 98 if (flags & Flags::HAS_NO_CONN) {
99 p.grid[x][y].gap = Cell::Gap::FULL; 99 p.grid[x][y].gap = Cell::Gap::FULL;
100 } 100 }
101 } 101 }
102 102
103 // Iterate the remaining intersections (endpoints, dots, gaps) 103 // Iterate the remaining intersections (endpoints, dots, gaps)
104 for (; i < _intersectionFlags.size(); i++) { 104 for (; i < _intersectionFlags.size(); i++) {
105 int location = FindConnection(i); 105 int location = FindConnection(i);
106 if (location == -1) continue; // @Error: Unable to find connection point 106 if (location == -1) continue; // @Error: Unable to find connection point
107 // (x1, y1) location of this intersection 107 // (x1, y1) location of this intersection
108 // (x2, y2) location of the connected intersection 108 // (x2, y2) location of the connected intersection
109 float x1 = _intersectionLocations[2*i]; 109 float x1 = _intersectionLocations[2*i];
110 float y1 = _intersectionLocations[2*i+1]; 110 float y1 = _intersectionLocations[2*i+1];
111 float x2 = _intersectionLocations[2*location]; 111 float x2 = _intersectionLocations[2*location];
112 float y2 = _intersectionLocations[2*location+1]; 112 float y2 = _intersectionLocations[2*location+1];
113 auto [x, y] = loc_to_xy(p, location); 113 auto [x, y] = loc_to_xy(p, location);
114 114
115 if (_intersectionFlags[i] & Flags::IS_ENDPOINT) { 115 if (_intersectionFlags[i] & Flags::IS_ENDPOINT) {
116 // Our x coordinate is less than the target's 116 // Our x coordinate is less than the target's
117 if (x1 < x2) p.grid[x][y].end = Cell::Dir::LEFT; 117 if (x1 < x2) p.grid[x][y].end = Cell::Dir::LEFT;
118 else if (x1 > x2) p.grid[x][y].end = Cell::Dir::RIGHT; 118 else if (x1 > x2) p.grid[x][y].end = Cell::Dir::RIGHT;
119 // Note that Y coordinates are reversed: 0.0 (bottom) 1.0 (top) 119 // Note that Y coordinates are reversed: 0.0 (bottom) 1.0 (top)
120 else if (y1 < y2) p.grid[x][y].end = Cell::Dir::DOWN; 120 else if (y1 < y2) p.grid[x][y].end = Cell::Dir::DOWN;
121 else if (y1 > y2) p.grid[x][y].end = Cell::Dir::UP; 121 else if (y1 > y2) p.grid[x][y].end = Cell::Dir::UP;
122 } else if (_intersectionFlags[i] & Flags::HAS_DOT) { 122 } else if (_intersectionFlags[i] & Flags::HAS_DOT) {
123 if (x1 < x2) x--; 123 if (x1 < x2) x--;
124 else if (x1 > x2) x++; 124 else if (x1 > x2) x++;
125 else if (y1 < y2) y++; 125 else if (y1 < y2) y++;
126 else if (y1 > y2) y--; 126 else if (y1 > y2) y--;
127 p.grid[x][y].dot = FlagsToDot(_intersectionFlags[i]); 127 p.grid[x][y].dot = FlagsToDot(_intersectionFlags[i]);
128 } else if (_intersectionFlags[i] & Flags::HAS_ONE_CONN) { 128 } else if (_intersectionFlags[i] & Flags::HAS_ONE_CONN) {
129 if (x1 < x2) x--; 129 if (x1 < x2) x--;
130 else if (x1 > x2) x++; 130 else if (x1 > x2) x++;
131 else if (y1 < y2) y++; 131 else if (y1 < y2) y++;
132 else if (y1 > y2) y--; 132 else if (y1 > y2) y--;
133 p.grid[x][y].gap = Cell::Gap::BREAK; 133 p.grid[x][y].gap = Cell::Gap::BREAK;
134 } 134 }
135 } 135 }
136} 136}
137 137
138void PuzzleSerializer::ReadDecorations(Puzzle& p, int id) { 138void PuzzleSerializer::ReadDecorations(Puzzle& p, int id) {
139 int numDecorations = _memory->ReadPanelData<int>(id, NUM_DECORATIONS, 1)[0]; 139 int numDecorations = _memory->ReadEntityData<int>(id, NUM_DECORATIONS, 1)[0];
140 std::vector<int> decorations = _memory->ReadArray<int>(id, DECORATIONS, numDecorations); 140 std::vector<int> decorations = _memory->ReadArray<int>(id, DECORATIONS, numDecorations);
141 if (numDecorations > 0) p.hasDecorations = true; 141 if (numDecorations > 0) p.hasDecorations = true;
142 142
143 for (int i=0; i<numDecorations; i++) { 143 for (int i=0; i<numDecorations; i++) {
144 auto [x, y] = dloc_to_xy(p, i); 144 auto [x, y] = dloc_to_xy(p, i);
145 auto d = std::make_shared<Decoration>(); 145 auto d = std::make_shared<Decoration>();
146 p.grid[x][y].decoration = d; 146 p.grid[x][y].decoration = d;
147 d->type = static_cast<Type>(decorations[i] & 0xFF00); 147 d->type = static_cast<Type>(decorations[i] & 0xFF00);
@@ -156,11 +156,11 @@ void PuzzleSerializer::ReadDecorations(Puzzle& p, int id) {
156 break; 156 break;
157 } 157 }
158 d->color = static_cast<Color>(decorations[i] & 0xF); 158 d->color = static_cast<Color>(decorations[i] & 0xF);
159 } 159 }
160} 160}
161 161
162void PuzzleSerializer::ReadSequence(Puzzle& p, int id) { 162void PuzzleSerializer::ReadSequence(Puzzle& p, int id) {
163 int sequenceLength = _memory->ReadPanelData<int>(id, SEQUENCE_LEN, 1)[0]; 163 int sequenceLength = _memory->ReadEntityData<int>(id, SEQUENCE_LEN, 1)[0];
164 std::vector<int> sequence = _memory->ReadArray<int>(id, SEQUENCE, sequenceLength); 164 std::vector<int> sequence = _memory->ReadArray<int>(id, SEQUENCE, sequenceLength);
165 165
166 for (int location : sequence) { 166 for (int location : sequence) {
@@ -170,15 +170,15 @@ void PuzzleSerializer::ReadSequence(Puzzle& p, int id) {
170} 170}
171 171
172void PuzzleSerializer::WriteIntersections(const Puzzle& p) { 172void PuzzleSerializer::WriteIntersections(const Puzzle& p) {
173 // @Cleanup: If I write directly to locations, then I can simplify this gross loop iterator. 173 // @Cleanup: If I write directly to locations, then I can simplify this gross loop iterator.
174 // int numIntersections = (p.width / 2 + 1) * (p.height / 2 + 1); 174 // int numIntersections = (p.width / 2 + 1) * (p.height / 2 + 1);
175 // Grided intersections 175 // Grided intersections
176 for (int y=p.height-1; y>=0; y-=2) { 176 for (int y=p.height-1; y>=0; y-=2) {
177 for (int x=0; x<p.width; x+=2) { 177 for (int x=0; x<p.width; x+=2) {
178 auto [xPos, yPos] = xy_to_pos(p, x, y); 178 auto [xPos, yPos] = xy_to_pos(p, x, y);
179 _intersectionLocations.push_back(xPos); 179 _intersectionLocations.push_back(xPos);
180 _intersectionLocations.push_back(yPos); 180 _intersectionLocations.push_back(yPos);
181 int flags = 0; 181 int flags = 0;
182 if (p.grid[x][y].start) { 182 if (p.grid[x][y].start) {
183 flags |= Flags::IS_STARTPOINT; 183 flags |= Flags::IS_STARTPOINT;
184 } 184 }
@@ -199,26 +199,26 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p) {
199 199
200 int numConnections = 0; 200 int numConnections = 0;
201 if (p.grid[x][y].end != Cell::Dir::NONE) numConnections++; 201 if (p.grid[x][y].end != Cell::Dir::NONE) numConnections++;
202 // Create connections for this intersection for top/left only. 202 // Create connections for this intersection for top/left only.
203 // Top connection 203 // Top connection
204 if (y > 0 && p.grid[x][y-1].gap != Cell::Gap::FULL) { 204 if (y > 0 && p.grid[x][y-1].gap != Cell::Gap::FULL) {
205 _connectionsA.push_back(xy_to_loc(p, x, y-2)); 205 _connectionsA.push_back(xy_to_loc(p, x, y-2));
206 _connectionsB.push_back(xy_to_loc(p, x, y)); 206 _connectionsB.push_back(xy_to_loc(p, x, y));
207 flags |= Flags::HAS_VERTI_CONN; 207 flags |= Flags::HAS_VERTI_CONN;
208 numConnections++; 208 numConnections++;
209 } 209 }
210 // Bottom connection 210 // Bottom connection
211 if (y < p.height - 1 && p.grid[x][y+1].gap != Cell::Gap::FULL) { 211 if (y < p.height - 1 && p.grid[x][y+1].gap != Cell::Gap::FULL) {
212 flags |= Flags::HAS_VERTI_CONN; 212 flags |= Flags::HAS_VERTI_CONN;
213 numConnections++; 213 numConnections++;
214 } 214 }
215 // Left connection 215 // Left connection
216 if (x > 0 && p.grid[x-1][y].gap != Cell::Gap::FULL) { 216 if (x > 0 && p.grid[x-1][y].gap != Cell::Gap::FULL) {
217 _connectionsA.push_back(xy_to_loc(p, x-2, y)); 217 _connectionsA.push_back(xy_to_loc(p, x-2, y));
218 _connectionsB.push_back(xy_to_loc(p, x, y)); 218 _connectionsB.push_back(xy_to_loc(p, x, y));
219 flags |= Flags::HAS_HORIZ_CONN; 219 flags |= Flags::HAS_HORIZ_CONN;
220 numConnections++; 220 numConnections++;
221 } 221 }
222 // Right connection 222 // Right connection
223 if (x < p.width - 1 && p.grid[x+1][y].gap != Cell::Gap::FULL) { 223 if (x < p.width - 1 && p.grid[x+1][y].gap != Cell::Gap::FULL) {
224 flags |= Flags::HAS_HORIZ_CONN; 224 flags |= Flags::HAS_HORIZ_CONN;
@@ -227,9 +227,9 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p) {
227 if (numConnections == 0) flags |= HAS_NO_CONN; 227 if (numConnections == 0) flags |= HAS_NO_CONN;
228 if (numConnections == 1) flags |= HAS_ONE_CONN; 228 if (numConnections == 1) flags |= HAS_ONE_CONN;
229 229
230 _intersectionFlags.push_back(flags); 230 _intersectionFlags.push_back(flags);
231 } 231 }
232 } 232 }
233} 233}
234 234
235void PuzzleSerializer::WriteEndpoints(const Puzzle& p) { 235void PuzzleSerializer::WriteEndpoints(const Puzzle& p) {
@@ -237,27 +237,27 @@ void PuzzleSerializer::WriteEndpoints(const Puzzle& p) {
237 for (int y=0; y<p.height; y++) { 237 for (int y=0; y<p.height; y++) {
238 if (p.grid[x][y].end == Cell::Dir::NONE) continue; 238 if (p.grid[x][y].end == Cell::Dir::NONE) continue;
239 _connectionsA.push_back(xy_to_loc(p, x, y)); 239 _connectionsA.push_back(xy_to_loc(p, x, y));
240 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); 240 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size()));
241 241
242 auto [xPos, yPos] = xy_to_pos(p, x, y); 242 auto [xPos, yPos] = xy_to_pos(p, x, y);
243 switch (p.grid[x][y].end) { 243 switch (p.grid[x][y].end) {
244 case Cell::Dir::LEFT: 244 case Cell::Dir::LEFT:
245 xPos -= .05f; 245 xPos -= .05f;
246 break; 246 break;
247 case Cell::Dir::RIGHT: 247 case Cell::Dir::RIGHT:
248 xPos += .05f; 248 xPos += .05f;
249 break; 249 break;
250 case Cell::Dir::UP: 250 case Cell::Dir::UP:
251 yPos += .05f; // Y position goes from 0 (bottom) to 1 (top), so this is reversed. 251 yPos += .05f; // Y position goes from 0 (bottom) to 1 (top), so this is reversed.
252 break; 252 break;
253 case Cell::Dir::DOWN: 253 case Cell::Dir::DOWN:
254 yPos -= .05f; 254 yPos -= .05f;
255 break; 255 break;
256 } 256 }
257 _endpointLocations.emplace_back(x, y, static_cast<int>(_intersectionFlags.size())); 257 _endpointLocations.emplace_back(x, y, static_cast<int>(_intersectionFlags.size()));
258 _intersectionLocations.push_back(xPos); 258 _intersectionLocations.push_back(xPos);
259 _intersectionLocations.push_back(yPos); 259 _intersectionLocations.push_back(yPos);
260 _intersectionFlags.push_back(Flags::IS_ENDPOINT); 260 _intersectionFlags.push_back(Flags::IS_ENDPOINT);
261 } 261 }
262 } 262 }
263} 263}
@@ -265,32 +265,32 @@ void PuzzleSerializer::WriteEndpoints(const Puzzle& p) {
265void PuzzleSerializer::WriteDots(const Puzzle& p) { 265void PuzzleSerializer::WriteDots(const Puzzle& p) {
266 for (int x=0; x<p.width; x++) { 266 for (int x=0; x<p.width; x++) {
267 for (int y=0; y<p.height; y++) { 267 for (int y=0; y<p.height; y++) {
268 if (x%2 == y%2) continue; // Cells are invalid, intersections are already handled. 268 if (x%2 == y%2) continue; // Cells are invalid, intersections are already handled.
269 if (p.grid[x][y].dot == Cell::Dot::NONE) continue; 269 if (p.grid[x][y].dot == Cell::Dot::NONE) continue;
270 270
271 // We need to introduce a new segment which contains this dot. Break the existing segment, and add one. 271 // We need to introduce a new segment which contains this dot. Break the existing segment, and add one.
272 int connectionLocation = -1; 272 int connectionLocation = -1;
273 for (int i=0; i<_connectionsA.size(); i++) { 273 for (int i=0; i<_connectionsA.size(); i++) {
274 auto [x1, y1] = loc_to_xy(p, _connectionsA[i]); 274 auto [x1, y1] = loc_to_xy(p, _connectionsA[i]);
275 auto [x2, y2] = loc_to_xy(p, _connectionsB[i]); 275 auto [x2, y2] = loc_to_xy(p, _connectionsB[i]);
276 if ((x1+1 == x && x2-1 == x && y1 == y && y2 == y) || 276 if ((x1+1 == x && x2-1 == x && y1 == y && y2 == y) ||
277 (y1+1 == y && y2-1 == y && x1 == x && x2 == x)) { 277 (y1+1 == y && y2-1 == y && x1 == x && x2 == x)) {
278 connectionLocation = i; 278 connectionLocation = i;
279 break; 279 break;
280 } 280 }
281 } 281 }
282 if (connectionLocation == -1) continue; // @Error 282 if (connectionLocation == -1) continue; // @Error
283 283
284 // @Assume: B > A for connections. To remove, add the horiz/verti check, see gaps. 284 // @Assume: B > A for connections. To remove, add the horiz/verti check, see gaps.
285 int other_connection = _connectionsB[connectionLocation]; 285 int other_connection = _connectionsB[connectionLocation];
286 _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size()); 286 _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size());
287 _connectionsA.push_back(other_connection); 287 _connectionsA.push_back(other_connection);
288 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); 288 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size()));
289 289
290 // Add this dot to the end 290 // Add this dot to the end
291 auto [xPos, yPos] = xy_to_pos(p, x, y); 291 auto [xPos, yPos] = xy_to_pos(p, x, y);
292 _intersectionLocations.push_back(xPos); 292 _intersectionLocations.push_back(xPos);
293 _intersectionLocations.push_back(yPos); 293 _intersectionLocations.push_back(yPos);
294 294
295 int flags = Flags::HAS_DOT; 295 int flags = Flags::HAS_DOT;
296 switch (p.grid[x][y].dot) { 296 switch (p.grid[x][y].dot) {
@@ -307,27 +307,27 @@ void PuzzleSerializer::WriteDots(const Puzzle& p) {
307 break; 307 break;
308 } 308 }
309 _intersectionFlags.push_back(flags); 309 _intersectionFlags.push_back(flags);
310 } 310 }
311 } 311 }
312} 312}
313 313
314void PuzzleSerializer::WriteGaps(const Puzzle& p) { 314void PuzzleSerializer::WriteGaps(const Puzzle& p) {
315 for (int x=0; x<p.width; x++) { 315 for (int x=0; x<p.width; x++) {
316 for (int y=0; y<p.height; y++) { 316 for (int y=0; y<p.height; y++) {
317 if (x%2 == y%2) continue; // Cells are invalid, intersections are already handled. 317 if (x%2 == y%2) continue; // Cells are invalid, intersections are already handled.
318 if (p.grid[x][y].gap != Cell::Gap::BREAK) continue; 318 if (p.grid[x][y].gap != Cell::Gap::BREAK) continue;
319 319
320 // We need to introduce a new segment which contains this dot. Break the existing segment, and add one. 320 // We need to introduce a new segment which contains this dot. Break the existing segment, and add one.
321 int connectionLocation = -1; 321 int connectionLocation = -1;
322 for (int i=0; i<_connectionsA.size(); i++) { 322 for (int i=0; i<_connectionsA.size(); i++) {
323 auto [x1, y1] = loc_to_xy(p, _connectionsA[i]); 323 auto [x1, y1] = loc_to_xy(p, _connectionsA[i]);
324 auto [x2, y2] = loc_to_xy(p, _connectionsB[i]); 324 auto [x2, y2] = loc_to_xy(p, _connectionsB[i]);
325 if ((x1+1 == x && x2-1 == x && y1 == y && y2 == y) || 325 if ((x1+1 == x && x2-1 == x && y1 == y && y2 == y) ||
326 (y1+1 == y && y2-1 == y && x1 == x && x2 == x)) { 326 (y1+1 == y && y2-1 == y && x1 == x && x2 == x)) {
327 connectionLocation = i; 327 connectionLocation = i;
328 break; 328 break;
329 } 329 }
330 } 330 }
331 if (connectionLocation == -1) continue; // @Error 331 if (connectionLocation == -1) continue; // @Error
332 332
333 auto [xPos, yPos] = xy_to_pos(p, x, y); 333 auto [xPos, yPos] = xy_to_pos(p, x, y);
@@ -335,49 +335,49 @@ void PuzzleSerializer::WriteGaps(const Puzzle& p) {
335 if (x%2 == 0) { // Vertical gap 335 if (x%2 == 0) { // Vertical gap
336 _connectionsA[connectionLocation] = xy_to_loc(p, x, y-1); 336 _connectionsA[connectionLocation] = xy_to_loc(p, x, y-1);
337 _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size()); 337 _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size());
338 _intersectionLocations.push_back(xPos); 338 _intersectionLocations.push_back(xPos);
339 _intersectionLocations.push_back(yPos + VERTI_GAP_SIZE / 2); 339 _intersectionLocations.push_back(yPos + VERTI_GAP_SIZE / 2);
340 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN); 340 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN);
341 341
342 _connectionsA.push_back(xy_to_loc(p, x, y+1)); 342 _connectionsA.push_back(xy_to_loc(p, x, y+1));
343 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); 343 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size()));
344 _intersectionLocations.push_back(xPos); 344 _intersectionLocations.push_back(xPos);
345 _intersectionLocations.push_back(yPos - VERTI_GAP_SIZE / 2); 345 _intersectionLocations.push_back(yPos - VERTI_GAP_SIZE / 2);
346 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN); 346 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN);
347 } else if (y%2 == 0) { // Horizontal gap 347 } else if (y%2 == 0) { // Horizontal gap
348 _connectionsA[connectionLocation] = xy_to_loc(p, x-1, y); 348 _connectionsA[connectionLocation] = xy_to_loc(p, x-1, y);
349 _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size()); 349 _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size());
350 _intersectionLocations.push_back(xPos - HORIZ_GAP_SIZE / 2); 350 _intersectionLocations.push_back(xPos - HORIZ_GAP_SIZE / 2);
351 _intersectionLocations.push_back(yPos); 351 _intersectionLocations.push_back(yPos);
352 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN); 352 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN);
353 353
354 _connectionsA.push_back(xy_to_loc(p, x+1, y)); 354 _connectionsA.push_back(xy_to_loc(p, x+1, y));
355 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); 355 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size()));
356 _intersectionLocations.push_back(xPos + HORIZ_GAP_SIZE / 2); 356 _intersectionLocations.push_back(xPos + HORIZ_GAP_SIZE / 2);
357 _intersectionLocations.push_back(yPos); 357 _intersectionLocations.push_back(yPos);
358 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN); 358 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN);
359 } 359 }
360 } 360 }
361 } 361 }
362} 362}
363 363
364void PuzzleSerializer::WriteDecorations(const Puzzle& p, int id) { 364void PuzzleSerializer::WriteDecorations(const Puzzle& p, int id) {
365 if (!p.hasDecorations) return; 365 if (!p.hasDecorations) return;
366 366
367 std::vector<int> decorations; 367 std::vector<int> decorations;
368 for (int y=p.height-2; y>0; y-=2) { 368 for (int y=p.height-2; y>0; y-=2) {
369 for (int x=1; x<p.width-1; x+=2) { 369 for (int x=1; x<p.width-1; x+=2) {
370 auto d = p.grid[x][y].decoration; 370 auto d = p.grid[x][y].decoration;
371 if (d) { 371 if (d) {
372 decorations.push_back(d->color | d->type | d->count | d->polyshape); 372 decorations.push_back(d->color | d->type | d->count | d->polyshape);
373 } else { 373 } else {
374 decorations.push_back(0); 374 decorations.push_back(0);
375 } 375 }
376 } 376 }
377 } 377 }
378 378
379 _memory->WritePanelData<int>(id, NUM_DECORATIONS, {static_cast<int>(decorations.size())}); 379 _memory->WriteEntityData<int>(id, NUM_DECORATIONS, {static_cast<int>(decorations.size())});
380 _memory->WriteArray<int>(id, DECORATIONS, decorations); 380 _memory->WriteArray<int>(id, DECORATIONS, decorations);
381} 381}
382 382
383void PuzzleSerializer::WriteSequence(const Puzzle& p, int id) { 383void PuzzleSerializer::WriteSequence(const Puzzle& p, int id) {
@@ -399,7 +399,7 @@ void PuzzleSerializer::WriteSequence(const Puzzle& p, int id) {
399 } 399 }
400 } 400 }
401 401
402 _memory->WritePanelData<int>(id, SEQUENCE_LEN, {static_cast<int>(sequence.size())}); 402 _memory->WriteEntityData<int>(id, SEQUENCE_LEN, {static_cast<int>(sequence.size())});
403 _memory->WriteNewArray<int>(id, SEQUENCE, sequence); 403 _memory->WriteNewArray<int>(id, SEQUENCE, sequence);
404} 404}
405 405
@@ -438,7 +438,7 @@ int PuzzleSerializer::xy_to_dloc(const Puzzle& p, int x, int y) const {
438} 438}
439 439
440std::tuple<float, float> PuzzleSerializer::xy_to_pos(const Puzzle& p, int x, int y) const { 440std::tuple<float, float> PuzzleSerializer::xy_to_pos(const Puzzle& p, int x, int y) const {
441 return { 441 return {
442 MIN + (x/2.0f) * WIDTH_INTERVAL, 442 MIN + (x/2.0f) * WIDTH_INTERVAL,
443 MAX - (y/2.0f) * HEIGHT_INTERVAL 443 MAX - (y/2.0f) * HEIGHT_INTERVAL
444 }; 444 };
@@ -454,8 +454,8 @@ Cell::Dot PuzzleSerializer::FlagsToDot(int flags) const {
454 454
455int PuzzleSerializer::FindConnection(int location) const { 455int PuzzleSerializer::FindConnection(int location) const {
456 for (int j=0; j<_connectionsA.size(); j++) { 456 for (int j=0; j<_connectionsA.size(); j++) {
457 if (_connectionsA[j] == location) return _connectionsB[j]; 457 if (_connectionsA[j] == location) return _connectionsB[j];
458 if (_connectionsB[j] == location) return _connectionsA[j]; 458 if (_connectionsB[j] == location) return _connectionsA[j];
459 } 459 }
460 return -1; 460 return -1;
461} 461}
diff --git a/Source/Randomizer.cpp b/Source/Randomizer.cpp index 14583f8..2545c8f 100644 --- a/Source/Randomizer.cpp +++ b/Source/Randomizer.cpp
@@ -156,35 +156,35 @@ void Randomizer::Randomize() {
156 156
157void Randomizer::AdjustSpeed() { 157void Randomizer::AdjustSpeed() {
158 // Desert Surface Final Control 158 // Desert Surface Final Control
159 _memory->WritePanelData<float>(0x09F95, OPEN_RATE, {0.04f}); // 4x 159 _memory->WriteEntityData<float>(0x09F95, OPEN_RATE, {0.04f}); // 4x
160 // Swamp Sliding Bridge 160 // Swamp Sliding Bridge
161 _memory->WritePanelData<float>(0x0061A, OPEN_RATE, {0.1f}); // 4x 161 _memory->WriteEntityData<float>(0x0061A, OPEN_RATE, {0.1f}); // 4x
162 // Mountain 2 Elevator 162 // Mountain 2 Elevator
163 _memory->WritePanelData<float>(0x09EEC, OPEN_RATE, {0.075f}); // 3x 163 _memory->WriteEntityData<float>(0x09EEC, OPEN_RATE, {0.075f}); // 3x
164} 164}
165 165
166void Randomizer::RandomizeLasers() { 166void Randomizer::RandomizeLasers() {
167 Randomize(lasers, SWAP::TARGETS); 167 Randomize(lasers, SWAP::TARGETS);
168 // Read the target of keep front laser, and write it to keep back laser. 168 // Read the target of keep front laser, and write it to keep back laser.
169 std::vector<int> keepFrontLaserTarget = _memory->ReadPanelData<int>(0x0360E, TARGET, 1); 169 std::vector<int> keepFrontLaserTarget = _memory->ReadEntityData<int>(0x0360E, TARGET, 1);
170 _memory->WritePanelData<int>(0x03317, TARGET, keepFrontLaserTarget); 170 _memory->WriteEntityData<int>(0x03317, TARGET, keepFrontLaserTarget);
171} 171}
172 172
173void Randomizer::PreventSnipes() 173void Randomizer::PreventSnipes()
174{ 174{
175 // Distance-gate swamp snipe 1 to prevent RNG swamp snipe 175 // Distance-gate swamp snipe 1 to prevent RNG swamp snipe
176 _memory->WritePanelData<float>(0x17C05, MAX_BROADCAST_DISTANCE, {15.0}); 176 _memory->WriteEntityData<float>(0x17C05, MAX_BROADCAST_DISTANCE, {15.0});
177 // Distance-gate shadows laser to prevent sniping through the bars 177 // Distance-gate shadows laser to prevent sniping through the bars
178 _memory->WritePanelData<float>(0x19650, MAX_BROADCAST_DISTANCE, {2.5}); 178 _memory->WriteEntityData<float>(0x19650, MAX_BROADCAST_DISTANCE, {2.5});
179} 179}
180 180
181// Private methods 181// Private methods
182void Randomizer::RandomizeTutorial() { 182void Randomizer::RandomizeTutorial() {
183 // Disable tutorial cursor speed modifications (not working?) 183 // Disable tutorial cursor speed modifications (not working?)
184 _memory->WritePanelData<float>(0x00295, CURSOR_SPEED_SCALE, {1.0}); 184 _memory->WriteEntityData<float>(0x00295, CURSOR_SPEED_SCALE, {1.0});
185 _memory->WritePanelData<float>(0x0C373, CURSOR_SPEED_SCALE, {1.0}); 185 _memory->WriteEntityData<float>(0x0C373, CURSOR_SPEED_SCALE, {1.0});
186 _memory->WritePanelData<float>(0x00293, CURSOR_SPEED_SCALE, {1.0}); 186 _memory->WriteEntityData<float>(0x00293, CURSOR_SPEED_SCALE, {1.0});
187 _memory->WritePanelData<float>(0x002C2, CURSOR_SPEED_SCALE, {1.0}); 187 _memory->WriteEntityData<float>(0x002C2, CURSOR_SPEED_SCALE, {1.0});
188} 188}
189 189
190void Randomizer::RandomizeSymmetry() { 190void Randomizer::RandomizeSymmetry() {
@@ -198,11 +198,11 @@ void Randomizer::RandomizeDesert() {
198 Randomize(desertPanels, SWAP::LINES); 198 Randomize(desertPanels, SWAP::LINES);
199 199
200 // Turn off desert surface 8 200 // Turn off desert surface 8
201 _memory->WritePanelData<float>(0x09F94, POWER, {0.0, 0.0}); 201 _memory->WriteEntityData<float>(0x09F94, POWER, {0.0, 0.0});
202 // Turn off desert flood final 202 // Turn off desert flood final
203 _memory->WritePanelData<float>(0x18076, POWER, {0.0, 0.0}); 203 _memory->WriteEntityData<float>(0x18076, POWER, {0.0, 0.0});
204 // Change desert floating target to desert flood final 204 // Change desert floating target to desert flood final
205 _memory->WritePanelData<int>(0x17ECA, TARGET, {0x18077}); 205 _memory->WriteEntityData<int>(0x17ECA, TARGET, {0x18077});
206} 206}
207 207
208void Randomizer::RandomizeQuarry() { 208void Randomizer::RandomizeQuarry() {
@@ -210,14 +210,14 @@ void Randomizer::RandomizeQuarry() {
210 210
211void Randomizer::RandomizeTreehouse() { 211void Randomizer::RandomizeTreehouse() {
212 // Ensure that whatever pivot panels we have are flagged as "pivotable" 212 // Ensure that whatever pivot panels we have are flagged as "pivotable"
213 int panelFlags = _memory->ReadPanelData<int>(0x17DD1, STYLE_FLAGS, 1)[0]; 213 int panelFlags = _memory->ReadEntityData<int>(0x17DD1, STYLE_FLAGS, 1)[0];
214 _memory->WritePanelData<int>(0x17DD1, STYLE_FLAGS, {panelFlags | 0x8000}); 214 _memory->WriteEntityData<int>(0x17DD1, STYLE_FLAGS, {panelFlags | 0x8000});
215 panelFlags = _memory->ReadPanelData<int>(0x17CE3, STYLE_FLAGS, 1)[0]; 215 panelFlags = _memory->ReadEntityData<int>(0x17CE3, STYLE_FLAGS, 1)[0];
216 _memory->WritePanelData<int>(0x17CE3, STYLE_FLAGS, {panelFlags | 0x8000}); 216 _memory->WriteEntityData<int>(0x17CE3, STYLE_FLAGS, {panelFlags | 0x8000});
217 panelFlags = _memory->ReadPanelData<int>(0x17DB7, STYLE_FLAGS, 1)[0]; 217 panelFlags = _memory->ReadEntityData<int>(0x17DB7, STYLE_FLAGS, 1)[0];
218 _memory->WritePanelData<int>(0x17DB7, STYLE_FLAGS, {panelFlags | 0x8000}); 218 _memory->WriteEntityData<int>(0x17DB7, STYLE_FLAGS, {panelFlags | 0x8000});
219 panelFlags = _memory->ReadPanelData<int>(0x17E52, STYLE_FLAGS, 1)[0]; 219 panelFlags = _memory->ReadEntityData<int>(0x17E52, STYLE_FLAGS, 1)[0];
220 _memory->WritePanelData<int>(0x17E52, STYLE_FLAGS, {panelFlags | 0x8000}); 220 _memory->WriteEntityData<int>(0x17E52, STYLE_FLAGS, {panelFlags | 0x8000});
221} 221}
222 222
223void Randomizer::RandomizeKeep() { 223void Randomizer::RandomizeKeep() {
@@ -225,9 +225,9 @@ void Randomizer::RandomizeKeep() {
225 225
226void Randomizer::RandomizeShadows() { 226void Randomizer::RandomizeShadows() {
227 // Change the shadows tutorial cable to only activate avoid 227 // Change the shadows tutorial cable to only activate avoid
228 _memory->WritePanelData<int>(0x319A8, CABLE_TARGET_2, {0}); 228 _memory->WriteEntityData<int>(0x319A8, CABLE_TARGET_2, {0});
229 // Change shadows avoid 8 to power shadows follow 229 // Change shadows avoid 8 to power shadows follow
230 _memory->WritePanelData<int>(0x1972F, TARGET, {0x1C34C}); 230 _memory->WriteEntityData<int>(0x1972F, TARGET, {0x1C34C});
231 231
232 std::vector<int> randomOrder(shadowsPanels.size(), 0); 232 std::vector<int> randomOrder(shadowsPanels.size(), 0);
233 std::iota(randomOrder.begin(), randomOrder.end(), 0); 233 std::iota(randomOrder.begin(), randomOrder.end(), 0);
@@ -236,9 +236,9 @@ void Randomizer::RandomizeShadows() {
236 RandomizeRange(randomOrder, SWAP::NONE, 16, 21); // Follow 236 RandomizeRange(randomOrder, SWAP::NONE, 16, 21); // Follow
237 ReassignTargets(shadowsPanels, randomOrder); 237 ReassignTargets(shadowsPanels, randomOrder);
238 // Turn off original starting panel 238 // Turn off original starting panel
239 _memory->WritePanelData<float>(shadowsPanels[0], POWER, {0.0f, 0.0f}); 239 _memory->WriteEntityData<float>(shadowsPanels[0], POWER, {0.0f, 0.0f});
240 // Turn on new starting panel 240 // Turn on new starting panel
241 _memory->WritePanelData<float>(shadowsPanels[randomOrder[0]], POWER, {1.0f, 1.0f}); 241 _memory->WriteEntityData<float>(shadowsPanels[randomOrder[0]], POWER, {1.0f, 1.0f});
242} 242}
243 243
244void Randomizer::RandomizeTown() { 244void Randomizer::RandomizeTown() {
@@ -298,7 +298,7 @@ void Randomizer::RandomizeMountain() {
298 // Randomize final pillars order 298 // Randomize final pillars order
299 std::vector<int> targets = {pillars[0] + 1}; 299 std::vector<int> targets = {pillars[0] + 1};
300 for (const int pillar : pillars) { 300 for (const int pillar : pillars) {
301 int target = _memory->ReadPanelData<int>(pillar, TARGET, 1)[0]; 301 int target = _memory->ReadEntityData<int>(pillar, TARGET, 1)[0];
302 targets.push_back(target); 302 targets.push_back(target);
303 } 303 }
304 targets[5] = pillars[5] + 1; 304 targets[5] = pillars[5] + 1;
@@ -309,17 +309,17 @@ void Randomizer::RandomizeMountain() {
309 RandomizeRange(randomOrder, SWAP::NONE, 5, 9); // Right Pillars 1-4 309 RandomizeRange(randomOrder, SWAP::NONE, 5, 9); // Right Pillars 1-4
310 ReassignTargets(pillars, randomOrder, targets); 310 ReassignTargets(pillars, randomOrder, targets);
311 // Turn off original starting panels 311 // Turn off original starting panels
312 _memory->WritePanelData<float>(pillars[0], POWER, {0.0f, 0.0f}); 312 _memory->WriteEntityData<float>(pillars[0], POWER, {0.0f, 0.0f});
313 _memory->WritePanelData<float>(pillars[5], POWER, {0.0f, 0.0f}); 313 _memory->WriteEntityData<float>(pillars[5], POWER, {0.0f, 0.0f});
314 // Turn on new starting panels 314 // Turn on new starting panels
315 _memory->WritePanelData<float>(pillars[randomOrder[0]], POWER, {1.0f, 1.0f}); 315 _memory->WriteEntityData<float>(pillars[randomOrder[0]], POWER, {1.0f, 1.0f});
316 _memory->WritePanelData<float>(pillars[randomOrder[5]], POWER, {1.0f, 1.0f}); 316 _memory->WriteEntityData<float>(pillars[randomOrder[5]], POWER, {1.0f, 1.0f});
317} 317}
318 318
319void Randomizer::RandomizeChallenge() { 319void Randomizer::RandomizeChallenge() {
320 ChallengeRandomizer cr(_memory, Random::RandInt(1, 0x7FFFFFFF)); // 0 will trigger an "RNG not initialized" block 320 ChallengeRandomizer cr(_memory, Random::RandInt(1, 0x7FFFFFFF)); // 0 will trigger an "RNG not initialized" block
321 for (int panel : challengePanels) { 321 for (int panel : challengePanels) {
322 _memory->WritePanelData<int>(panel, POWER_OFF_ON_FAIL, {0}); 322 _memory->WriteEntityData<int>(panel, POWER_OFF_ON_FAIL, {0});
323 } 323 }
324} 324}
325 325
@@ -420,10 +420,10 @@ void Randomizer::SwapPanels(int panel1, int panel2, int flags) {
420 } 420 }
421 421
422 for (auto const& [offset, size] : offsets) { 422 for (auto const& [offset, size] : offsets) {
423 std::vector<byte> panel1data = _memory->ReadPanelData<byte>(panel1, offset, size); 423 std::vector<byte> panel1data = _memory->ReadEntityData<byte>(panel1, offset, size);
424 std::vector<byte> panel2data = _memory->ReadPanelData<byte>(panel2, offset, size); 424 std::vector<byte> panel2data = _memory->ReadEntityData<byte>(panel2, offset, size);
425 _memory->WritePanelData<byte>(panel2, offset, panel1data); 425 _memory->WriteEntityData<byte>(panel2, offset, panel1data);
426 _memory->WritePanelData<byte>(panel1, offset, panel2data); 426 _memory->WriteEntityData<byte>(panel1, offset, panel2data);
427 } 427 }
428} 428}
429 429
@@ -433,7 +433,7 @@ void Randomizer::ReassignTargets(const std::vector<int>& panels, const std::vect
433 // The first panel may not have a wire to power it, so we use the panel ID itself. 433 // The first panel may not have a wire to power it, so we use the panel ID itself.
434 targets = {panels[0] + 1}; 434 targets = {panels[0] + 1};
435 for (const int panel : panels) { 435 for (const int panel : panels) {
436 int target = _memory->ReadPanelData<int>(panel, TARGET, 1)[0]; 436 int target = _memory->ReadEntityData<int>(panel, TARGET, 1)[0];
437 targets.push_back(target); 437 targets.push_back(target);
438 } 438 }
439 } 439 }
@@ -441,17 +441,17 @@ void Randomizer::ReassignTargets(const std::vector<int>& panels, const std::vect
441 for (size_t i=0; i<order.size() - 1; i++) { 441 for (size_t i=0; i<order.size() - 1; i++) {
442 // Set the target of order[i] to order[i+1], using the "real" target as determined above. 442 // Set the target of order[i] to order[i+1], using the "real" target as determined above.
443 const int panelTarget = targets[order[i+1]]; 443 const int panelTarget = targets[order[i+1]];
444 _memory->WritePanelData<int>(panels[order[i]], TARGET, {panelTarget}); 444 _memory->WriteEntityData<int>(panels[order[i]], TARGET, {panelTarget});
445 } 445 }
446} 446}
447 447
448void Randomizer::ReassignNames(const std::vector<int>& panels, const std::vector<int>& order) { 448void Randomizer::ReassignNames(const std::vector<int>& panels, const std::vector<int>& order) {
449 std::vector<int64_t> names; 449 std::vector<int64_t> names;
450 for (const int panel : panels) { 450 for (const int panel : panels) {
451 names.push_back(_memory->ReadPanelData<int64_t>(panel, AUDIO_LOG_NAME, 1)[0]); 451 names.push_back(_memory->ReadEntityData<int64_t>(panel, AUDIO_LOG_NAME, 1)[0]);
452 } 452 }
453 453
454 for (int i=0; i<panels.size(); i++) { 454 for (int i=0; i<panels.size(); i++) {
455 _memory->WritePanelData<int64_t>(panels[i], AUDIO_LOG_NAME, {names[order[i]]}); 455 _memory->WriteEntityData<int64_t>(panels[i], AUDIO_LOG_NAME, {names[order[i]]});
456 } 456 }
457} 457}
diff --git a/Source/Randomizer2.cpp b/Source/Randomizer2.cpp index 81b6874..d9c00c0 100644 --- a/Source/Randomizer2.cpp +++ b/Source/Randomizer2.cpp
@@ -233,40 +233,6 @@ void Randomizer2::RandomizeKeep() {
233 233
234 // *** Hedges 3 ** 234 // *** Hedges 3 **
235 { 235 {
236 std::vector<int> audioMarkers = {
237 0x000034a9,
238 0x000034b1,
239 0x000034be,
240 0x000034c4,
241 0x000034cb,
242 0x000034cc,
243 0x000034cd,
244 0x000034ce,
245 0x000034df,
246 0x000034e0,
247 0x000034e1,
248 0x000034e2,
249 0x000034f3,
250 0x000131cb,
251 0x00017e34,
252 0x00017e6f,
253 0x00017e76,
254 0x00017e77,
255 0x00017e7a,
256 0x00017e7e,
257 0x00017e8b,
258 0x00017e8d,
259 0x00017eb5,
260 0x000394a4,
261 0x0003b54e,
262 };
263 std::vector<int> good;
264 for (int marker : audioMarkers) {
265 // std::vector<char> assetName = _memory->ReadArray<char>(marker, 0xD8, 100);
266 std::vector<char> name = {'m', 'a', 'z', 'e', '_', 'p', 'e', 'b', 'b', 'l', 'e', '\0'};
267 _memory->WriteNewArray(marker, 0xD8, name);
268 }
269
270 Puzzle p; 236 Puzzle p;
271 p.NewGrid(4, 4); 237 p.NewGrid(4, 4);
272 238
@@ -283,6 +249,9 @@ void Randomizer2::RandomizeKeep() {
283 p.grid[0][8].start = true; 249 p.grid[0][8].start = true;
284 p.grid[8][2].end = Cell::Dir::RIGHT; 250 p.grid[8][2].end = Cell::Dir::RIGHT;
285 251
252 std::vector<int> pebbleMarkers = {0x034a9, 0x034b1, 0x034be, 0x034c4};
253
254
286 std::vector<Pos> cutEdges = Randomizer2Core::CutEdgesToBeUnique(p); 255 std::vector<Pos> cutEdges = Randomizer2Core::CutEdgesToBeUnique(p);
287 assert(cutEdges.size() == 7); 256 assert(cutEdges.size() == 7);
288 for (Pos pos : cutEdges) { 257 for (Pos pos : cutEdges) {
@@ -352,9 +321,9 @@ void Randomizer2::SetGate(int panel, int X, int Y) {
352 } 321 }
353 322
354 SetPos(panel, x, y, 19.2f); 323 SetPos(panel, x, y, 19.2f);
355 _memory->WritePanelData<float>(panel, ORIENTATION, {0.0f, 0.0f, z, w}); 324 _memory->WriteEntityData<float>(panel, ORIENTATION, {0.0f, 0.0f, z, w});
356} 325}
357 326
358void Randomizer2::SetPos(int panel, float x, float y, float z) { 327void Randomizer2::SetPos(int panel, float x, float y, float z) {
359 _memory->WritePanelData<float>(panel, POSITION, {x, y, z}); 328 _memory->WriteEntityData<float>(panel, POSITION, {x, y, z});
360} \ No newline at end of file 329} \ No newline at end of file