diff options
| -rw-r--r-- | App/Main.cpp | 21 | ||||
| -rw-r--r-- | Source/Memory.h | 140 | ||||
| -rw-r--r-- | Source/Panel.cpp | 337 | ||||
| -rw-r--r-- | Source/Panel.h | 224 | ||||
| -rw-r--r-- | Source/Randomizer.h | 136 |
5 files changed, 387 insertions, 471 deletions
| diff --git a/App/Main.cpp b/App/Main.cpp index 39dd517..535a18e 100644 --- a/App/Main.cpp +++ b/App/Main.cpp | |||
| @@ -27,12 +27,11 @@ | |||
| 27 | #define TMP4 0x504 | 27 | #define TMP4 0x504 |
| 28 | 28 | ||
| 29 | #include "Panel.h" | 29 | #include "Panel.h" |
| 30 | int panel = 0x33D4; | 30 | // int panel = 0x33D4; // Tutorial vault |
| 31 | std::shared_ptr<Panel> g_panel; | 31 | int panel = 0x0005D; // Outside Tutorial Dots Tutorial 1 |
| 32 | Puzzle g_puzzle; | ||
| 32 | /* ------- Temp ------- */ | 33 | /* ------- Temp ------- */ |
| 33 | 34 | ||
| 34 | |||
| 35 | |||
| 36 | // Globals | 35 | // Globals |
| 37 | HWND g_hwnd; | 36 | HWND g_hwnd; |
| 38 | HWND g_seed; | 37 | HWND g_seed; |
| @@ -133,13 +132,10 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | |||
| 133 | CheckDlgButton(hwnd, SPEED_UP_AUTOSCROLLERS, !IsDlgButtonChecked(hwnd, SPEED_UP_AUTOSCROLLERS)); | 132 | CheckDlgButton(hwnd, SPEED_UP_AUTOSCROLLERS, !IsDlgButtonChecked(hwnd, SPEED_UP_AUTOSCROLLERS)); |
| 134 | break; | 133 | break; |
| 135 | case TMP1: | 134 | case TMP1: |
| 136 | g_panel = std::make_shared<Panel>(g_witnessProc, panel); | 135 | g_puzzle = PuzzleSerializer(g_witnessProc).ReadPuzzle(panel); |
| 137 | break; | 136 | break; |
| 138 | case TMP2: | 137 | case TMP2: |
| 139 | if(g_panel) g_panel->Write(panel); | 138 | PuzzleSerializer(g_witnessProc).WritePuzzle(g_puzzle, panel); |
| 140 | break; | ||
| 141 | case TMP4: | ||
| 142 | if(g_panel) g_panel->Serialize(); | ||
| 143 | break; | 139 | break; |
| 144 | } | 140 | } |
| 145 | } | 141 | } |
| @@ -223,10 +219,9 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance | |||
| 223 | CreateCheckbox(10, 340, SPEED_UP_AUTOSCROLLERS); | 219 | CreateCheckbox(10, 340, SPEED_UP_AUTOSCROLLERS); |
| 224 | CreateLabel(30, 340, 205, L"Speed up various autoscrollers"); | 220 | CreateLabel(30, 340, 205, L"Speed up various autoscrollers"); |
| 225 | 221 | ||
| 226 | // CreateButton(200, 100, 100, L"Read", TMP1); | 222 | CreateButton(200, 100, 100, L"Read", TMP1); |
| 227 | // CreateButton(200, 130, 100, L"Write", TMP2); | 223 | CreateButton(200, 130, 100, L"Write", TMP2); |
| 228 | // CreateButton(200, 160, 100, L"Random", TMP3); | 224 | CreateButton(200, 190, 100, L"Dump", TMP4); |
| 229 | // CreateButton(200, 190, 100, L"Dump", TMP4); | ||
| 230 | 225 | ||
| 231 | g_witnessProc->StartHeartbeat(g_hwnd); | 226 | g_witnessProc->StartHeartbeat(g_hwnd); |
| 232 | 227 | ||
| 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: | |||
| 54 | private: | 54 | private: |
| 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 | ||
| 9 | template <class T> | 7 | PuzzleSerializer::PuzzleSerializer(const std::shared_ptr<Memory>& memory) : _memory(memory) {} |
| 10 | int 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 | |||
| 17 | Panel::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 | |||
| 27 | void 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 | |||
| 35 | nlohmann::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 | ||
| 73 | void Panel::ReadDecorations(int id) { | 9 | Puzzle 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 | |||
| 83 | void 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 | ||
| 95 | void Panel::ReadIntersections(int id) { | 22 | void 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 | ||
| 167 | void Panel::WriteIntersections(int id) { | 93 | void 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 | |||
| 117 | void 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 | |||
| 127 | void 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 | ||
| 248 | void 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 | |||
| 265 | std::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 | |||
| 274 | int 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 | |||
| 282 | std::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 | |||
| 291 | int 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 | |||
| 299 | Cell::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 | ||
| 5 | enum IntersectionFlags { | 5 | class Memory; |
| 6 | IS_ENDPOINT = 0x1, | 6 | |
| 7 | IS_STARTPOINT = 0x2, | 7 | enum 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 | /* | 17 | enum 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 | |||
| 27 | class Endpoint { | ||
| 28 | public: | ||
| 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 | |||
| 58 | private: | ||
| 59 | int _x, _y; | ||
| 60 | Direction _dir; | ||
| 61 | }; | 28 | }; |
| 62 | 29 | ||
| 63 | class Panel { | ||
| 64 | public: | ||
| 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 | |||
| 71 | private: | ||
| 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 | ||
| 130 | struct Decoration { | 30 | struct 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 | ||
| 138 | struct Cell { | 38 | struct 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 { | |||
| 149 | struct Puzzle { | 49 | struct 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 { | |||
| 159 | class PuzzleSerializer { | 59 | class PuzzleSerializer { |
| 160 | public: | 60 | public: |
| 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 | ||
| 65 | private: | ||
| 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); | |
| 202 | static 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 | ||
