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