about summary refs log tree commit diff stats
path: root/data/maps/the_extravagant/doors.txtpb
blob: b7e7e06865b836618a7559b6d7d16ea1d2bf7a06 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
doors {
  name: "M Side Middle Door"
  type: EVENT
  panels { room: "X Plus" name: "ROSE" }
}
doors {
  name: "M Side Right Door"
  type: EVENT
  panels { room: "X Plus" name: "ROSE" }
}
doors {
  name: "W Side Middle Door"
  type: EVENT
  panels { room: "X Minus" name: "DUO" }
}
doors {
  name: "W Side Right Door"
  type: EVENT
  panels { room: "X Minus" name: "DUO" }
}
doors {
  name: "E Door"
  type: EVENT
  panels { room: "Engine Room" name: "ENGINE" }
  panels { room: "Engine Room" name: "CABOOSE" }
  panels { room: "Hat Chamber" name: "BRIM" }
  panels { room: "Hat Chamber" name: "OUTFIT" }
  panels { room: "X Minus Middle Leg" name: "ANTENNA" }
  panels { room: "X Minus Right Leg" name: "ROWBOAT" }
  panels { room: "X Minus" name: "DUO" }
  panels { room: "X Plus Middle Leg" name: "COLONY" }
  panels { room: "X Plus Right Leg" name: "HEAD" }
  panels { room: "X Plus" name: "ROSE" }
  panels { room: "Y Minus First Floor" name: "RHINO" }
  panels { room: "Y Minus First Floor" name: "HORN" }
  panels { room: "Y Minus Second Floor" name: "COMPASS" }
  panels { room: "Y Minus Third Floor" name: "WHISKERS" }
  panels { room: "Y Plus Third Floor" name: "CACTUS" }
  panels { room: "Y Plus Third Floor" name: "TAIL" }
}
a id='n287' href='#n287'>287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
#include "pch.h"
#include "Richedit.h"
#include "Version.h"

#include "Memory.h"
#include "Random.h"
#include "Randomizer.h"
#include "Randomizer2.h"
#include "Panels_.h"

#define HEARTBEAT 0x401
#define RANDOMIZE_READY 0x402
#define RANDOMIZING 0403
#define RANDOMIZE_DONE 0x404
#define RANDOMIZE_CHALLENGE_DONE 0x405
#define CHALLENGE_ONLY 0x406
#define DISABLE_SNIPES 0x407
#define SPEED_UP_AUTOSCROLLERS 0x408

/* ------- Temp ------- */
#include "Solver.h"
#include "PuzzleSerializer.h"
#include <sstream>
#include <iomanip>

#define TMP1 0x501
#define TMP2 0x502
#define TMP3 0x503
#define TMP4 0x504

HWND g_panelId;
Puzzle g_puzzle;

HWND g_rngDebug;
#define TMP5 0x505
/* ------- Temp ------- */

