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