]> gitweb.ps.run Git - npengine/blobdiff - src/main.cpp
update for win11
[npengine] / src / main.cpp
index f6d131b075e131bae155d20c7df1a6b88c36b06b..61fda8fb4b6a9032eae185de053e6005508e6cc8 100644 (file)
@@ -1,5 +1,6 @@
 #include <fstream>\r
 #include <stdio.h>\r
+#include <stdint.h>\r
 #include <string>\r
 #include <time.h>\r
 #include <windows.h>\r
@@ -23,7 +24,16 @@ const int WIDTH = 56, HEIGHT = 29;
 std::string map;\r
 \r
 clock_t game_clock;\r
-double dt;\r
+double frame_time = 30;\r
+\r
+int lvl = 0;\r
+\r
+// Util\r
+\r
+double get_dur(clock_t then) {\r
+  double result = (double)(clock() - then) / CLOCKS_PER_SEC;\r
+  return result * 1000;\r
+}\r
 \r
 // Edit\r
 \r
@@ -32,13 +42,12 @@ HWND hwnd_edit = NULL;
 \r
 string get_text() {\r
   int len = SendMessageA(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);\r
-  char *buffer = new char[len + 1];\r
-  int read = SendMessageA(hwnd_edit, WM_GETTEXT, len + 1, (LPARAM)buffer);\r
+  string result;\r
+  result.resize(len + 1);\r
+  int read = SendMessageA(hwnd_edit, WM_GETTEXT, len + 1, (LPARAM)result.data());\r
   if (read != len)\r
     puts("???");\r
-  buffer[read] = 0;\r
-  string result(buffer);\r
-  delete[] buffer;\r
+  result.data()[read] = 0;\r
   return result;\r
 }\r
 \r