// Globals
HWND g_hwnd;
HWND g_seed;
HWND g_randomizerStatus;
HINSTANCE g_hInstance;
auto g_witnessProc = std::make_shared<Memory>(L"witness64_d3d11.exe");
std::shared_ptr<Randomizer> g_randomizer;
std::shared_ptr<Randomizer2> g_randomizer2;
void SetRandomSeed();

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
	if (message == WM_DESTROY) {
		PostQuitMessage(0);
    } else if (message == WM_NOTIFY) {
        MSGFILTER* m = (MSGFILTER *)lParam;
        if (m->msg == WM_KEYDOWN && m->wParam == VK_RETURN) {
            if (IsWindowEnabled(g_randomizerStatus) == TRUE) {
                PostMessage(g_hwnd, WM_COMMAND, RANDOMIZING, NULL);
                return 1; // Non-zero to indicate that message was handled
            }
        }
    } else if (message == WM_COMMAND || message == WM_TIMER || message == WM_NOTIFY) {
        switch (LOWORD(wParam)) {
            case HEARTBEAT:
                switch ((ProcStatus)lParam) {
                    case ProcStatus::NotRunning:
                        // Shut down randomizer, wait for startup
                        if (g_randomizer) {
                            g_randomizer = nullptr;
                            g_randomizer2 = nullptr;
                            EnableWindow(g_randomizerStatus, FALSE);
                        }
                        break;
                    case ProcStatus::Running:
                        if (!g_randomizer) {
                            g_randomizer = std::make_shared<Randomizer>(g_witnessProc);
                            g_randomizer2 = std::make_shared<Randomizer2>(g_witnessProc);
                            PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_READY, NULL);
                        }
                        break;
                    case ProcStatus::NewGame: // This status will fire only once per new game
                        SetWindowText(g_seed, L"");
                        PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_READY, NULL);
                        break;
                    }
                break;
            case RANDOMIZE_READY:
                EnableWindow(g_randomizerStatus, TRUE);
                if (IsDlgButtonChecked(hwnd, CHALLENGE_ONLY)) {
                    SetWindowText(g_randomizerStatus, L"Randomize Challenge");
                } else {
                    SetWindowText(g_randomizerStatus, L"Randomize");
                }
                break;
            case RANDOMIZING:
                if (!g_randomizer) break; // E.g. an enter press at the wrong time
                EnableWindow(g_randomizerStatus, FALSE);

                SetRandomSeed();
                std::thread([]{
                    if (IsDlgButtonChecked(g_hwnd, DISABLE_SNIPES)) {
                        MEMORY_CATCH(g_randomizer->PreventSnipes());
                    }
                    if (IsDlgButtonChecked(g_hwnd, SPEED_UP_AUTOSCROLLERS)) {
                        MEMORY_CATCH(g_randomizer->AdjustSpeed());
                    }
                    if (IsDlgButtonChecked(g_hwnd, CHALLENGE_ONLY)) {
                        SetWindowText(g_randomizerStatus, L"Randomizing Challenge...");
                        MEMORY_CATCH(g_randomizer->RandomizeChallenge());
                        PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_CHALLENGE_DONE, NULL);
                    } else {
                        SetWindowText(g_randomizerStatus, L"Randomizing...");
                        MEMORY_CATCH(g_randomizer->Randomize());
                        PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_DONE, NULL);
                    }
                }).detach();
                break;
            case RANDOMIZE_DONE:
                EnableWindow(g_randomizerStatus, FALSE);
                SetWindowText(g_randomizerStatus, L"Randomized!");
                break;
            case RANDOMIZE_CHALLENGE_DONE:
                EnableWindow(g_randomizerStatus, FALSE);
                SetWindowText(g_randomizerStatus, L"Randomized Challenge!");
                std::thread([]{
                    // Allow re-randomization for challenge -- it doesn't break the rest of the game.
                    std::this_thread::sleep_for(std::chrono::seconds(10));
                    PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_READY, NULL);
                }).detach();
                break;
            case CHALLENGE_ONLY:
                CheckDlgButton(hwnd, CHALLENGE_ONLY, !IsDlgButtonChecked(hwnd, CHALLENGE_ONLY));
                if (IsWindowEnabled(g_randomizerStatus)) {
                    PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_READY, NULL);
                }
                break;
            case DISABLE_SNIPES:
                CheckDlgButton(hwnd, DISABLE_SNIPES, !IsDlgButtonChecked(hwnd, DISABLE_SNIPES));
                break;
            case SPEED_UP_AUTOSCROLLERS:
                CheckDlgButton(hwnd, SPEED_UP_AUTOSCROLLERS, !IsDlgButtonChecked(hwnd, SPEED_UP_AUTOSCROLLERS));
                break;
            case TMP1:
                {
                    std::wstring text(128, L'\0');
                    int length = GetWindowText(g_panelId, text.data(), static_cast<int>(text.size()));
                    text.resize(length);
                    std::wstringstream s;
                    int panelId;
                    s << text;
                    s >> std::hex >> panelId;
                    g_puzzle = PuzzleSerializer(g_witnessProc).ReadPuzzle(panelId);
                }
                break;
            case TMP2:
                {
                    std::wstring text(128, L'\0');
                    int length = GetWindowText(g_panelId, text.data(), static_cast<int>(text.size()));
                    text.resize(length);
                    std::wstringstream s;
                    int panelId;
                    s << text;
                    s >> std::hex >> panelId;
                    PuzzleSerializer(g_witnessProc).WritePuzzle(g_puzzle, panelId);
                }
                break;
            case TMP3:
                {
                    for (auto [key, value] : PANELS) {
                        std::stringstream out;
                        std::string name(value);
                        out << "  {'id': 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(5) << key << ", 'area':'";
                        int k;  
                        for (k=0; name[k] != ' '; k++) out << name[k];
                        if (name[k+2] == ' ') {
                            out << name[k] << name[k+1];
                            k += 2;
                        }
                        out << "', 'name':'";
                        k++;
                        for (k; k < name.size(); k++) out << name[k];
                        out << "', 'data':'";
                        auto puzzle = PuzzleSerializer(g_witnessProc).ReadPuzzle(key);
                        out << puzzle.Serialize();
                        out << "'},\r\n";
                        DebugPrint(out.str());
                    }
                }

                // Solver::Solve(g_puzzle);
                break;
            case TMP4:
                SetRandomSeed();
                g_randomizer2->Randomize();
            case TMP5:
                {
                    std::wstring text;
                    for (int i=0; i<10; i++) {
                        Random::SetSeed(i);
                        int rng = Random::RandInt(0, 999999);
                        text += std::to_wstring(rng) + L"\n";
                    }
                    SetWindowText(g_rngDebug, text.c_str());
                }
        }
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

