]> gitweb.ps.run Git - npengine/blob - src/main.cpp
pre double
[npengine] / src / main.cpp
1 #include <fstream>\r
2 #include <stdio.h>\r
3 #include <string>\r
4 #include <time.h>\r
5 #include <windows.h>\r
6 #include <Richedit.h>\r
7 \r
8 #pragma comment(lib, "user32.lib")\r
9 \r
10 #define CONSOLE\r
11 \r
12 #ifdef CONSOLE\r
13 #pragma comment(linker, "/subsystem:console")\r
14 #else\r
15 #pragma comment(linker, "/subsystem:windows")\r
16 #endif\r
17 \r
18 using namespace std;\r
19 \r
20 \r
21 const int WIDTH = 56, HEIGHT = 29;\r
22 \r
23 std::string map;\r
24 \r
25 clock_t game_clock;\r
26 double dt;\r
27 \r
28 // Edit\r
29 \r
30 HWND hwnd_notepad = NULL;\r
31 HWND hwnd_edit = NULL;\r
32 \r
33 string get_text() {\r
34   int len = SendMessageA(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);\r
35   char *buffer = new char[len + 1];\r
36   int read = SendMessageA(hwnd_edit, WM_GETTEXT, len + 1, (LPARAM)buffer);\r
37   if (read != len)\r
38     puts("???");\r
39   buffer[read] = 0;\r
40   string result(buffer);\r
41   delete[] buffer;\r
42   return result;\r
43 }\r
44 \r
45 void select_all() {\r
46   SendMessage(hwnd_edit, EM_SETSEL, 0, get_text().size());\r
47 }\r
48 \r
49 void select_length(int from, int length) {\r
50   SendMessage(hwnd_edit, EM_SETSEL, from, from + length);\r
51 }\r
52 \r
53 void select_from_to(int from, int to) {\r
54   SendMessage(hwnd_edit, EM_SETSEL, from, to);\r
55 }\r
56 \r
57 void replace(string str) {\r
58   SendMessage(hwnd_edit, EM_REPLACESEL, FALSE, (LPARAM)str.c_str());\r
59 }\r
60 \r
61 int get_pos(int x, int y) {\r
62   return (y + 1) * (WIDTH + 4) + x + 1;\r
63 }\r
64 \r
65 char get_block(int x, int y) {\r
66   return map[get_pos(x, y)];\r
67 }\r
68 \r
69 // Player\r
70 struct Player {\r
71   int x_screen = -1, y_screen = -1;\r
72   double x, y, x_vel, y_vel;\r
73 \r
74   void clear() {\r
75     if (x_screen < 0 || y_screen < 0) return;\r
76     int pos = get_pos(x_screen, y_screen);\r
77     select_length(pos, 1);\r
78     replace({ map[pos], 0 });\r
79   }\r
80   \r
81   void draw() {\r
82     if (collision_x(x - x_screen) || collision_y(y - y_screen)) {\r
83       x = x_screen;\r
84       y = y_screen;\r
85       return;\r
86     }\r
87     x_screen = round(x);\r
88     y_screen = round(y);\r
89     int pos = get_pos(x_screen, y_screen);\r
90     select_length(pos, 1);\r
91     replace({ 'Q', 0 });\r
92   }\r
93 \r
94   void update() {\r
95     x += x_vel;\r
96     y += y_vel;\r
97     if (!collision_y(1) && y_vel < 9)\r
98       y_vel += 1;\r
99     if (abs(x - x_screen) >= 1 || abs(x - x_screen) >= 1) {\r
100       clear();\r
101       draw();\r
102     }\r
103   }\r
104 \r
105   void move_to(int x, int y) {\r
106     clear();\r
107     this->x = x;\r
108     this->y = y;\r
109     draw();\r
110   }\r
111 \r
112   void move(int dx, int dy) {\r
113     move_to(x + dx, y + dy);\r
114   }\r
115 \r
116   bool collision_x(int n) {\r
117     if (x + n < 0 || x + n >= WIDTH)\r
118       return true;\r
119     for (int i = 0; i != n; i += (n < 0 ? -1 : 1))\r
120       if (get_block(x_screen + i + (n < 0 ? -1 : 1), y_screen) == 'X')\r
121         return true;\r
122     return false;\r
123   }\r
124   bool collision_y(int n) {\r
125     if (y + n < 0 || y + n >= HEIGHT)\r
126       return true;\r
127     for (int i = 0; i != n; i += (n < 0 ? -1 : 1))\r
128       if (get_block(x_screen, y_screen + i + (n < 0 ? -1 : 1)) == 'X')\r
129         return true;\r
130     return false;\r
131   }\r
132 };\r
133 Player player { 0, 0 };\r
134 \r
135 // Lvl\r
136 \r
137 std::string read_map(int lvl) {\r
138   std::ifstream ifs("lvl/" + std::to_string(lvl) + ".txt",\r
139                     std::ios::in | std::ios::binary);\r
140   if (!ifs.good())\r
141     puts("mist");\r
142   ifs.seekg(0, std::ios::end);\r
143   int length = ifs.tellg();\r
144   ifs.seekg(0, std::ios::beg);\r
145   char *buffer = new char[length + 1];\r
146   ifs.read(buffer, length);\r
147   ifs.close();\r
148   buffer[length] = 0;\r
149   std::string result(buffer);\r
150   delete buffer;\r
151   return result;\r
152 }\r
153 \r
154 void redraw() {\r
155   select_all();\r
156   replace(map);\r
157 }\r
158 \r
159 void load_level(int lvl) {\r
160   map = read_map(lvl);\r
161   redraw();\r
162   for (int x = 0; x < WIDTH; x++) {\r
163     for (int y = 0; y < HEIGHT; y++) {\r
164       if (map[get_pos(x, y)] == 'S')\r
165         player.move_to(x, y);\r
166     }\r
167   }\r
168 }\r
169 \r
170 // Notepad\r
171 \r
172 STARTUPINFOA si;\r
173 PROCESS_INFORMATION pi;\r
174 \r
175 BOOL CALLBACK ew_cb(HWND hwnd, LPARAM lp) {\r
176   DWORD pid;\r
177   DWORD tid = GetWindowThreadProcessId(hwnd, &pid);\r
178   if (pi.dwProcessId == pid && pi.dwThreadId == tid) {\r
179     hwnd_notepad = hwnd;\r
180     return false;\r
181   }\r
182   return true;\r
183 }\r
184 BOOL CALLBACK ecw_cb(HWND child, LPARAM in) {\r
185   char buffer[1024 + 1];\r
186   int len = GetClassNameA(child, buffer, 1024);\r
187   buffer[len] = 0;\r
188   if (strcmp(buffer, "Edit") == 0) {\r
189     hwnd_edit = child;\r
190     return false;\r
191   }\r
192   return true;\r
193 }\r
194 \r
195 void start_notepad() {\r
196   ZeroMemory(&si, sizeof(si));\r
197   si.cb = sizeof(si);\r
198   ZeroMemory(&pi, sizeof(pi));\r
199 \r
200   if (!CreateProcessA(NULL,  // No module name (use command line)\r
201                       "notepad.exe",   // Command line\r
202                       NULL,  // Process handle not inheritable\r
203                       NULL,  // Thread handle not inheritable\r
204                       FALSE, // Set handle inheritance to FALSE\r
205                       0,     // No creation flags\r
206                       NULL,  // Use parent's environment block\r
207                       NULL,  // Use parent's starting directory\r
208                       &si,   // Pointer to STARTUPINFO structure\r
209                       &pi)   // Pointer to PROCESS_INFORMATION structure\r
210   ) {\r
211     printf("CreateProcess failed (%d).\n", GetLastError());\r
212   }\r
213   Sleep(100);\r
214   EnumWindows(ew_cb, 0);\r
215   EnumChildWindows(hwnd_notepad, ecw_cb, 0);\r
216   SendMessage(hwnd_edit, EM_SETREADONLY, TRUE, NULL);\r
217 }\r
218 void close_notepad() {\r
219   TerminateProcess(pi.hProcess, 0);\r
220   CloseHandle(pi.hProcess);\r
221   CloseHandle(pi.hThread);\r
222 }\r
223 \r
224 // Keys\r
225 \r
226 enum class Key {\r
227   Left,\r
228   Right,\r
229   Jump,\r
230   Exit,\r
231   Redraw,\r
232   COUNT\r
233 };\r
234 \r
235 bool key_state[(uint64_t)Key::COUNT];\r
236 bool key_state_old[(uint64_t)Key::COUNT];\r
237 \r
238 int key_get_vk(Key key) {\r
239   switch (key) {\r
240     case Key::Left: return 'A';\r
241     case Key::Right: return 'D';\r
242     case Key::Jump: return VK_SPACE;\r
243     case Key::Exit: return VK_ESCAPE;\r
244     case Key::Redraw: return 'R';\r
245     default: return 0;\r
246   }\r
247 }\r
248 \r
249 void update_key_state() {\r
250   for (int i = 0; i < (int)Key::COUNT; i++) {\r
251     key_state[i] = GetAsyncKeyState(key_get_vk((Key)i));\r
252   }\r
253 }\r
254 \r
255 void update_key_state_old() {\r
256   for (int i = 0; i < (int)Key::COUNT; i++) {\r
257     key_state_old[i] = key_state[i];\r
258   }\r
259 }\r
260 \r
261 bool key_pressed(Key key) {\r
262   return key_state[(int)key] && !key_state_old[(int)key];\r
263 }\r
264 \r
265 bool key_down(Key key) {\r
266   return key_state[(int)key];\r
267 }\r
268 \r
269 bool key_up(Key key) {\r
270   return !key_state[(int)key];\r
271 }\r
272 \r
273 #ifdef CONSOLE\r
274 int main(int argc, char **argv) {\r
275 #else\r
276 int WinMain(HINSTANCE a0, HINSTANCE a1, LPSTR a2, int a3) {\r
277 #endif\r
278   start_notepad();\r
279   if (hwnd_notepad == NULL || hwnd_edit == NULL) {\r
280     puts("error");\r
281     return 1;\r
282   }\r
283   load_level(0);\r
284   while (true) {\r
285     dt = ((double)clock() - game_clock) / CLOCKS_PER_SEC * 1000;\r
286     game_clock = clock();\r
287     update_key_state();\r
288 \r
289     if (key_pressed(Key::Exit))\r
290       break;\r
291     if (key_pressed(Key::Redraw))\r
292       redraw();\r
293     if (key_down(Key::Left) && !player.collision_x(-1))\r
294       player.move(-1, 0);\r
295     if (key_down(Key::Right) && !player.collision_x(1))\r
296       player.move(+1, 0);\r
297     if (key_pressed(Key::Jump) && player.collision_y(1))\r
298       player.y_vel = -5;\r
299 \r
300     player.update();\r
301 \r
302     printf("%f %f\n", player.x, player.y);\r
303 \r
304     update_key_state_old();\r
305   }\r
306   close_notepad();\r
307 \r
308   return 0;\r
309 }