]> gitweb.ps.run Git - npengine/blob - src/main.cpp
4c7d99d4598e467d228d779e7f64e416b0df93ec
[npengine] / src / main.cpp
1 #define DIRECTINPUT_VERSION 0x0800\r
2 #include <dinput.h>\r
3 #include <fstream>\r
4 #include <stdio.h>\r
5 #include <string>\r
6 #include <time.h>\r
7 #include <windows.h>\r
8 \r
9 #pragma comment(lib, "user32.lib")\r
10 #pragma comment(lib, "dinput8.lib")\r
11 #pragma comment(lib, "dxguid.lib")\r
12 \r
13 HWND hwnd = NULL;\r
14 \r
15 STARTUPINFOA si;\r
16 PROCESS_INFORMATION pi;\r
17 \r
18 const int WIDTH = 56, HEIGHT = 29;\r
19 int x = 0, y = 0;\r
20 int spawn_x, spawn_y;\r
21 bool right = true;\r
22 \r
23 clock_t update_clock = clock();\r
24 double update_time = 40;\r
25 \r
26 BYTE dikeys[256];\r
27 bool keys[4] = {false, false, false, false};\r
28 bool keys_old[4] = {false, false, false, false};\r
29 \r
30 int jumping = 0;\r
31 \r
32 clock_t jump_clock = clock();\r
33 double jump_time1 = 50;\r
34 double jump_time2 = 100;\r
35 int jump_height = 3;\r
36 \r
37 DWORD wait_time = 10;\r
38 \r
39 int text_speed = 2;\r
40 \r
41 std::string map;\r
42 \r
43 void press_down(WORD vk) {\r
44   INPUT ip;\r
45 \r
46   ip.type = INPUT_KEYBOARD;\r
47   ip.ki.wScan = 0;\r
48   ip.ki.time = 0;\r
49   ip.ki.dwExtraInfo = 0;\r
50 \r
51   ip.ki.wVk = vk;\r
52   ip.ki.dwFlags = 0;\r
53   SendInput(1, &ip, sizeof(INPUT));\r
54 }\r
55 \r
56 void press_up(WORD vk) {\r
57   INPUT ip;\r
58   ip.type = INPUT_KEYBOARD;\r
59   ip.ki.wScan = 0;\r
60   ip.ki.time = 0;\r
61   ip.ki.dwExtraInfo = 0;\r
62 \r
63   ip.ki.wVk = vk;\r
64   ip.ki.dwFlags = KEYEVENTF_KEYUP;\r
65   SendInput(1, &ip, sizeof(INPUT));\r
66 }\r
67 \r
68 void press(WORD vk) {\r
69   press_down(vk);\r
70   press_up(vk);\r
71 }\r
72 \r
73 void key_down(char c) {\r
74   INPUT ip;\r
75   ip.type = INPUT_KEYBOARD;\r
76   ip.ki.time = 0;\r
77   ip.ki.dwExtraInfo = 0;\r
78 \r
79   ip.ki.dwFlags = KEYEVENTF_UNICODE;\r
80   ip.ki.wVk = 0;\r
81   ip.ki.wScan = c;\r
82   SendInput(1, &ip, sizeof(INPUT));\r
83 }\r
84 \r
85 void key_up(char c) {\r
86   INPUT ip;\r
87   ip.type = INPUT_KEYBOARD;\r
88   ip.ki.time = 0;\r
89   ip.ki.dwExtraInfo = 0;\r
90 \r
91   // Release key\r
92   ip.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;\r
93   SendInput(1, &ip, sizeof(INPUT));\r
94 }\r
95 \r
96 void key(char c) {\r
97   key_down(c);\r
98   key_up(c);\r
99 }\r
100 \r
101 LPDIRECTINPUT8 di;\r
102 LPDIRECTINPUTDEVICE8 keyboard;\r
103 \r
104 HRESULT initializedirectinput8() {\r
105   HRESULT hr;\r
106   // Create a DirectInput device\r
107   if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,\r
108                                      IID_IDirectInput8, (VOID **)&di, NULL))) {\r
109     return hr;\r
110   }\r
111   return 0;\r
112 }\r
113 \r
114 void createdikeyboard() {\r
115   di->CreateDevice(GUID_SysKeyboard, &keyboard, NULL);\r
116   keyboard->SetDataFormat(&c_dfDIKeyboard);\r
117   keyboard->SetCooperativeLevel(NULL, DISCL_FOREGROUND | DISCL_EXCLUSIVE);\r
118   keyboard->Acquire();\r
119 }\r
120 \r
121 void destroydikeyboard() {\r
122   keyboard->Unacquire();\r
123   keyboard->Release();\r
124 }\r
125 \r
126 #define keydown(name, key) (name[key] & 0x80)\r
127 \r
128 std::string read_map(int lvl) {\r
129   std::ifstream ifs("lvl/" + std::to_string(lvl) + ".txt",\r
130                     std::ios::in | std::ios::binary);\r
131   if (!ifs.good())\r
132     puts("mist");\r
133   ifs.seekg(0, std::ios::end);\r
134   int length = ifs.tellg();\r
135   ifs.seekg(0, std::ios::beg);\r
136   char *buffer = new char[length + 1];\r
137   ifs.read(buffer, length);\r
138   ifs.close();\r
139   buffer[length] = 0;\r
140   std::string result(buffer);\r
141   delete buffer;\r
142   return result;\r
143 }\r
144 \r
145 char get_block(int x, int y) {\r
146   char result = map[(y + 1) * (WIDTH + 4) + x + 1];\r
147   return result;\r
148 }\r
149 \r
150 double get_dur(clock_t then) {\r
151   double result = (double)(clock() - then) / CLOCKS_PER_SEC;\r
152   return result * 1000;\r
153 }\r
154 \r
155 void draw() {\r
156   press(VK_BACK);\r
157   key(right ? '>' : '<');\r
158 }\r
159 \r
160 void erase() {\r
161   press(VK_BACK);\r
162   key(get_block(x, y));\r
163 }\r
164 \r
165 void move(int dx, int dy) {\r
166   erase();\r
167 \r
168   for (int i = 0; i < dx; i++) {\r
169     right = true;\r
170     press(VK_RIGHT);\r
171   }\r
172   for (int i = 0; i > dx; i--) {\r
173     right = false;\r
174     press(VK_LEFT);\r
175   }\r
176   for (int i = 0; i < dy; i++) {\r
177     press(VK_DOWN);\r
178   }\r
179   for (int i = 0; i > dy; i--) {\r
180     press(VK_UP);\r
181   }\r
182 \r
183   draw();\r
184 \r
185   x += dx;\r
186   y += dy;\r
187 \r
188   printf("%d %d\n", x, y);\r
189 }\r
190 \r
191 void move_to(int _x, int _y) { move(_x - x, _y - y); }\r
192 \r
193 void print_text(int text_x, int text_y, const char *text, int delay,\r
194                 bool move = true) {\r
195   if (move) {\r
196     for (int i = x; i < text_x; i++)\r
197       press(VK_RIGHT);\r
198     for (int i = x; i > text_x; i--)\r
199       press(VK_LEFT);\r
200     for (int i = y; i < text_y; i++)\r
201       press(VK_DOWN);\r
202     for (int i = y; i > text_y; i--)\r
203       press(VK_UP);\r
204   }\r
205 \r
206   int len = strlen(text);\r
207   for (int i = 0; i < len; i++) {\r
208     if (text[i] == '\r')\r
209       continue;\r
210     press(VK_DELETE);\r
211     key(text[i]);\r
212     if (move) {\r
213       map[(text_y + 1) * (WIDTH + 4) + text_x + 1 + i] = text[i];\r
214     }\r
215     Sleep(delay);\r
216   }\r
217   if (move) {\r
218     for (int i = text_x + len; i < x; i++)\r
219       press(VK_RIGHT);\r
220     for (int i = text_x + len; i > x; i--)\r
221       press(VK_LEFT);\r
222     for (int i = text_y; i < y; i++)\r
223       press(VK_DOWN);\r
224     for (int i = text_y; i > y; i--)\r
225       press(VK_UP);\r
226   }\r
227 \r
228   draw();\r
229 \r
230   Sleep(100);\r
231 }\r
232 \r
233 void update_play(bool can_jump = true, int x_min = 0, int x_max = WIDTH - 1) {\r
234   if (get_dur(update_clock) >= update_time) {\r
235     update_clock = clock();\r
236 \r
237     if (keys[0] && x > x_min && get_block(x - 1, y) != 'X')\r
238       move(-1, 0);\r
239     if (keys[1] && x < x_max && get_block(x + 1, y) != 'X')\r
240       move(+1, 0);\r
241   }\r
242 \r
243   if (keys[2] && !keys_old[2] && jumping == 0 && can_jump) {\r
244     jumping = 1;\r
245     move(0, -1);\r
246     jump_clock = clock();\r
247   }\r
248   if (jumping != 0) {\r
249     if (jumping < jump_height && get_dur(jump_clock) > jump_time1) {\r
250       if (get_block(x, y - 1) != 'X') {\r
251         move(0, -1);\r
252         jumping++;\r
253         jump_clock = clock();\r
254       } else {\r
255         jumping = jump_height;\r
256       }\r
257     } else if (jumping == jump_height && get_dur(jump_clock) > jump_time2) {\r
258       jumping = 0;\r
259     }\r
260   }\r
261   if (!jumping && get_block(x, y + 1) != 'X' && y < HEIGHT - 1)\r
262     move(0, +1);\r
263 \r
264   char b = get_block(x, y);\r
265   if (b == '/' || b == '\\' || b == '-')\r
266     move_to(spawn_x, spawn_y);\r
267 }\r
268 \r
269 void redraw() {\r
270   press_down(VK_CONTROL);\r
271   press('A');\r
272   press_up(VK_CONTROL);\r
273   Sleep(100);\r
274   press(VK_DELETE);\r
275   Sleep(100);\r
276   int _x = x, _y = y;\r
277   print_text(0, 0, map.c_str(), 1, false);\r
278   for (int i = 0; i < 100; i++)\r
279     press(VK_UP);\r
280   for (int i = 0; i < 100; i++)\r
281     press(VK_LEFT);\r
282   x = y = 0;\r
283   press(VK_DOWN);\r
284   press(VK_RIGHT);\r
285   press(VK_RIGHT);\r
286   move_to(_x, _y);\r
287 }\r
288 \r
289 int lvl = 0;\r
290 \r
291 void setup() {\r
292   x = y = 0;\r
293   press(VK_DOWN);\r
294   press(VK_RIGHT);\r
295   press(VK_RIGHT);\r
296 \r
297   for (int i = 0; i < WIDTH; i++)\r
298     for (int j = 0; j < HEIGHT; j++)\r
299       if (get_block(i, j) == 'S') {\r
300         spawn_x = i;\r
301         spawn_y = j;\r
302       }\r
303       \r
304   move_to(spawn_x, spawn_y);\r
305 }\r
306 \r
307 void load_level(int l, bool terminate = true) {\r
308   lvl = l;\r
309   map = read_map(lvl);\r
310   if (terminate)\r
311     TerminateProcess(pi.hProcess, 0);\r
312 \r
313   char cmd[100];\r
314   sprintf(cmd, "notepad.exe lvl/%d.txt", lvl);\r
315 \r
316   if (!CreateProcessA(NULL,  // No module name (use command line)\r
317                       cmd,   // Command line\r
318                       NULL,  // Process handle not inheritable\r
319                       NULL,  // Thread handle not inheritable\r
320                       FALSE, // Set handle inheritance to FALSE\r
321                       0,     // No creation flags\r
322                       NULL,  // Use parent's environment block\r
323                       NULL,  // Use parent's starting directory\r
324                       &si,   // Pointer to STARTUPINFO structure\r
325                       &pi)   // Pointer to PROCESS_INFORMATION structure\r
326   ) {\r
327     printf("CreateProcess failed (%d).\n", GetLastError());\r
328     return;\r
329   }\r
330 \r
331   Sleep(100);\r
332 \r
333   char title[100];\r
334   sprintf(title, "%d.txt - Editor", lvl);\r
335   hwnd = FindWindowA(NULL, title);\r
336 \r
337   setup();\r
338 }\r
339 \r
340 void intro() {\r
341   static int progress = 0;\r
342   switch (progress) {\r
343   case 0:\r
344     print_text(4, 2, "Move with left/right.", text_speed);\r
345 \r
346     progress++;\r
347     break;\r
348   case 1:\r
349     update_play(false);\r
350     if (x == 5) {\r
351       print_text(4, 4, "Jump with up.", text_speed);\r
352       print_text(4, 6, "Stand on x.", text_speed);\r
353       progress++;\r
354     }\r
355     break;\r
356   case 2:\r
357     update_play();\r
358     if (x == 8) {\r
359       print_text(4, 8, "Collect ? for ???.", text_speed);\r
360       progress++;\r
361     }\r
362     break;\r
363   case 3:\r
364     update_play(true, 0, 22);\r
365     if (get_block(x, y) == '?') {\r
366       print_text(4, 10, "Avoid /\\.", text_speed);\r
367       progress++;\r
368     }\r
369     break;\r
370   case 4:\r
371     update_play();\r
372     if (x == 39) {\r
373       print_text(4, 14, "Finish lvl by reaching O.", text_speed);\r
374       progress++;\r
375     }\r
376     break;\r
377   case 5:\r
378     update_play();\r
379     if (get_block(x, y) == 'O') {\r
380       load_level(1);\r
381     }\r
382     break;\r
383   }\r
384 }\r
385 \r
386 void lvl1() { update_play(); }\r
387 \r
388 void update_game() {\r
389   switch (lvl) {\r
390   case 0:\r
391     intro();\r
392     break;\r
393   case 1:\r
394     lvl1();\r
395     break;\r
396   }\r
397 }\r
398 \r
399 /*\r
400   Todo:\r
401   - Msg Box Intro\r
402   - Multi Jump\r
403   - more blocks/lvls\r
404   - Set Accessibility \r
405 */\r
406 int main(int argc, char **argv) {\r
407   // Dies zu programmieren mit der reduzierten Inputrate.\r
408   // Ist nicht angenehm. Ich werde es ändern.......\r
409 \r
410   // printf("%c", get_block(6, 23));\r
411   // printf("%c", get_block(6, 24));\r
412 \r
413   ZeroMemory(&si, sizeof(si));\r
414   si.cb = sizeof(si);\r
415   ZeroMemory(&pi, sizeof(pi));\r
416 \r
417   // MessageBoxA(NULL, "Guten Tag.", "Spiel Name???", MB_OK);\r
418 \r
419   HRESULT hr;\r
420   initializedirectinput8();\r
421   createdikeyboard();\r
422 \r
423   load_level(0, false);\r
424 \r
425   MSG Msg;\r
426   while (true) {\r
427     hr = keyboard->GetDeviceState(256, dikeys);\r
428     if (keydown(dikeys, DIK_ESCAPE)) {\r
429       TerminateProcess(pi.hProcess, 0);\r
430       // MessageBoxA(NULL, "beendet...", "Schönes Wochenende.", MB_OK);\r
431       break;\r
432     }\r
433     if (keydown(dikeys, DIK_R)) {\r
434       redraw();\r
435     }\r
436     keys[0] = keydown(dikeys, DIK_LEFTARROW);\r
437     keys[1] = keydown(dikeys, DIK_RIGHTARROW);\r
438     keys[2] = keydown(dikeys, DIK_UPARROW);\r
439 \r
440     if (keys[0] && !keys_old[0])\r
441       press(VK_RIGHT);\r
442     if (keys[1] && !keys_old[1])\r
443       press(VK_LEFT);\r
444     if (keys[2] && !keys_old[2])\r
445       press(VK_DOWN);\r
446 \r
447     update_game();\r
448 \r
449     keys_old[0] = keys[0];\r
450     keys_old[1] = keys[1];\r
451     keys_old[2] = keys[2];\r
452     keys_old[3] = keys[3];\r
453 \r
454     WaitForSingleObject(pi.hProcess, wait_time);\r
455 \r
456     SetWindowPos(hwnd, HWND_TOPMOST, 100, 100, 500, 500, SWP_SHOWWINDOW);\r
457   }\r
458 \r
459   destroydikeyboard();\r
460 \r
461   // Close process and thread handles.\r
462   CloseHandle(pi.hProcess);\r
463   CloseHandle(pi.hThread);\r
464 \r
465   return 0;\r
466 }