void SetRandomSeed() {
    std::wstring text(128, L'\0');
    int length = GetWindowText(g_seed, text.data(), static_cast<int>(text.size()));
    if (length > 0) { // Set seed
        text.resize(length);
        Random::SetSeed(_wtoi(text.c_str()));
    } else { // Random seed
        int seed = Random::RandInt(0, 999999);

        text = std::to_wstring(seed);
        SetWindowText(g_seed, text.c_str());
        CHARRANGE range = {0, static_cast<long>(text.length())};
        PostMessage(g_seed, EM_EXSETSEL, NULL, (LPARAM)&range);
        SetFocus(g_seed);

		Random::SetSeed(seed);
    }
}

HWND CreateLabel(int x, int y, int width, LPCWSTR text) {
	return CreateWindow(L"STATIC", text,
		WS_TABSTOP | WS_VISIBLE | WS_CHILD | SS_LEFT,
		x, y, width, 16, g_hwnd, NULL, g_hInstance, NULL);
}

HWND CreateText(int x, int y, int width, LPCWSTR defaultText = L"") {
	return CreateWindow(MSFTEDIT_CLASS, defaultText,
        WS_TABSTOP | WS_VISIBLE | WS_CHILD | WS_BORDER,
        x, y, width, 26, g_hwnd, NULL, g_hInstance, NULL);
}

#pragma warning(push)
#pragma warning(disable: 4312)
HWND CreateButton(int x, int y, int width, LPCWSTR text, int message) {
	return CreateWindow(L"BUTTON", text,
		WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
		x, y, width, 26, g_hwnd, (HMENU)message, g_hInstance, NULL);
}

HWND CreateCheckbox(int x, int y, int message) {
	return CreateWindow(L"BUTTON", L"",
        WS_VISIBLE | WS_CHILD | BS_CHECKBOX,
        x, y, 12, 12, g_hwnd, (HMENU)message, g_hInstance, NULL);
}
#pragma warning(pop)

int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
	LoadLibrary(L"Msftedit.dll");
	WNDCLASSW wndClass = {
		CS_HREDRAW | CS_VREDRAW,
		WndProc,
		0,
		0,
		hInstance,
		NULL,
		LoadCursor(nullptr, IDC_ARROW),
		(HBRUSH)(COLOR_WINDOW+1),
		WINDOW_CLASS,
		WINDOW_CLASS,
	};
	RegisterClassW(&wndClass);

    g_hInstance = hInstance;

	RECT rect;
    GetClientRect(GetDesktopWindow(), &rect);
	g_hwnd = CreateWindow(WINDOW_CLASS, PRODUCT_NAME, WS_OVERLAPPEDWINDOW,
      rect.right - 550, 200, 500, 500, nullptr, nullptr, hInstance, nullptr);

    CreateLabel(390, 15, 90, L"Version: " VERSION_STR);
    g_seed = CreateText(10, 10, 100);
    PostMessage(g_seed, EM_SETEVENTMASK, 0, ENM_KEYEVENTS);
    g_randomizerStatus = CreateButton(120, 10, 180, L"Randomize", RANDOMIZING);
    EnableWindow(g_randomizerStatus, FALSE);
    CreateCheckbox(10, 300, CHALLENGE_ONLY);
    CreateLabel(30, 300, 200, L"Randomize the challenge only");
    CreateCheckbox(10, 320, DISABLE_SNIPES);
    CheckDlgButton(g_hwnd, DISABLE_SNIPES, TRUE);
    CreateLabel(30, 320, 240, L"Disable Swamp and Shadows snipes");
    CreateCheckbox(10, 340, SPEED_UP_AUTOSCROLLERS);
    CreateLabel(30, 340, 205, L"Speed up various autoscrollers");

    // CreateButton(200, 50, 200, L"Test RNG", TMP5);
    // g_rngDebug = CreateWindow(L"STATIC", L"",
	//     WS_TABSTOP | WS_VISIBLE | WS_CHILD | SS_LEFT,
	//     200, 80, 200, 200, g_hwnd, NULL, g_hInstance, NULL);
#ifndef NDEBUG
    g_panelId = CreateText(200, 100, 100, L"59");
    CreateButton(200, 130, 100, L"Read", TMP1);
    CreateButton(200, 160, 100, L"Write", TMP2);
    CreateButton(200, 190, 100, L"Solve", TMP3);
    CreateButton(200, 220, 100, L"Randomize2", TMP4);
#endif

    g_witnessProc->StartHeartbeat(g_hwnd, HEARTBEAT);

	ShowWindow(g_hwnd, nCmdShow);
	UpdateWindow(g_hwnd);

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0) == TRUE) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}