@@ -59,7 +68,7 @@ void replace(string str) {
 }\r
 \r
 int get_pos(int x, int y) {\r
-  return (y + 1) * (WIDTH + 4) + x + 1;\r
+  return (y + 1) * (WIDTH + 3) + x + 1;\r
 }\r
 \r
 char get_block(int x, int y) {\r
@@ -68,42 +77,27 @@ char get_block(int x, int y) {
 \r
 // Player\r
 struct Player {\r
-  int x_screen = -1, y_screen = -1;\r
-  double x, y, x_vel, y_vel;\r
+  bool left = false;\r
+  int x, y;\r
+  int x_spawn, y_spawn;\r
+  int jumping = 0;\r
 \r
   void clear() {\r
-    if (x_screen < 0 || y_screen < 0) return;\r
-    int pos = get_pos(x_screen, y_screen);\r
+    int pos = get_pos(x, y);\r
     select_length(pos, 1);\r
     replace({ map[pos], 0 });\r
   }\r
   \r
   void draw() {\r
-    if (collision_x(x - x_screen) || collision_y(y - y_screen)) {\r
-      x = x_screen;\r
-      y = y_screen;\r
-      return;\r
-    }\r
-    x_screen = round(x);\r
-    y_screen = round(y);\r
-    int pos = get_pos(x_screen, y_screen);\r
+    int pos = get_pos(x, y);\r
     select_length(pos, 1);\r
-    replace({ 'Q', 0 });\r
-  }\r
-\r
-  void update() {\r
-    x += x_vel;\r
-    y += y_vel;\r
-    if (!collision_y(1) && y_vel < 9)\r
-      y_vel += 1;\r
-    if (abs(x - x_screen) >= 1 || abs(x - x_screen) >= 1) {\r
-      clear();\r
-      draw();\r
-    }\r
+    replace({ left ? '<' : '>', 0 });\r
   }\r
 \r
   void move_to(int x, int y) {\r
     clear();\r
+    if (this->x > x) left = true;\r
+    if (this->x < x) left = false;\r
     this->x = x;\r
     this->y = y;\r
     draw();\r
@@ -117,7 +111,7 @@ struct Player {
     if (x + n < 0 || x + n >= WIDTH)\r
       return true;\r
     for (int i = 0; i != n; i += (n < 0 ? -1 : 1))\r
-      if (get_block(x_screen + i + (n < 0 ? -1 : 1), y_screen) == 'X')\r
+      if (get_block(x + i + (n < 0 ? -1 : 1), y) == 'X')\r
         return true;\r
     return false;\r
   }\r
@@ -125,7 +119,7 @@ struct Player {
     if (y + n < 0 || y + n >= HEIGHT)\r
       return true;\r
     for (int i = 0; i != n; i += (n < 0 ? -1 : 1))\r
-      if (get_block(x_screen, y_screen + i + (n < 0 ? -1 : 1)) == 'X')\r
+      if (get_block(x, y + i + (n < 0 ? -1 : 1)) == 'X')\r
         return true;\r
     return false;\r
   }\r
@@ -147,22 +141,28 @@ std::string read_map(int lvl) {
   ifs.close();\r
   buffer[length] = 0;\r
   std::string result(buffer);\r
-  delete buffer;\r
+  delete[] buffer;\r
   return result;\r
 }\r
 \r
 void redraw() {\r
   select_all();\r
   replace(map);\r
+  player.draw();\r
 }\r
 \r
-void load_level(int lvl) {\r
-  map = read_map(lvl);\r
+void load_level(int l) {\r
+  lvl = l;\r
+  map = read_map(l);\r
   redraw();\r
   for (int x = 0; x < WIDTH; x++) {\r
     for (int y = 0; y < HEIGHT; y++) {\r
-      if (map[get_pos(x, y)] == 'S')\r
+      if (map[get_pos(x, y)] == 'S') {\r
+        player.x_spawn = x;\r
+        player.y_spawn = y;\r
         player.move_to(x, y);\r
+        return;\r
+      }\r
     }\r
   }\r
 }\r
@@ -172,24 +172,10 @@ void load_level(int lvl) {
 STARTUPINFOA si;\r
 PROCESS_INFORMATION pi;\r
 \r
-BOOL CALLBACK ew_cb(HWND hwnd, LPARAM lp) {\r
-  DWORD pid;\r
-  DWORD tid = GetWindowThreadProcessId(hwnd, &pid);\r
-  if (pi.dwProcessId == pid && pi.dwThreadId == tid) {\r
-    hwnd_notepad = hwnd;\r
-    return false;\r
-  }\r
-  return true;\r
-}\r
-BOOL CALLBACK ecw_cb(HWND child, LPARAM in) {\r
-  char buffer[1024 + 1];\r
-  int len = GetClassNameA(child, buffer, 1024);\r
-  buffer[len] = 0;\r
-  if (strcmp(buffer, "Edit") == 0) {\r
-    hwnd_edit = child;\r
-    return false;\r
-  }\r
-  return true;\r
+bool check_class(HWND hwnd, const char *name) {\r
+    char b[64];\r
+    int n = GetClassNameA(hwnd, b, 64);\r
+    return (n && strncmp(b, name, n) == 0);\r
 }\r
 \r
 void start_notepad() {\r
@@ -198,7 +184,7 @@ void start_notepad() {
   ZeroMemory(&pi, sizeof(pi));\r
 \r
   if (!CreateProcessA(NULL,  // No module name (use command line)\r
-                      "notepad.exe",   // Command line\r
+                      "notepad.exe lvl/0.txt",   // Command line\r
                       NULL,  // Process handle not inheritable\r
                       NULL,  // Thread handle not inheritable\r
                       FALSE, // Set handle inheritance to FALSE\r
@@ -210,15 +196,44 @@ void start_notepad() {
   ) {\r
     printf("CreateProcess failed (%d).\n", GetLastError());\r
   }\r
-  Sleep(100);\r
-  EnumWindows(ew_cb, 0);\r
-  EnumChildWindows(hwnd_notepad, ecw_cb, 0);\r
+  Sleep(1000);\r
+  EnumWindows([](HWND hwnd, LPARAM lp)->BOOL{\r
+    if (check_class(hwnd, "Notepad")) {\r
+      *(HWND*)lp = hwnd;\r
+      return false;\r
+    }\r
+    return true;\r
+  }, (LPARAM)&hwnd_notepad);\r
+  EnumChildWindows(hwnd_notepad, [](HWND hwnd, LPARAM lp)->BOOL{\r
+    printf("looking at %p\n", hwnd);\r
+    if (check_class(hwnd, "NotepadTextBox")) {\r
+      EnumChildWindows(hwnd, [](HWND hwnd, LPARAM lp)->BOOL{\r
+        printf("  looking at %p\n", hwnd);\r
+        const size_t size = (WIDTH+4)*(HEIGHT+2);\r
+        char b[size];\r
+        DWORD_PTR dwResult;\r
+        b[0] = 0;\r
+        SendMessageTimeoutA(hwnd, WM_GETTEXT, size, (LPARAM)b,\r
+                SMTO_ABORTIFHUNG, 100, &dwResult);\r
+        if (b[0] == '+') {\r
+          // TODO: check lvl\r
+          printf("%.*s.\n", size, b);\r
+          *(HWND*)lp = hwnd;\r
+          return false;\r
+        }\r
+        return true;\r
+      }, lp);\r
+      if (lp) return false;\r
+    }\r
+    return true;\r
+  }, (LPARAM)&hwnd_edit);\r
   SendMessage(hwnd_edit, EM_SETREADONLY, TRUE, NULL);\r
 }\r
 void close_notepad() {\r
-  TerminateProcess(pi.hProcess, 0);\r
-  CloseHandle(pi.hProcess);\r
-  CloseHandle(pi.hThread);\r
+  SendMessage(hwnd_edit, EM_SETREADONLY, FALSE, NULL);\r
+  //TerminateProcess(pi.hProcess, 0);\r
+  //CloseHandle(pi.hProcess);\r
+  //CloseHandle(pi.hThread);\r
 }\r
 \r
 // Keys\r
@@ -270,6 +285,131 @@ bool key_up(Key key) {
   return !key_state[(int)key];\r
 }\r
 \r
+// Gameplay\r
+  \r
+clock_t jump_clock = clock();\r
+int jump_height = 3;\r
+double jump_time1 = 50;\r
+double jump_time2 = 100;\r
+int text_speed = 50;\r
+\r
+void update_play(bool can_jump = true, int x_min = 0, int x_max = WIDTH - 1) {\r
+  if (key_down(Key::Left) &&\r
+      !player.collision_x(-1) &&\r
+      player.x > x_min)\r
+      player.move(-1, 0);\r
+  if (key_down(Key::Right) &&\r
+      !player.collision_x(1) &&\r
+      player.x < x_max)\r
+    player.move(+1, 0);\r
+\r
+  if (key_pressed(Key::Jump) &&\r
+      can_jump &&\r
+      player.jumping == 0 &&\r
+      !player.collision_y(-1)) {\r
+    player.jumping = 1;\r
+    player.move(0, -1);\r
+    jump_clock = clock();\r
+  }\r
+  if (player.jumping != 0) {\r
+    if (player.jumping < jump_height && get_dur(jump_clock) > jump_time1) {\r
+      if (!player.collision_y(-1)) {\r
+        player.move(0, -1);\r
+        player.jumping++;\r
+        jump_clock = clock();\r
+      } else {\r
+        player.jumping = jump_height;\r
+      }\r
+    } else if (player.jumping == jump_height && get_dur(jump_clock) > jump_time2) {\r
+      player.jumping = 0;\r
+    }\r
+  }\r
+  if (!player.jumping && !player.collision_y(1))\r
+    player.move(0, +1);\r
+\r
+  char b = get_block(player.x, player.y);\r
+  if (b == '/' || b == '\\' || b == '<' || b == '>')\r
+    player.move_to(player.x_spawn, player.y_spawn);\r
+}\r
+\r
+void print_text(int x, int y, string text, int delay) {\r
+  for (int i = 0; i < text.size(); i++) {\r
+    select_length(get_pos(x + i, y), 1);\r
+    replace(text.substr(i, 1));\r
+    Sleep(delay);\r
+  }\r
+}\r
+\r
+void intro() {\r
+  static int progress = 0;\r
+  switch (progress) {\r
+  case 0:\r
+    print_text(4, 2, "Move with A/D.", text_speed);\r
+\r
+    progress++;\r
+    break;\r
+  case 1:\r
+    update_play(false);\r
+    if (player.x == 17) {\r
+      print_text(4, 4, "Jump with up.", text_speed);\r
+      print_text(4, 6, "Stand on x.", text_speed);\r
+      progress++;\r
+    }\r
+    break;\r
+  case 2:\r
+    update_play();\r
+    if (player.x == 22) {\r
+      print_text(4, 8, "Collect ? for ???.", text_speed);\r
+      progress++;\r
+    }\r
+    break;\r
+  case 3:\r
+    update_play(true, 0, 33);\r
+    if (get_block(player.x, player.y) == '?') {\r
+      print_text(4, 10, "Avoid /\\.", text_speed);\r
+      progress++;\r
+    }\r
+    break;\r
+  case 4:\r
+    update_play();\r
+    if (player.x == 39) {\r
+      print_text(4, 14, "Finish lvl by reaching O.", text_speed);\r
+      progress++;\r
+    }\r
+    break;\r
+  case 5:\r
+    update_play();\r
+    if (get_block(player.x, player.y) == 'O') {\r
+      load_level(1);\r
+    }\r
+    break;\r
+  }\r
+}\r
+\r
+void lvl1() {\r
+  static int progress = 0;\r
+  switch (progress) {\r
+  case 0:\r
+    print_text(4, 2, "Also avoid > and <.", text_speed);\r
+    progress++;\r
+    break;\r
+  case 1:\r
+    update_play();\r
+    break;\r
+  }\r
+}\r
+\r
+void update_game() {\r
+  switch (lvl) {\r
+  case 0:\r
+    intro();\r
+    break;\r
+  case 1:\r
+    lvl1();\r
+    break;\r
+  }\r
+}\r
+\r
 #ifdef CONSOLE\r
 int main(int argc, char **argv) {\r
 #else\r
@@ -280,9 +420,12 @@ int WinMain(HINSTANCE a0, HINSTANCE a1, LPSTR a2, int a3) {
     puts("error");\r
     return 1;\r
   }\r
+\r
   load_level(0);\r
+  \r
   while (true) {\r
-    dt = ((double)clock() - game_clock) / CLOCKS_PER_SEC * 1000;\r
+    //dt = ((double)clock() - game_clock) / CLOCKS_PER_SEC * 1000;\r
+    if (get_dur(game_clock) < frame_time) continue;\r
     game_clock = clock();\r
     update_key_state();\r
 \r
@@ -290,20 +433,12 @@ int WinMain(HINSTANCE a0, HINSTANCE a1, LPSTR a2, int a3) {
       break;\r
     if (key_pressed(Key::Redraw))\r
       redraw();\r
-    if (key_down(Key::Left) && !player.collision_x(-1))\r
-      player.move(-1, 0);\r
-    if (key_down(Key::Right) && !player.collision_x(1))\r
-      player.move(+1, 0);\r
-    if (key_pressed(Key::Jump) && player.collision_y(1))\r
-      player.y_vel = -5;\r
-\r
-    player.update();\r
-\r
-    printf("%f %f\n", player.x, player.y);\r
+    \r
+    update_game();\r
 \r
     update_key_state_old();\r
   }\r
   close_notepad();\r
 \r
   return 0;\r
-}
\ No newline at end of file
+}\r