X-Git-Url: https://gitweb.ps.run/npengine/blobdiff_plain/f7e4fe9f4c198045f54f83ffe379fd7a20d8dd76..95e933b0f5f5e186548e28b9cb10b374fedb755c:/src/main.cpp diff --git a/src/main.cpp b/src/main.cpp index 5493148..888035d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,127 +1,136 @@ -#define DIRECTINPUT_VERSION 0x0800 -#include -#include +#include #include -#include #include -#include +#include +#include +#include #pragma comment(lib, "user32.lib") -#pragma comment(lib, "dinput8.lib") -#pragma comment(lib, "dxguid.lib") -HWND hwnd = NULL; +#define CONSOLE -const int WIDTH = 43, HEIGHT = 25; -int x = 0, y = 0; -bool right = true; +#ifdef CONSOLE +#pragma comment(linker, "/subsystem:console") +#else +#pragma comment(linker, "/subsystem:windows") +#endif -clock_t update_clock = clock(); -double update_time = 40; +using namespace std; -bool keys[4] = { false, false, false, false }; -bool keys_old[4] = { false, false, false, false }; -int jumping = 0; +const int WIDTH = 56, HEIGHT = 29; -clock_t jump_clock = clock(); -double jump_time1 = 50; -double jump_time2 = 100; -int jump_height = 3; +std::string map; -DWORD wait_time = 10; +clock_t game_clock; +double frame_time = 30; -void press_down(WORD vk) { - INPUT ip; +int lvl = 0; - ip.type = INPUT_KEYBOARD; - ip.ki.wScan = 0; - ip.ki.time = 0; - ip.ki.dwExtraInfo = 0; +// Util - ip.ki.wVk = vk; - ip.ki.dwFlags = 0; - SendInput(1, &ip, sizeof(INPUT)); +double get_dur(clock_t then) { + double result = (double)(clock() - then) / CLOCKS_PER_SEC; + return result * 1000; } -void press_up(WORD vk) { - INPUT ip; - ip.type = INPUT_KEYBOARD; - ip.ki.wScan = 0; - ip.ki.time = 0; - ip.ki.dwExtraInfo = 0; +// Edit - ip.ki.dwFlags = KEYEVENTF_KEYUP; - SendInput(1, &ip, sizeof(INPUT)); -} +HWND hwnd_notepad = NULL; +HWND hwnd_edit = NULL; -void press(WORD vk) { - press_down(vk); - press_up(vk); - GetAsyncKeyState(vk); +string get_text() { + int len = SendMessageA(hwnd_edit, WM_GETTEXTLENGTH, 0, 0); + char *buffer = new char[len + 1]; + int read = SendMessageA(hwnd_edit, WM_GETTEXT, len + 1, (LPARAM)buffer); + if (read != len) + puts("???"); + buffer[read] = 0; + string result(buffer); + delete[] buffer; + return result; } -void key_down(char c) { - if (hwnd == NULL) - puts("oh no"); - INPUT ip; - ip.type = INPUT_KEYBOARD; - ip.ki.time = 0; - ip.ki.dwExtraInfo = 0; - - ip.ki.dwFlags = KEYEVENTF_UNICODE; - ip.ki.wVk = 0; - ip.ki.wScan = c; - SendInput(1, &ip, sizeof(INPUT)); +void select_all() { + SendMessage(hwnd_edit, EM_SETSEL, 0, get_text().size()); } -void key_up(char c) { - if (hwnd == NULL) - puts("oh no"); - INPUT ip; - ip.type = INPUT_KEYBOARD; - ip.ki.time = 0; - ip.ki.dwExtraInfo = 0; - - // Release key - ip.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; - SendInput(1, &ip, sizeof(INPUT)); +void select_length(int from, int length) { + SendMessage(hwnd_edit, EM_SETSEL, from, from + length); } -void key(char c) { - key_down(c); - key_up(c); +void select_from_to(int from, int to) { + SendMessage(hwnd_edit, EM_SETSEL, from, to); } -LPDIRECTINPUT8 di; -LPDIRECTINPUTDEVICE8 keyboard; - -HRESULT initializedirectinput8() { - HRESULT hr; - // Create a DirectInput device - if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, - IID_IDirectInput8, (VOID **)&di, NULL))) { - return hr; - } - return 0; +void replace(string str) { + SendMessage(hwnd_edit, EM_REPLACESEL, FALSE, (LPARAM)str.c_str()); } -void createdikeyboard() { - di->CreateDevice(GUID_SysKeyboard, &keyboard, NULL); - keyboard->SetDataFormat(&c_dfDIKeyboard); - keyboard->SetCooperativeLevel(NULL, DISCL_FOREGROUND | DISCL_EXCLUSIVE); - keyboard->Acquire(); +int get_pos(int x, int y) { + return (y + 1) * (WIDTH + 4) + x + 1; } -void destroydikeyboard() { - keyboard->Unacquire(); - keyboard->Release(); +char get_block(int x, int y) { + return map[get_pos(x, y)]; } -#define keydown(name, key) (name[key] & 0x80) +// Player +struct Player { + bool left = false; + int x, y; + int x_spawn, y_spawn; + int jumping = 0; + + void clear() { + int pos = get_pos(x, y); + select_length(pos, 1); + replace({ map[pos], 0 }); + } + + void draw() { + int pos = get_pos(x, y); + select_length(pos, 1); + replace({ left ? '<' : '>', 0 }); + } + + void move_to(int x, int y) { + clear(); + if (this->x > x) left = true; + if (this->x < x) left = false; + this->x = x; + this->y = y; + draw(); + } + + void move(int dx, int dy) { + move_to(x + dx, y + dy); + } + + bool collision_x(int n) { + if (x + n < 0 || x + n >= WIDTH) + return true; + for (int i = 0; i != n; i += (n < 0 ? -1 : 1)) + if (get_block(x + i + (n < 0 ? -1 : 1), y) == 'X') + return true; + return false; + } + bool collision_y(int n) { + if (y + n < 0 || y + n >= HEIGHT) + return true; + for (int i = 0; i != n; i += (n < 0 ? -1 : 1)) + if (get_block(x, y + i + (n < 0 ? -1 : 1)) == 'X') + return true; + return false; + } +}; +Player player { 0, 0 }; + +// Lvl -std::string read_map() { - std::ifstream ifs("lvl/1.txt", std::ios::in | std::ios::binary); +std::string read_map(int lvl) { + std::ifstream ifs("lvl/" + std::to_string(lvl) + ".txt", + std::ios::in | std::ios::binary); if (!ifs.good()) puts("mist"); ifs.seekg(0, std::ios::end); @@ -135,257 +144,286 @@ std::string read_map() { delete buffer; return result; } -std::string map = read_map(); -char get_block(int x, int y) { - char result = map[WIDTH + 8 + y * (WIDTH + 4) + x + 1]; - return result; +void redraw() { + select_all(); + replace(map); + player.draw(); } -double get_dur(clock_t then) { - double result = (double)(clock() - then) / CLOCKS_PER_SEC; - return result * 1000; -} - -void draw() { - press(VK_BACK); - key(right ? '>' : '<'); +void load_level(int l) { + lvl = l; + map = read_map(l); + redraw(); + for (int x = 0; x < WIDTH; x++) { + for (int y = 0; y < HEIGHT; y++) { + if (map[get_pos(x, y)] == 'S') { + player.x_spawn = x; + player.y_spawn = y; + player.move_to(x, y); + return; + } + } + } } -void erase() { - press(VK_BACK); - key(get_block(x, y)); -} +// Notepad -void move(int dx, int dy) { - erase(); +STARTUPINFOA si; +PROCESS_INFORMATION pi; - for (int i = 0; i < dx; i++) { - right = true; - press(VK_RIGHT); - } - for (int i = 0; i > dx; i--) { - right = false; - press(VK_LEFT); - } - for (int i = 0; i < dy; i++) { - press(VK_DOWN); +BOOL CALLBACK ew_cb(HWND hwnd, LPARAM lp) { + DWORD pid; + DWORD tid = GetWindowThreadProcessId(hwnd, &pid); + if (pi.dwProcessId == pid && pi.dwThreadId == tid) { + hwnd_notepad = hwnd; + return false; } - for (int i = 0; i > dy; i--) { - press(VK_UP); + return true; +} +BOOL CALLBACK ecw_cb(HWND child, LPARAM in) { + char buffer[1024 + 1]; + int len = GetClassNameA(child, buffer, 1024); + buffer[len] = 0; + if (strcmp(buffer, "Edit") == 0) { + hwnd_edit = child; + return false; } - - draw(); - - x += dx; - y += dy; - - printf("%d %d\n", x, y); + return true; } -void move_to(int _x, int _y) { - move(_x - x, _y - y); +void start_notepad() { + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + + if (!CreateProcessA(NULL, // No module name (use command line) + "notepad.exe", // Command line + NULL, // Process handle not inheritable + NULL, // Thread handle not inheritable + FALSE, // Set handle inheritance to FALSE + 0, // No creation flags + NULL, // Use parent's environment block + NULL, // Use parent's starting directory + &si, // Pointer to STARTUPINFO structure + &pi) // Pointer to PROCESS_INFORMATION structure + ) { + printf("CreateProcess failed (%d).\n", GetLastError()); + } + Sleep(100); + EnumWindows(ew_cb, 0); + EnumChildWindows(hwnd_notepad, ecw_cb, 0); + SendMessage(hwnd_edit, EM_SETREADONLY, TRUE, NULL); +} +void close_notepad() { + TerminateProcess(pi.hProcess, 0); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); } -void print_text(int text_x, int text_y, const char *text, int delay) { - for (int i = x; i < text_x; i++) press(VK_RIGHT); - for (int i = x; i > text_x; i--) press(VK_LEFT); - for (int i = y; i < text_y; i++) press(VK_DOWN); - for (int i = y; i > text_y; i--) press(VK_UP); +// Keys + +enum class Key { + Left, + Right, + Jump, + Exit, + Redraw, + COUNT +}; + +bool key_state[(uint64_t)Key::COUNT]; +bool key_state_old[(uint64_t)Key::COUNT]; + +int key_get_vk(Key key) { + switch (key) { + case Key::Left: return 'A'; + case Key::Right: return 'D'; + case Key::Jump: return VK_SPACE; + case Key::Exit: return VK_ESCAPE; + case Key::Redraw: return 'R'; + default: return 0; + } +} - int len = strlen(text); - for (int i = 0; i < len; i++) { - press(VK_DELETE); - key(text[i]); - Sleep(delay); +void update_key_state() { + for (int i = 0; i < (int)Key::COUNT; i++) { + key_state[i] = GetAsyncKeyState(key_get_vk((Key)i)); } - for (int i = text_x + len; i < x; i++) press(VK_RIGHT); - for (int i = text_x + len; i > x; i--) press(VK_LEFT); - for (int i = text_y; i < y; i++) press(VK_DOWN); - for (int i = text_y; i > y; i--) press(VK_UP); +} - draw(); +void update_key_state_old() { + for (int i = 0; i < (int)Key::COUNT; i++) { + key_state_old[i] = key_state[i]; + } +} - Sleep(100); +bool key_pressed(Key key) { + return key_state[(int)key] && !key_state_old[(int)key]; } -void update_play(bool can_jump = true) { - if (get_dur(update_clock) >= update_time) { - update_clock = clock(); - - if (keys[0] && - x > 0 && - get_block(x - 1, y) != 'x') - move(-1, 0); - if (keys[1] && - x < WIDTH - 1 && - get_block(x + 1, y) != 'x') - move(+1, 0); - } +bool key_down(Key key) { + return key_state[(int)key]; +} - // bool left = false; - // bool right = false; - // bool up = false; - // bool down = false; +bool key_up(Key key) { + return !key_state[(int)key]; +} - if (keys[2] && !keys_old[2] && jumping == 0 && can_jump) { - jumping = 1; - move(0, -1); +// Gameplay + +clock_t jump_clock = clock(); +int jump_height = 3; +double jump_time1 = 50; +double jump_time2 = 100; +int text_speed = 50; + +void update_play(bool can_jump = true, int x_min = 0, int x_max = WIDTH - 1) { + if (key_down(Key::Left) && + !player.collision_x(-1) && + player.x > x_min) + player.move(-1, 0); + if (key_down(Key::Right) && + !player.collision_x(1) && + player.x < x_max) + player.move(+1, 0); + + if (key_pressed(Key::Jump) && + can_jump && + player.jumping == 0 && + !player.collision_y(-1)) { + player.jumping = 1; + player.move(0, -1); jump_clock = clock(); } - if (jumping != 0) { - if (jumping < jump_height && get_dur(jump_clock) > jump_time1) { - if (get_block(x, y - 1) != 'x') { - move(0, -1); - jumping++; - jump_clock = clock(); + if (player.jumping != 0) { + if (player.jumping < jump_height && get_dur(jump_clock) > jump_time1) { + if (!player.collision_y(-1)) { + player.move(0, -1); + player.jumping++; + jump_clock = clock(); } else { - jumping = jump_height; + player.jumping = jump_height; } - } - else if (jumping == jump_height && get_dur(jump_clock) > jump_time2) { - jumping = 0; + } else if (player.jumping == jump_height && get_dur(jump_clock) > jump_time2) { + player.jumping = 0; } } - if (!jumping && get_block(x, y + 1) != 'x' && y < HEIGHT - 1) - move(0, +1); - - char block = get_block(x, y); - switch (block) { - case '/': - case '\\': - move_to(0, 24); - break; - case '?': - puts("?"); - break; - case 'O': - puts("O"); - break; - } + if (!player.jumping && !player.collision_y(1)) + player.move(0, +1); + + char b = get_block(player.x, player.y); + if (b == '/' || b == '\\' || b == '<' || b == '>') + player.move_to(player.x_spawn, player.y_spawn); } -int lvl = 0; +void print_text(int x, int y, string text, int delay) { + for (int i = 0; i < text.size(); i++) { + select_length(get_pos(x + i, y), 1); + replace(text.substr(i, 1)); + Sleep(delay); + } +} void intro() { static int progress = 0; switch (progress) { case 0: - press(VK_DOWN); - press(VK_RIGHT); - press(VK_RIGHT); - - move_to(1, 24); - - print_text(4, 2, "Move with left/right.", 30); + print_text(4, 2, "Move with left/right.", text_speed); progress++; break; case 1: update_play(false); - if (x == 5) { - print_text(4, 4, "Jump with up.", 30); - print_text(4, 6, "Stand on x.", 30); + if (player.x == 17) { + print_text(4, 4, "Jump with up.", text_speed); + print_text(4, 6, "Stand on x.", text_speed); progress++; } break; case 2: update_play(); - if (x == 8) { - print_text(4, 8, "Collect ? for ???.", 30); + if (player.x == 22) { + print_text(4, 8, "Collect ? for ???.", text_speed); + progress++; + } + break; + case 3: + update_play(true, 0, 33); + if (get_block(player.x, player.y) == '?') { + print_text(4, 10, "Avoid /\\.", text_speed); + progress++; + } + break; + case 4: + update_play(); + if (player.x == 39) { + print_text(4, 14, "Finish lvl by reaching O.", text_speed); + progress++; + } + break; + case 5: + update_play(); + if (get_block(player.x, player.y) == 'O') { + load_level(1); } break; } } +void lvl1() { + static int progress = 0; + switch (progress) { + case 0: + print_text(4, 2, "Also avoid > and <.", text_speed); + progress++; + break; + case 1: + update_play(); + break; + } +} + void update_game() { switch (lvl) { case 0: intro(); break; + case 1: + lvl1(); + break; } } -/* - Todo: - - Restart - - Next Level -*/ +#ifdef CONSOLE int main(int argc, char **argv) { - // Dies zu programmieren mit der reduzierten Inputrate. - // Ist nicht angenehm. Ich werde es ändern....... - - // printf("%c", get_block(6, 23)); - // printf("%c", get_block(6, 24)); - - STARTUPINFOA si; - PROCESS_INFORMATION pi; - - ZeroMemory( &si, sizeof(si) ); - si.cb = sizeof(si); - ZeroMemory( &pi, sizeof(pi) ); - - //MessageBoxA(NULL, "Guten Tag.", "Spiel Name???", MB_OK); - - // Start the child process. - if( !CreateProcessA( NULL, // No module name (use command line) - "notepad.exe lvl/1.txt", // Command line - NULL, // Process handle not inheritable - NULL, // Thread handle not inheritable - FALSE, // Set handle inheritance to FALSE - 0, // No creation flags - NULL, // Use parent's environment block - NULL, // Use parent's starting directory - &si, // Pointer to STARTUPINFO structure - &pi ) // Pointer to PROCESS_INFORMATION structure - ) - { - printf( "CreateProcess failed (%d).\n", GetLastError() ); - return 0; +#else +int WinMain(HINSTANCE a0, HINSTANCE a1, LPSTR a2, int a3) { +#endif + start_notepad(); + if (hwnd_notepad == NULL || hwnd_edit == NULL) { + puts("error"); + return 1; } - - Sleep(100); - - hwnd = FindWindowA(NULL, "1.txt - Editor"); - - HRESULT hr; - BYTE dikeys[256]; - initializedirectinput8(); - createdikeyboard(); - - MSG Msg; - while (true) { - hr = keyboard->GetDeviceState(256, dikeys); - if (keydown(dikeys, DIK_ESCAPE)) { - TerminateProcess(pi.hProcess, 0); - //MessageBoxA(NULL, "beendet...", "Schönes Wochenende.", MB_OK); - break; - } - keys[0] = keydown(dikeys, DIK_LEFTARROW); - keys[1] = keydown(dikeys, DIK_RIGHTARROW); - keys[2] = keydown(dikeys, DIK_UPARROW); - - if (keys[0] && !keys_old[0]) press(VK_RIGHT); - if (keys[1] && !keys_old[1]) press(VK_LEFT); - if (keys[2] && !keys_old[2]) press(VK_DOWN); + load_level(0); + + while (true) { + //dt = ((double)clock() - game_clock) / CLOCKS_PER_SEC * 1000; + if (get_dur(game_clock) < frame_time) continue; + game_clock = clock(); + update_key_state(); + + if (key_pressed(Key::Exit)) + break; + if (key_pressed(Key::Redraw)) + redraw(); + update_game(); - keys_old[0] = keys[0]; - keys_old[1] = keys[1]; - keys_old[2] = keys[2]; - keys_old[3] = keys[3]; - - WaitForSingleObject( pi.hProcess, wait_time); - - SetWindowPos(hwnd, HWND_TOPMOST, 100, 100, 750, 750, SWP_SHOWWINDOW); + update_key_state_old(); } - - destroydikeyboard(); - - // Close process and thread handles. - CloseHandle( pi.hProcess ); - CloseHandle( pi.hThread ); + close_notepad(); return 0; } \ No newline at end of file