summary refs log tree commit diff stats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/Memory.h140
-rw-r--r--Source/Panel.cpp337
-rw-r--r--Source/Panel.h224
-rw-r--r--Source/Randomizer.h136
4 files changed, 379 insertions, 458 deletions
diff --git a/Source/Memory.h b/Source/Memory.h index c19d92b..95de884 100644 --- a/Source/Memory.h +++ b/Source/Memory.h
@@ -54,6 +54,7 @@ public:
54private: 54private:
55 template<class T> 55 template<class T>
56 std::vector<T> ReadData(const std::vector<int>& offsets, size_t numItems) { 56 std::vector<T> ReadData(const std::vector<int>& offsets, size_t numItems) {
57 if (numItems == 0) return {};
57 std::vector<T> data; 58 std::vector<T> data;
58 data.resize(numItems); 59 data.resize(numItems);
59 for (int i=0; i<5; i++) { 60 for (int i=0; i<5; i++) {
@@ -68,6 +69,7 @@ private:
68 69
69 template <class T> 70 template <class T>
70 void WriteData(const std::vector<int>& offsets, const std::vector<T>& data) { 71 void WriteData(const std::vector<int>& offsets, const std::vector<T>& data) {
72 if (data.empty()) return;
71 for (int i=0; i<5; i++) { 73 for (int i=0; i<5; i++) {
72 if (WriteProcessMemory(_handle, ComputeOffset(offsets), &data[0], sizeof(T) * data.size(), nullptr)) { 74 if (WriteProcessMemory(_handle, ComputeOffset(offsets), &data[0], sizeof(T) * data.size(), nullptr)) {
73 return; 75 return;
@@ -97,4 +99,140 @@ private:
97 friend class Temp; 99 friend class Temp;
98 friend class ChallengeRandomizer; 100 friend class ChallengeRandomizer;
99 friend class Randomizer; 101 friend class Randomizer;
100}; \ No newline at end of file 102};
103
104#if GLOBALS == 0x5B28C0
105#define PATH_COLOR 0xC8
106#define REFLECTION_PATH_COLOR 0xD8
107#define DOT_COLOR 0xF8
108#define ACTIVE_COLOR 0x108
109#define BACKGROUND_REGION_COLOR 0x118
110#define SUCCESS_COLOR_A 0x128
111#define SUCCESS_COLOR_B 0x138
112#define STROBE_COLOR_A 0x148
113#define STROBE_COLOR_B 0x158
114#define ERROR_COLOR 0x168
115#define PATTERN_POINT_COLOR 0x188
116#define PATTERN_POINT_COLOR_A 0x198
117#define PATTERN_POINT_COLOR_B 0x1A8
118#define SYMBOL_A 0x1B8
119#define SYMBOL_B 0x1C8
120#define SYMBOL_C 0x1D8
121#define SYMBOL_D 0x1E8
122#define SYMBOL_E 0x1F8
123#define PUSH_SYMBOL_COLORS 0x208
124#define OUTER_BACKGROUND 0x20C
125#define OUTER_BACKGROUND_MODE 0x21C
126#define TRACED_EDGES 0x230
127#define AUDIO_PREFIX 0x278
128#define POWER 0x2A8
129#define TARGET 0x2BC
130#define POWER_OFF_ON_FAIL 0x2C0
131#define IS_CYLINDER 0x2FC
132#define CYLINDER_Z0 0x300
133#define CYLINDER_Z1 0x304
134#define CYLINDER_RADIUS 0x308
135#define CURSOR_SPEED_SCALE 0x358
136#define NEEDS_REDRAW 0x384
137#define SPECULAR_ADD 0x398
138#define SPECULAR_POWER 0x39C
139#define PATH_WIDTH_SCALE 0x3A4
140#define STARTPOINT_SCALE 0x3A8
141#define NUM_DOTS 0x3B8
142#define NUM_CONNECTIONS 0x3BC
143#define MAX_BROADCAST_DISTANCE 0x3C0
144#define DOT_POSITIONS 0x3C8
145#define DOT_FLAGS 0x3D0
146#define DOT_CONNECTION_A 0x3D8
147#define DOT_CONNECTION_B 0x3E0
148#define DECORATIONS 0x420
149#define DECORATION_FLAGS 0x428
150#define DECORATION_COLORS 0x430
151#define NUM_DECORATIONS 0x438
152#define REFLECTION_DATA 0x440
153#define GRID_SIZE_X 0x448
154#define GRID_SIZE_Y 0x44C
155#define STYLE_FLAGS 0x450
156#define SEQUENCE_LEN 0x45C
157#define SEQUENCE 0x460
158#define DOT_SEQUENCE_LEN 0x468
159#define DOT_SEQUENCE 0x470
160#define DOT_SEQUENCE_LEN_REFLECTION 0x478
161#define DOT_SEQUENCE_REFLECTION 0x480
162#define NUM_COLORED_REGIONS 0x4A0
163#define COLORED_REGIONS 0x4A8
164#define PANEL_TARGET 0x4B0
165#define SPECULAR_TEXTURE 0x4D8
166#define CABLE_TARGET_2 0xD8
167#define AUDIO_LOG_NAME 0xC8
168#define OPEN_RATE 0xE8
169#define METADATA 0xF2 // sizeof(short)
170#define HOTEL_EP_NAME 0x4BC640
171#elif GLOBALS == 0x62D0A0
172#define PATH_COLOR 0xC0
173#define REFLECTION_PATH_COLOR 0xD0
174#define DOT_COLOR 0xF0
175#define ACTIVE_COLOR 0x100
176#define BACKGROUND_REGION_COLOR 0x110
177#define SUCCESS_COLOR_A 0x120
178#define SUCCESS_COLOR_B 0x130
179#define STROBE_COLOR_A 0x140
180#define STROBE_COLOR_B 0x150
181#define ERROR_COLOR 0x160
182#define PATTERN_POINT_COLOR 0x180
183#define PATTERN_POINT_COLOR_A 0x190
184#define PATTERN_POINT_COLOR_B 0x1A0
185#define SYMBOL_A 0x1B0
186#define SYMBOL_B 0x1C0
187#define SYMBOL_C 0x1D0
188#define SYMBOL_D 0x1E0
189#define SYMBOL_E 0x1F0
190#define PUSH_SYMBOL_COLORS 0x200
191#define OUTER_BACKGROUND 0x204
192#define OUTER_BACKGROUND_MODE 0x214
193#define TRACED_EDGES 0x228
194#define AUDIO_PREFIX 0x270
195#define POWER 0x2A0
196#define TARGET 0x2B4
197#define POWER_OFF_ON_FAIL 0x2B8
198#define IS_CYLINDER 0x2F4
199#define CYLINDER_Z0 0x2F8
200#define CYLINDER_Z1 0x2FC
201#define CYLINDER_RADIUS 0x300
202#define CURSOR_SPEED_SCALE 0x350
203#define NEEDS_REDRAW 0x37C
204#define SPECULAR_ADD 0x38C
205#define SPECULAR_POWER 0x390
206#define PATH_WIDTH_SCALE 0x39C
207#define STARTPOINT_SCALE 0x3A0
208#define NUM_DOTS 0x3B4
209#define NUM_CONNECTIONS 0x3B8
210#define MAX_BROADCAST_DISTANCE 0x3BC
211#define DOT_POSITIONS 0x3C0
212#define DOT_FLAGS 0x3C8
213#define DOT_CONNECTION_A 0x3D0
214#define DOT_CONNECTION_B 0x3D8
215#define DECORATIONS 0x418
216#define DECORATION_FLAGS 0x420
217#define DECORATION_COLORS 0x428
218#define NUM_DECORATIONS 0x430
219#define REFLECTION_DATA 0x438
220#define GRID_SIZE_X 0x440
221#define GRID_SIZE_Y 0x444
222#define STYLE_FLAGS 0x448
223#define SEQUENCE_LEN 0x454
224#define SEQUENCE 0x458
225#define DOT_SEQUENCE_LEN 0x460
226#define DOT_SEQUENCE 0x468
227#define DOT_SEQUENCE_LEN_REFLECTION 0x470
228#define DOT_SEQUENCE_REFLECTION 0x478
229#define NUM_COLORED_REGIONS 0x498
230#define COLORED_REGIONS 0x4A0
231#define PANEL_TARGET 0x4A8
232#define SPECULAR_TEXTURE 0x4D0
233#define CABLE_TARGET_2 0xD0
234#define AUDIO_LOG_NAME 0x0
235#define OPEN_RATE 0xE0
236#define METADATA 0x13A // sizeof(short)
237#define HOTEL_EP_NAME 0x51E340
238#endif \ No newline at end of file
diff --git a/Source/Panel.cpp b/Source/Panel.cpp index 43e9763..b6f0403 100644 --- a/Source/Panel.cpp +++ b/Source/Panel.cpp
@@ -1,108 +1,36 @@
1#include "Panel.h" 1#include "Panel.h"
2#include "Random.h"
3#include "Memory.h" 2#include "Memory.h"
4#include "Randomizer.h"
5#include <sstream>
6 3
7#pragma warning (disable:26451) 4#pragma warning (disable:26451)
5#pragma warning (disable:26812)
8 6
9template <class T> 7PuzzleSerializer::PuzzleSerializer(const std::shared_ptr<Memory>& memory) : _memory(memory) {}
10int find(const std::vector<T> &data, T search, size_t startIndex = 0) {
11 for (size_t i=startIndex ; i<data.size(); i++) {
12 if (data[i] == search) return static_cast<int>(i);
13 }
14 return -1;
15}
16
17Panel::Panel(const std::shared_ptr<Memory>& memory, int id) : _memory(memory) {
18 _width = 2 * _memory->ReadPanelData<int>(id, GRID_SIZE_X, 1)[0] - 1;
19 _height = 2 * _memory->ReadPanelData<int>(id, GRID_SIZE_Y, 1)[0] - 1;
20 _grid.resize(_width);
21 for (auto& row : _grid) row.resize(_height);
22
23 ReadIntersections(id);
24 ReadDecorations(id);
25}
26
27void Panel::Write(int id) {
28 WriteIntersections(id);
29 WriteDecorations(id);
30
31 _memory->WritePanelData<int>(id, GRID_SIZE_X, {(_width + 1)/2});
32 _memory->WritePanelData<int>(id, GRID_SIZE_Y, {(_height + 1)/2});
33}
34
35nlohmann::json Panel::Serialize() {
36 nlohmann::json puzzle = {
37 {"pillar", false},
38 {"dots", nlohmann::json::array()},
39 {"gaps", nlohmann::json::array()},
40 {"name", "Imported from The Witness :O"},
41 {"regionCache", nlohmann::json::object()},
42 };
43 if (_grid.empty()) return {};
44 puzzle["grid"] = nlohmann::json::array();
45
46 for (int x=0; x<_width; x++) {
47 for (int y=0; y<_height; y++) {
48 if (x%2 == 1 && y%2 == 1) {
49 puzzle["grid"][x][y] = Decoration_to_json(_grid[x][y]);
50 } else {
51 if (_grid[x][y] & IntersectionFlags::HAS_DOT) {
52 puzzle["dots"].emplace_back(nlohmann::json({{"x", x}, {"y", y}}));
53 }
54 puzzle["grid"][x][y] = false;
55 }
56 }
57 }
58
59 puzzle["startPoints"] = nlohmann::json::array();
60 for (auto [x, y] : _startpoints) {
61 nlohmann::json startPoint = {{"x", x}, {"y", y}};
62 puzzle["startPoints"].emplace_back(startPoint);
63 }
64 puzzle["endPoints"] = nlohmann::json::array();
65 for (Endpoint endpoint : _endpoints) {
66 puzzle["endPoints"].emplace_back(endpoint.to_json());
67 }
68
69 std::string out = puzzle.dump();
70 return puzzle;
71}
72 8
73void Panel::ReadDecorations(int id) { 9Puzzle PuzzleSerializer::ReadPuzzle(int id) {
74 int numDecorations = _memory->ReadPanelData<int>(id, NUM_DECORATIONS, 1)[0]; 10 Puzzle p;
75 std::vector<int> decorations = _memory->ReadArray<int>(id, DECORATIONS, numDecorations); 11 p.width = 2 * _memory->ReadPanelData<int>(id, GRID_SIZE_X, 1)[0] - 1;
12 p.height = 2 * _memory->ReadPanelData<int>(id, GRID_SIZE_Y, 1)[0] - 1;
13 p.grid.resize(p.width);
14 for (auto& row : p.grid) row.resize(p.height);
76 15
77 for (int i=0; i<numDecorations; i++) { 16 ReadIntersections(p, id);
78 auto [x, y] = dloc_to_xy(i); 17 ReadDecorations(p, id);
79 _grid[x][y] = decorations[i];
80 }
81}
82
83void Panel::WriteDecorations(int id) {
84 std::vector<int> decorations;
85 for (int y=_height-2; y>0; y-=2) {
86 for (int x=1; x<_width - 1; x+=2) {
87 decorations.push_back(_grid[x][y]);
88 }
89 }
90 18
91 _memory->WritePanelData<int>(id, NUM_DECORATIONS, {static_cast<int>(decorations.size())}); 19 return p;
92 _memory->WriteArray<int>(id, DECORATIONS, decorations);
93} 20}
94 21
95void Panel::ReadIntersections(int id) { 22void PuzzleSerializer::ReadIntersections(Puzzle& p, int id) {
96 int numIntersections = _memory->ReadPanelData<int>(id, NUM_DOTS, 1)[0]; 23 int numIntersections = _memory->ReadPanelData<int>(id, NUM_DOTS, 1)[0];
97 std::vector<int> intersectionFlags = _memory->ReadArray<int>(id, DOT_FLAGS, numIntersections); 24 std::vector<int> intersectionFlags = _memory->ReadArray<int>(id, DOT_FLAGS, numIntersections);
98 25
99 int i = 0; 26 int i = 0;
100 for (;; i++) { 27 for (;; i++) {
101 auto [x, y] = loc_to_xy(i); 28 auto [x, y] = loc_to_xy(p, i);
102 if (y < 0) break; 29 if (y < 0) break;
103 if (intersectionFlags[i] & IntersectionFlags::IS_STARTPOINT) { 30 if (intersectionFlags[i] & Flags::IS_STARTPOINT) {
104 _startpoints.push_back({x, y}); 31 p.grid[x][y].start = true;
105 } 32 }
33 p.grid[x][y].dot = FlagsToDot(intersectionFlags[i]);
106 } 34 }
107 35
108 int numConnections = _memory->ReadPanelData<int>(id, NUM_CONNECTIONS, 1)[0]; 36 int numConnections = _memory->ReadPanelData<int>(id, NUM_CONNECTIONS, 1)[0];
@@ -112,34 +40,32 @@ void Panel::ReadIntersections(int id) {
112 40
113 // Iterate the remaining intersections (endpoints, dots, gaps) 41 // Iterate the remaining intersections (endpoints, dots, gaps)
114 for (; i < numIntersections; i++) { 42 for (; i < numIntersections; i++) {
115 if (intersectionFlags[i] & IntersectionFlags::IS_ENDPOINT) { 43 if (intersectionFlags[i] & Flags::IS_ENDPOINT) {
116 for (int j=0; j<numConnections; j++) { 44 for (int j=0; j<numConnections; j++) {
117 int location = 0; 45 int location = 0;
118 if (connections_a[j] == i) location = connections_b[j]; 46 if (connections_a[j] == i) location = connections_b[j];
119 if (connections_b[j] == i) location = connections_a[j]; 47 if (connections_b[j] == i) location = connections_a[j];
120 if (location != 0) { 48 if (location != 0) {
121 Endpoint::Direction dir; 49 auto [x, y] = loc_to_xy(p, location);
122 if (intersections[2*i] < intersections[2*location]) { // Our (i) x coordinate is less than the target's (location) 50 if (intersections[2*i] < intersections[2*location]) { // Our (i) x coordinate is less than the target's (location)
123 dir = Endpoint::Direction::LEFT; 51 p.grid[x][y].end = Cell::Dir::LEFT;
124 } else if (intersections[2*i] > intersections[2*location]) { 52 } else if (intersections[2*i] > intersections[2*location]) {
125 dir = Endpoint::Direction::RIGHT; 53 p.grid[x][y].end = Cell::Dir::RIGHT;
126 } else if (intersections[2*i + 1] > intersections[2*location + 1]) { // y coordinate is 0 (bottom) 1 (top), so this check is reversed. 54 } else if (intersections[2*i + 1] > intersections[2*location + 1]) { // y coordinate is 0 (bottom) 1 (top), so this check is reversed.
127 dir = Endpoint::Direction::UP; 55 p.grid[x][y].end = Cell::Dir::UP;
128 } else { 56 } else {
129 dir = Endpoint::Direction::DOWN; 57 p.grid[x][y].end = Cell::Dir::DOWN;
130 } 58 }
131 auto [x, y] = loc_to_xy(location);
132 _endpoints.push_back(Endpoint(x, y, dir));
133 break; 59 break;
134 } 60 }
135 } 61 }
136 } else if (intersectionFlags[i] & IntersectionFlags::HAS_DOT) { 62 } else if (intersectionFlags[i] & Flags::HAS_DOT) {
137 for (int j=0; j<numConnections; j++) { 63 for (int j=0; j<numConnections; j++) {
138 int location = 0; 64 int location = 0;
139 if (connections_a[j] == i) location = connections_b[j]; 65 if (connections_a[j] == i) location = connections_b[j];
140 if (connections_b[j] == i) location = connections_a[j]; 66 if (connections_b[j] == i) location = connections_a[j];
141 if (location != 0) { 67 if (location != 0) {
142 auto [x, y] = loc_to_xy(location); 68 auto [x, y] = loc_to_xy(p, location);
143 float x1 = intersections[2*i]; 69 float x1 = intersections[2*i];
144 float y1 = intersections[2*i+1]; 70 float y1 = intersections[2*i+1];
145 float x2 = intersections[2*location]; 71 float x2 = intersections[2*location];
@@ -156,7 +82,7 @@ void Panel::ReadIntersections(int id) {
156 y++; 82 y++;
157 } 83 }
158 84
159 _grid[x][y] |= IntersectionFlags::HAS_DOT; 85 p.grid[x][y].dot = FlagsToDot(intersectionFlags[i]);
160 break; 86 break;
161 } 87 }
162 } 88 }
@@ -164,72 +90,134 @@ void Panel::ReadIntersections(int id) {
164 } 90 }
165} 91}
166 92
167void Panel::WriteIntersections(int id) { 93void PuzzleSerializer::ReadDecorations(Puzzle& p, int id) {
94 int numDecorations = _memory->ReadPanelData<int>(id, NUM_DECORATIONS, 1)[0];
95 std::vector<int> decorations = _memory->ReadArray<int>(id, DECORATIONS, numDecorations);
96 if (numDecorations != decorations.size()) return; // @Error!
97
98 for (int i=0; i<numDecorations; i++) {
99 auto [x, y] = dloc_to_xy(p, i);
100 auto d = std::make_shared<Decoration>();
101 p.grid[x][y].decoration = d;
102 d->type = static_cast<Shape>(decorations[i] & 0xFF00);
103 switch(d->type) {
104 case Shape::Poly:
105 case Shape::RPoly:
106 case Shape::Ylop:
107 d->polyshape = decorations[i] & 0xFFFF0000;
108 break;
109 case Shape::Triangle:
110 d->count = decorations[i] & 0x000F0000;
111 break;
112 }
113 d->color = static_cast<Color>(decorations[i] & 0xF);
114 }
115}
116
117void PuzzleSerializer::WritePuzzle(const Puzzle& p, int id) {
118 _memory->WritePanelData<int>(id, GRID_SIZE_X, {(p.width + 1)/2});
119 _memory->WritePanelData<int>(id, GRID_SIZE_Y, {(p.height + 1)/2});
120
121 WriteIntersections(p, id);
122 WriteDecorations(p, id);
123
124 _memory->WritePanelData<int>(id, NEEDS_REDRAW, {1});
125}
126
127void PuzzleSerializer::WriteIntersections(const Puzzle& p, int id) {
168 std::vector<float> intersections; 128 std::vector<float> intersections;
169 std::vector<int> intersectionFlags; 129 std::vector<int> intersectionFlags;
170 std::vector<int> connections_a; 130 std::vector<int> connections_a;
171 std::vector<int> connections_b; 131 std::vector<int> connections_b;
172 132
173 double min = 0.1; 133 float min = 0.1f;
174 double max = 0.9; 134 float max = 0.9f;
175 double width_interval = (max - min) / (_width/2); 135 float width_interval = (max - min) / (p.width/2);
176 double height_interval = (max - min) / (_height/2); 136 float height_interval = (max - min) / (p.height/2);
177 137
178 // TODO(future): Stop using push_back and set these into explicit locations, unrequires loop iteration order 138 // @Cleanup: If I write directly to locations, then I can remove this gross loop iterator.
179 for (int y=_height-1; y>=0; y-=2) { 139 for (int y=p.height-1; y>=0; y-=2) {
180 for (int x=0; x<_width; x+=2) { 140 for (int x=0; x<p.width; x+=2) {
181 intersections.push_back(static_cast<float>(min + (x/2) * width_interval)); 141 intersections.push_back(static_cast<float>(min + (x/2) * width_interval));
182 intersections.push_back(static_cast<float>(max - (y/2) * height_interval)); 142 intersections.push_back(static_cast<float>(max - (y/2) * height_interval));
183 int flags = 0; 143 int flags = 0;
184 if (find(_startpoints, {x, y}) != -1) flags |= IntersectionFlags::IS_STARTPOINT; 144 if (p.grid[x][y].start) {
145 flags |= Flags::IS_STARTPOINT;
146 }
185 intersectionFlags.push_back(flags); 147 intersectionFlags.push_back(flags);
186 148
187 // Create connections for this intersection -- always write low -> high 149 // Create connections for this intersection -- always write low -> high
188 if (y > 0) { 150 if (y > 0) {
189 connections_a.push_back(xy_to_loc(x, y-2)); 151 connections_a.push_back(xy_to_loc(p, x, y-2));
190 connections_b.push_back(xy_to_loc(x, y)); 152 connections_b.push_back(xy_to_loc(p, x, y));
191 } 153 }
192 if (x > 0) { 154 if (x > 0) {
193 connections_a.push_back(xy_to_loc(x-2, y)); 155 connections_a.push_back(xy_to_loc(p, x-2, y));
194 connections_b.push_back(xy_to_loc(x, y)); 156 connections_b.push_back(xy_to_loc(p, x, y));
195 } 157 }
196 } 158 }
197 } 159 }
198 160
199 for (Endpoint endpoint : _endpoints) { 161 for (int x=0; x<p.width; x++) {
200 connections_a.push_back(xy_to_loc(endpoint.GetX(), endpoint.GetY())); // Target to connect to 162 for (int y=0; y<p.height; y++) {
201 connections_b.push_back(static_cast<int>(intersectionFlags.size())); // This endpoint 163 if (p.grid[x][y].end == Cell::Dir::NONE) continue;
202 164 connections_a.push_back(xy_to_loc(p, x, y)); // Target to connect to
203 double xPos = min + (endpoint.GetX()/2) * width_interval; 165 connections_b.push_back(static_cast<int>(intersectionFlags.size())); // This endpoint
204 double yPos = max - (endpoint.GetY()/2) * height_interval; 166
205 if (endpoint.GetDir()== Endpoint::Direction::LEFT) { 167 float xPos = min + (x/2) * width_interval;
206 xPos -= .05; 168 float yPos = max - (y/2) * height_interval;
207 } else if (endpoint.GetDir() == Endpoint::Direction::RIGHT) { 169 switch (p.grid[x][y].end) {
208 xPos += .05; 170 case Cell::Dir::LEFT:
209 } else if (endpoint.GetDir() == Endpoint::Direction::UP) { 171 xPos -= .05f;
210 yPos += .05; // Y position goes from 0 (bottom) to 1 (top), so this is reversed. 172 break;
211 } else if (endpoint.GetDir() == Endpoint::Direction::DOWN) { 173 case Cell::Dir::RIGHT:
212 yPos -= .05; 174 xPos += .05f;
213 } 175 break;
214 intersections.push_back(static_cast<float>(xPos)); 176 case Cell::Dir::UP:
215 intersections.push_back(static_cast<float>(yPos)); 177 yPos += .05f; // Y position goes from 0 (bottom) to 1 (top), so this is reversed.
216 intersectionFlags.push_back(IntersectionFlags::IS_ENDPOINT); 178 break;
217 } 179 case Cell::Dir::DOWN:
180 yPos -= .05f;
181 break;
182 }
183 intersections.push_back(xPos);
184 intersections.push_back(yPos);
185 intersectionFlags.push_back(Flags::IS_ENDPOINT);
186 }
187 }
218 188
219 // Dots 189 // Dots
220 for (int y=0; y<_height; y++) { 190 for (int x=0; x<p.width; x++) {
221 for (int x=0; x<_width; x++) { 191 for (int y=0; y<p.height; y++) {
222 if (!(_grid[x][y] & IntersectionFlags::HAS_DOT)) continue; 192 if (p.grid[x][y].dot == Cell::Dot::NONE) continue;
223 if (x%2 == 1 && y%2 == 1) continue; 193 if (x%2 == 1 && y%2 == 1) continue;
194
195 int flags = Flags::HAS_DOT;
196 switch (p.grid[x][y].dot) {
197 case Cell::Dot::BLACK:
198 break;
199 case Cell::Dot::BLUE:
200 flags |= DOT_IS_BLUE;
201 break;
202 case Cell::Dot::YELLOW:
203 flags |= DOT_IS_ORANGE;
204 break;
205 case Cell::Dot::INVISIBLE:
206 flags |= DOT_IS_INVISIBLE;
207 break;
208 }
209
210 // Dot is already a point the grid, just overwrite the flags
224 if (x%2 == 0 && y%2 == 0) { 211 if (x%2 == 0 && y%2 == 0) {
225 intersectionFlags[xy_to_loc(x, y)] |= _grid[x][y]; 212 intersectionFlags[xy_to_loc(p, x, y)] |= flags;
226 continue; 213 continue;
227 } 214 }
228 215
216 // Else, we need to introduce a new segment
229 // Locate the segment we're breaking 217 // Locate the segment we're breaking
230 for (int i=0; i<connections_a.size(); i++) { 218 for (int i=0; i<connections_a.size(); i++) {
231 auto [x1, y1] = loc_to_xy(connections_a[i]); 219 auto [x1, y1] = loc_to_xy(p, connections_a[i]);
232 auto [x2, y2] = loc_to_xy(connections_b[i]); 220 auto [x2, y2] = loc_to_xy(p, connections_b[i]);
233 if ((x1+1 == x && x2-1 == x && y1 == y && y2 == y) || 221 if ((x1+1 == x && x2-1 == x && y1 == y && y2 == y) ||
234 (y1+1 == y && y2-1 == y && x1 == x && x2 == x)) { 222 (y1+1 == y && y2-1 == y && x1 == x && x2 == x)) {
235 int other_connection = connections_b[i]; 223 int other_connection = connections_b[i];
@@ -241,21 +229,82 @@ void Panel::WriteIntersections(int id) {
241 } 229 }
242 } 230 }
243 // Add this dot to the end 231 // Add this dot to the end
244 double xPos = min + (x/2.0) * width_interval; 232 float xPos = min + (x/2.0f) * width_interval;
245 double yPos = max - (y/2.0) * height_interval; 233 float yPos = max - (y/2.0f) * height_interval;
246 intersections.push_back(static_cast<float>(xPos)); 234 intersections.push_back(xPos);
247 intersections.push_back(static_cast<float>(yPos)); 235 intersections.push_back(yPos);
248 intersectionFlags.push_back(_grid[x][y]); 236 intersectionFlags.push_back(flags);
249 } 237 }
250 } 238 }
251 239
252
253 _memory->WritePanelData<int>(id, NUM_DOTS, {static_cast<int>(intersectionFlags.size())}); 240 _memory->WritePanelData<int>(id, NUM_DOTS, {static_cast<int>(intersectionFlags.size())});
254 _memory->WriteArray<float>(id, DOT_POSITIONS, intersections); 241 _memory->WriteArray<float>(id, DOT_POSITIONS, intersections);
255 _memory->WriteArray<int>(id, DOT_FLAGS, intersectionFlags); 242 _memory->WriteArray<int>(id, DOT_FLAGS, intersectionFlags);
256 _memory->WritePanelData<int>(id, NUM_CONNECTIONS, {static_cast<int>(connections_a.size())}); 243 _memory->WritePanelData<int>(id, NUM_CONNECTIONS, {static_cast<int>(connections_a.size())});
257 _memory->WriteArray<int>(id, DOT_CONNECTION_A, connections_a); 244 _memory->WriteArray<int>(id, DOT_CONNECTION_A, connections_a);
258 _memory->WriteArray<int>(id, DOT_CONNECTION_B, connections_b); 245 _memory->WriteArray<int>(id, DOT_CONNECTION_B, connections_b);
259 _memory->WritePanelData<int>(id, NEEDS_REDRAW, {1});
260} 246}
261 247
248void PuzzleSerializer::WriteDecorations(const Puzzle& p, int id) {
249 std::vector<int> decorations;
250 for (int y=p.height-2; y>0; y-=2) {
251 for (int x=1; x<p.width-1; x+=2) {
252 auto d = p.grid[x][y].decoration;
253 if (d) {
254 decorations.push_back(d->color | d->type | d->count | d->polyshape);
255 } else {
256 decorations.push_back(0);
257 }
258 }
259 }
260
261 _memory->WritePanelData<int>(id, NUM_DECORATIONS, {static_cast<int>(decorations.size())});
262 _memory->WriteArray<int>(id, DECORATIONS, decorations);
263}
264
265std::tuple<int, int> PuzzleSerializer::loc_to_xy(const Puzzle& p, int location) {
266 int height2 = (p.height - 1) / 2;
267 int width2 = (p.width + 1) / 2;
268
269 int x = 2 * (location % width2);
270 int y = 2 * (height2 - location / width2);
271 return {x, y};
272}
273
274int PuzzleSerializer::xy_to_loc(const Puzzle& p, int x, int y) {
275 int height2 = (p.height - 1) / 2;
276 int width2 = (p.width + 1) / 2;
277
278 int rowsFromBottom = height2 - y/2;
279 return rowsFromBottom * width2 + x/2;
280}
281
282std::tuple<int, int> PuzzleSerializer::dloc_to_xy(const Puzzle& p, int location) {
283 int height2 = (p.height - 3) / 2;
284 int width2 = (p.width - 1) / 2;
285
286 int x = 2 * (location % width2) + 1;
287 int y = 2 * (height2 - location / width2) + 1;
288 return {x, y};
289}
290
291int PuzzleSerializer::xy_to_dloc(const Puzzle& p, int x, int y) {
292 int height2 = (p.height - 3) / 2;
293 int width2 = (p.width - 1) / 2;
294
295 int rowsFromBottom = height2 - (y - 1)/2;
296 return rowsFromBottom * width2 + (x - 1)/2;
297}
298
299Cell::Dot PuzzleSerializer::FlagsToDot(int flags) {
300 if (!(flags & Flags::HAS_DOT)) return Cell::Dot::NONE;
301 if (flags & Flags::DOT_IS_BLUE) {
302 return Cell::Dot::BLUE;
303 } else if (flags & Flags::DOT_IS_ORANGE) {
304 return Cell::Dot::YELLOW;
305 } else if (flags & Flags::DOT_IS_INVISIBLE) {
306 return Cell::Dot::INVISIBLE;
307 } else {
308 return Cell::Dot::BLACK;
309 }
310}
diff --git a/Source/Panel.h b/Source/Panel.h index 0d1af14..caa7b04 100644 --- a/Source/Panel.h +++ b/Source/Panel.h
@@ -1,145 +1,45 @@
1#pragma once 1#pragma once
2#include "json.hpp" 2#include <memory>
3#include "Memory.h" 3#include <vector>
4 4
5enum IntersectionFlags { 5class Memory;
6 IS_ENDPOINT = 0x1, 6
7 IS_STARTPOINT = 0x2, 7enum Shape {
8 IS_GAP = 0x10000, 8 Stone = 0x100,
9 HAS_DOT = 0x40020, 9 Star = 0x200,
10 DOT_IS_BLUE = 0x100, 10 Poly = 0x400,
11 DOT_IS_ORANGE = 0x200, 11 Eraser = 0x500,
12 DOT_IS_INVISIBLE = 0x1000, 12 Triangle = 0x600,
13 RPoly = 0x1000,
14 Ylop = 0x2000,
13}; 15};
14 16
15/* 17enum Color {
16 enum Style { 18 Black = 0x1,
17 SYMMETRICAL = 0x2, 19 White = 0x2,
18 IS_2COLOR = 0x10, 20 Gray = 0x3,
19 HAS_DOTS = 0x4, 21 Purple = 0x4,
20 HAS_STARS = 0x40, 22 Green = 0x5,
21 HAS_STONES = 0x100, 23 Cyan = 0x6,
22 HAS_ERASERS = 0x1000, 24 Pink = 0x7,
23 HAS_SHAPERS = 0x2000, 25 Yellow = 0x8,
24 }; 26 Blue = 0x9,
25*/ 27 Orange = 0xA,
26
27class Endpoint {
28public:
29 enum class Direction {
30 LEFT,
31 RIGHT,
32 UP,
33 DOWN
34 };
35
36 Endpoint(int x, int y, Direction dir) {
37 _x = x;
38 _y = y;
39 _dir = dir;
40 }
41
42 int GetX() {return _x;}
43 void SetX(int x) {_x = x;}
44 int GetY() {return _y;}
45 void SetY(int y) {_y = y;}
46 Direction GetDir() {return _dir;}
47 void SetDir(Direction dir) {_dir = dir;}
48
49 nlohmann::json to_json() {
50 nlohmann::json json = {{"x", _x}, {"y", _y}};
51 if (_dir == Direction::LEFT) json["dir"] = "left";
52 if (_dir == Direction::RIGHT) json["dir"] = "right";
53 if (_dir == Direction::UP) json["dir"] = "up";
54 if (_dir == Direction::DOWN) json["dir"] = "down";
55 return json;
56 }
57
58private:
59 int _x, _y;
60 Direction _dir;
61}; 28};
62 29
63class Panel {
64public:
65 Panel(const std::shared_ptr<Memory>& memory, int id);
66 // explicit Panel(nlohmann::json json);
67
68 void Write(int id);
69 nlohmann::json Serialize();
70
71private:
72 // For testing
73 Panel() = default;
74
75 void ReadIntersections(int id);
76 void WriteIntersections(int id);
77 void ReadDecorations(int id);
78 void WriteDecorations(int id);
79
80 // TODO: Reflection data
81 // TODO: Decoration colors
82
83 std::tuple<int, int> loc_to_xy(int location) {
84 int height2 = (_height - 1) / 2;
85 int width2 = (_width + 1) / 2;
86
87 int x = 2 * (location % width2);
88 int y = 2 * (height2 - location / width2);
89 return {x, y};
90 }
91
92 int xy_to_loc(int x, int y) {
93 int height2 = (_height - 1) / 2;
94 int width2 = (_width + 1) / 2;
95
96 int rowsFromBottom = height2 - y/2;
97 return rowsFromBottom * width2 + x/2;
98 }
99
100 std::tuple<int, int> dloc_to_xy(int location) {
101 int height2 = (_height - 3) / 2;
102 int width2 = (_width - 1) / 2;
103
104 int x = 2 * (location % width2) + 1;
105 int y = 2 * (height2 - location / width2) + 1;
106 return {x, y};
107 }
108
109 int xy_to_dloc(int x, int y) {
110 int height2 = (_height - 3) / 2;
111 int width2 = (_width - 1) / 2;
112
113 int rowsFromBottom = height2 - (y - 1)/2;
114 return rowsFromBottom * width2 + (x - 1)/2;
115 }
116
117 std::shared_ptr<Memory> _memory;
118
119 int _width, _height;
120
121 std::vector<std::vector<int>> _grid;
122 std::vector<Endpoint> _endpoints;
123 std::vector<std::pair<int ,int>> _startpoints;
124 int _style;
125
126 friend class PanelExtractionTests;
127};
128
129// V2 stuff here
130struct Decoration { 30struct Decoration {
131 enum class Type {STONE, STAR, POLY, ERASER, TRIANGLE, RPOLY, YLOP}; 31 Shape type;
132 Type type; 32 Color color;
133 // TODO: Color color; 33 int polyshape;
134 uint32_t polyshape; 34 // For triangles only
135 int count; // For triangles 35 int count;
136}; 36};
137 37
138struct Cell { 38struct Cell {
139 bool start; 39 bool start;
140 enum class Dir {NONE, LEFT, RIGHT, UP, DOWN}; 40 enum class Dir {NONE, LEFT, RIGHT, UP, DOWN};
141 Dir end; 41 Dir end;
142 Decoration* decoration; 42 std::shared_ptr<Decoration> decoration;
143 enum class Dot {NONE, BLACK, BLUE, YELLOW, INVISIBLE}; 43 enum class Dot {NONE, BLACK, BLUE, YELLOW, INVISIBLE};
144 Dot dot; 44 Dot dot;
145 enum class Gap {NONE, BREAK, FULL}; 45 enum class Gap {NONE, BREAK, FULL};
@@ -149,7 +49,7 @@ struct Cell {
149struct Puzzle { 49struct Puzzle {
150 int16_t height; 50 int16_t height;
151 int16_t width; 51 int16_t width;
152 Cell** grid; 52 std::vector<std::vector<Cell>> grid;
153 53
154 enum class Symmetry {NONE, X, Y, XY}; 54 enum class Symmetry {NONE, X, Y, XY};
155 Symmetry sym; 55 Symmetry sym;
@@ -159,33 +59,11 @@ struct Puzzle {
159class PuzzleSerializer { 59class PuzzleSerializer {
160public: 60public:
161 PuzzleSerializer(const std::shared_ptr<Memory>& memory); 61 PuzzleSerializer(const std::shared_ptr<Memory>& memory);
162 Puzzle ReadPuzzle(int panelId); 62 Puzzle ReadPuzzle(int id);
163 void WritePuzzle(int panelId, const Puzzle& puzzle); 63 void WritePuzzle(const Puzzle& p, int id);
164
165//private:
166 enum Shape {
167 Stone = 0x100,
168 Star = 0x200,
169 Poly = 0x400,
170 Eraser = 0x500,
171 Triangle = 0x600,
172 RPoly = 0x1000,
173 Ylop = 0x2000,
174 };
175
176 enum Color {
177 Black = 0x1,
178 White = 0x2,
179 Gray = 0x3,
180 Purple = 0x4,
181 Green = 0x5,
182 Cyan = 0x6,
183 Pink = 0x7,
184 Yellow = 0x8,
185 Blue = 0x9,
186 Orange = 0xA,
187 };
188 64
65private:
66 // @Bug: Blue and orange are swapped?
189 enum Flags { 67 enum Flags {
190 IS_ENDPOINT = 0x1, 68 IS_ENDPOINT = 0x1,
191 IS_STARTPOINT = 0x2, 69 IS_STARTPOINT = 0x2,
@@ -196,25 +74,17 @@ public:
196 HAS_DOT = 0x40020, 74 HAS_DOT = 0x40020,
197 }; 75 };
198 76
199 std::shared_ptr<Memory> _memory; 77 void ReadIntersections(Puzzle& p, int id);
200}; 78 void ReadDecorations(Puzzle& p, int id);
201 79 void WriteIntersections(const Puzzle& p, int id);
202static nlohmann::json Decoration_to_json(int decoration) { 80 void WriteDecorations(const Puzzle& p, int id);
203 nlohmann::json json = {};
204 int shape = decoration & 0x00000F00;
205 if (shape == PuzzleSerializer::Shape::Stone) json["type"] = "square";
206 if (shape == PuzzleSerializer::Shape::Star) json["type"] = "star";
207 if (shape == PuzzleSerializer::Shape::Poly) json["type"] = "poly";
208 if (shape == PuzzleSerializer::Shape::Eraser) json["type"] = "eraser";
209 if (shape == PuzzleSerializer::Shape::Triangle) json["type"] = "triangle";
210 81
211 int color = decoration & 0x0000000F; 82 std::tuple<int, int> loc_to_xy(const Puzzle& p, int location);
212 if (color == PuzzleSerializer::Color::Black) json["color"] = "black"; 83 int xy_to_loc(const Puzzle& p, int x, int y);
213 if (color == PuzzleSerializer::Color::White) json["color"] = "white"; 84 // Decoration location
214 if (color == PuzzleSerializer::Color::Gray) json["color"] = "gray"; 85 std::tuple<int, int> dloc_to_xy(const Puzzle& p, int location);
215 if (color == PuzzleSerializer::Color::Blue) json["color"] = "blue"; 86 int xy_to_dloc(const Puzzle& p, int x, int y);
216 if (color == PuzzleSerializer::Color::Green) json["color"] = "green"; 87 Cell::Dot FlagsToDot(int flags);
217 88
218 if (json.empty()) return false; 89 std::shared_ptr<Memory> _memory;
219 return json; 90};
220}
diff --git a/Source/Randomizer.h b/Source/Randomizer.h index d9ea700..87f1f59 100644 --- a/Source/Randomizer.h +++ b/Source/Randomizer.h
@@ -47,139 +47,3 @@ private:
47 47
48 friend class SwapTests_Shipwreck_Test; 48 friend class SwapTests_Shipwreck_Test;
49}; 49};
50
51#if GLOBALS == 0x5B28C0
52#define PATH_COLOR 0xC8
53#define REFLECTION_PATH_COLOR 0xD8
54#define DOT_COLOR 0xF8
55#define ACTIVE_COLOR 0x108
56#define BACKGROUND_REGION_COLOR 0x118
57#define SUCCESS_COLOR_A 0x128
58#define SUCCESS_COLOR_B 0x138
59#define STROBE_COLOR_A 0x148
60#define STROBE_COLOR_B 0x158
61#define ERROR_COLOR 0x168
62#define PATTERN_POINT_COLOR 0x188
63#define PATTERN_POINT_COLOR_A 0x198
64#define PATTERN_POINT_COLOR_B 0x1A8
65#define SYMBOL_A 0x1B8
66#define SYMBOL_B 0x1C8
67#define SYMBOL_C 0x1D8
68#define SYMBOL_D 0x1E8
69#define SYMBOL_E 0x1F8
70#define PUSH_SYMBOL_COLORS 0x208
71#define OUTER_BACKGROUND 0x20C
72#define OUTER_BACKGROUND_MODE 0x21C
73#define TRACED_EDGES 0x230
74#define AUDIO_PREFIX 0x278
75#define POWER 0x2A8
76#define TARGET 0x2BC
77#define POWER_OFF_ON_FAIL 0x2C0
78#define IS_CYLINDER 0x2FC
79#define CYLINDER_Z0 0x300
80#define CYLINDER_Z1 0x304
81#define CYLINDER_RADIUS 0x308
82#define CURSOR_SPEED_SCALE 0x358
83#define NEEDS_REDRAW 0x384
84#define SPECULAR_ADD 0x398
85#define SPECULAR_POWER 0x39C
86#define PATH_WIDTH_SCALE 0x3A4
87#define STARTPOINT_SCALE 0x3A8
88#define NUM_DOTS 0x3B8
89#define NUM_CONNECTIONS 0x3BC
90#define MAX_BROADCAST_DISTANCE 0x3C0
91#define DOT_POSITIONS 0x3C8
92#define DOT_FLAGS 0x3D0
93#define DOT_CONNECTION_A 0x3D8
94#define DOT_CONNECTION_B 0x3E0
95#define DECORATIONS 0x420
96#define DECORATION_FLAGS 0x428
97#define DECORATION_COLORS 0x430
98#define NUM_DECORATIONS 0x438
99#define REFLECTION_DATA 0x440
100#define GRID_SIZE_X 0x448
101#define GRID_SIZE_Y 0x44C
102#define STYLE_FLAGS 0x450
103#define SEQUENCE_LEN 0x45C
104#define SEQUENCE 0x460
105#define DOT_SEQUENCE_LEN 0x468
106#define DOT_SEQUENCE 0x470
107#define DOT_SEQUENCE_LEN_REFLECTION 0x478
108#define DOT_SEQUENCE_REFLECTION 0x480
109#define NUM_COLORED_REGIONS 0x4A0
110#define COLORED_REGIONS 0x4A8
111#define PANEL_TARGET 0x4B0
112#define SPECULAR_TEXTURE 0x4D8
113#define CABLE_TARGET_2 0xD8
114#define AUDIO_LOG_NAME 0xC8
115#define OPEN_RATE 0xE8
116#define METADATA 0xF2 // sizeof(short)
117#define HOTEL_EP_NAME 0x4BC640
118#elif GLOBALS == 0x62D0A0
119#define PATH_COLOR 0xC0
120#define REFLECTION_PATH_COLOR 0xD0
121#define DOT_COLOR 0xF0
122#define ACTIVE_COLOR 0x100
123#define BACKGROUND_REGION_COLOR 0x110
124#define SUCCESS_COLOR_A 0x120
125#define SUCCESS_COLOR_B 0x130
126#define STROBE_COLOR_A 0x140
127#define STROBE_COLOR_B 0x150
128#define ERROR_COLOR 0x160
129#define PATTERN_POINT_COLOR 0x180
130#define PATTERN_POINT_COLOR_A 0x190
131#define PATTERN_POINT_COLOR_B 0x1A0
132#define SYMBOL_A 0x1B0
133#define SYMBOL_B 0x1C0
134#define SYMBOL_C 0x1D0
135#define SYMBOL_D 0x1E0
136#define SYMBOL_E 0x1F0
137#define PUSH_SYMBOL_COLORS 0x200
138#define OUTER_BACKGROUND 0x204
139#define OUTER_BACKGROUND_MODE 0x214
140#define TRACED_EDGES 0x228
141#define AUDIO_PREFIX 0x270
142#define POWER 0x2A0
143#define TARGET 0x2B4
144#define POWER_OFF_ON_FAIL 0x2B8
145#define IS_CYLINDER 0x2F4
146#define CYLINDER_Z0 0x2F8
147#define CYLINDER_Z1 0x2FC
148#define CYLINDER_RADIUS 0x300
149#define CURSOR_SPEED_SCALE 0x350
150#define NEEDS_REDRAW 0x37C
151#define SPECULAR_ADD 0x38C
152#define SPECULAR_POWER 0x390
153#define PATH_WIDTH_SCALE 0x39C
154#define STARTPOINT_SCALE 0x3A0
155#define NUM_DOTS 0x3B4
156#define NUM_CONNECTIONS 0x3B8
157#define MAX_BROADCAST_DISTANCE 0x3BC
158#define DOT_POSITIONS 0x3C0
159#define DOT_FLAGS 0x3C8
160#define DOT_CONNECTION_A 0x3D0
161#define DOT_CONNECTION_B 0x3D8
162#define DECORATIONS 0x418
163#define DECORATION_FLAGS 0x420
164#define DECORATION_COLORS 0x428
165#define NUM_DECORATIONS 0x430
166#define REFLECTION_DATA 0x438
167#define GRID_SIZE_X 0x440
168#define GRID_SIZE_Y 0x444
169#define STYLE_FLAGS 0x448
170#define SEQUENCE_LEN 0x454
171#define SEQUENCE 0x458
172#define DOT_SEQUENCE_LEN 0x460
173#define DOT_SEQUENCE 0x468
174#define DOT_SEQUENCE_LEN_REFLECTION 0x470
175#define DOT_SEQUENCE_REFLECTION 0x478
176#define NUM_COLORED_REGIONS 0x498
177#define COLORED_REGIONS 0x4A0
178#define PANEL_TARGET 0x4A8
179#define SPECULAR_TEXTURE 0x4D0
180#define CABLE_TARGET_2 0xD0
181#define AUDIO_LOG_NAME 0x0
182#define OPEN_RATE 0xE0
183#define METADATA 0x13A // sizeof(short)
184#define HOTEL_EP_NAME 0x51E340
185#endif \ No newline at end of file