]> 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, y;\r
72 \r
73   void clear() {\r
74     int pos = get_pos(x, y);\r
75     select_length(pos, 1);\r
76     replace({ map[pos], 0 });\r
77   }\r
78   \r
79   void draw() {\r
80     int pos = get_pos(x, y);\r
81     select_length(pos, 1);\r
82     replace({ 'Q', 0 });\r
83   }\r
84 \r
85   void move_to(int x, int y) {\r
86     clear();\r
87     this->x = x;\r
88     this->y = y;\r
89     draw();\r
90   }\r
91 \r
92   void move(int dx, int dy) {\r
93     move_to(x + dx, y + dy);\r
94   }\r
95 \r
96   bool collision(int xdir, int ydir) {\r
97     int newx = x + xdir;\r
98     int newy = y + ydir;\r
99     if (newx < 0 || newx >= WIDTH || newy < 0 || newy >= HEIGHT)\r
100       return true;\r
101     return get_block(newx, newy) == 'X';\r
102   }\r
103 };\r
104 Player player { 0, 0 };\r
105 \r
106 // Lvl\r
107 \r
108 std::string read_map(int lvl) {\r
109   std::ifstream ifs("lvl/" + std::to_string(lvl) + ".txt",\r
110                     std::ios::in | std::ios::binary);\r
111   if (!ifs.good())\r
112     puts("mist");\r
113   ifs.seekg(0, std::ios::end);\r
114   int length = ifs.tellg();\r
115   ifs.seekg(0, std::ios::beg);\r
116   char *buffer = new char[length + 1];\r
117   ifs.read(buffer, length);\r
118   ifs.close();\r
119   buffer[length] = 0;\r
120   std::string result(buffer);\r
121   delete buffer;\r
122   return result;\r
123 }\r
124 \r
125 void redraw() {\r
126   select_all();\r
127   replace(map);\r
128 }\r
129 \r
130 void load_level(int lvl) {\r
131   map = read_map(lvl);\r
132   redraw();\r
133   for (int x = 0; x < WIDTH; x++) {\r
134     for (int y = 0; y < HEIGHT; y++) {\r
135       if (map[get_pos(x, y)] == 'S')\r
136         player.move_to(x, y);\r
137     }\r
138   }\r
139 }\r
140 \r
141 // Notepad\r
142 \r
143 STARTUPINFOA si;\r
144 PROCESS_INFORMATION pi;\r
145 \r
146 BOOL CALLBACK ew_cb(HWND hwnd, LPARAM lp) {\r
147   DWORD pid;\r
148   DWORD tid = GetWindowThreadProcessId(hwnd, &pid);\r
149   if (pi.dwProcessId == pid && pi.dwThreadId == tid) {\r
150     hwnd_notepad = hwnd;\r
151     return false;\r
152   }\r
153   return true;\r
154 }\r
155 BOOL CALLBACK ecw_cb(HWND child, LPARAM in) {\r
156   char buffer[1024 + 1];\r
157   int len = GetClassNameA(child, buffer, 1024);\r
158   buffer[len] = 0;\r
159   if (strcmp(buffer, "Edit") == 0) {\r
160     hwnd_edit = child;\r
161     return false;\r
162   }\r
163   return true;\r
164 }\r
165 \r
166 void start_notepad() {\r
167   ZeroMemory(&si, sizeof(si));\r
168   si.cb = sizeof(si);\r
169   ZeroMemory(&pi, sizeof(pi));\r
170 \r
171   if (!CreateProcessA(NULL,  // No module name (use command line)\r
172                       "notepad.exe",   // Command line\r
173                       NULL,  // Process handle not inheritable\r
174                       NULL,  // Thread handle not inheritable\r
175                       FALSE, // Set handle inheritance to FALSE\r
176                       0,     // No creation flags\r
177                       NULL,  // Use parent's environment block\r
178                       NULL,  // Use parent's starting directory\r
179                       &si,   // Pointer to STARTUPINFO structure\r
180                       &pi)   // Pointer to PROCESS_INFORMATION structure\r
181   ) {\r
182     printf("CreateProcess failed (%d).\n", GetLastError());\r
183   }\r
184   Sleep(100);\r
185   EnumWindows(ew_cb, 0);\r
186   EnumChildWindows(hwnd_notepad, ecw_cb, 0);\r
187   SendMessage(hwnd_edit, EM_SETREADONLY, TRUE, NULL);\r
188 }\r
189 void close_notepad() {\r
190   TerminateProcess(pi.hProcess, 0);\r
191   CloseHandle(pi.hProcess);\r
192   CloseHandle(pi.hThread);\r
193 }\r
194 \r
195 // Keys\r
196 \r
197 enum class Key {\r
198   Left,\r
199   Right,\r
200   Jump,\r
201   Exit,\r
202   Redraw,\r
203   COUNT\r
204 };\r
205 \r
206 bool key_state[(uint64_t)Key::COUNT];\r
207 bool key_state_old[(uint64_t)Key::COUNT];\r
208 \r
209 int key_get_vk(Key key) {\r
210   switch (key) {\r
211     case Key::Left: return 'A';\r
212     case Key::Right: return 'D';\r
213     case Key::Jump: return VK_SPACE;\r
214     case Key::Exit: return VK_ESCAPE;\r
215     case Key::Redraw: return 'R';\r
216     default: return 0;\r
217   }\r
218 }\r
219 \r
220 void update_key_state() {\r
221   for (int i = 0; i < (int)Key::COUNT; i++) {\r
222     key_state[i] = GetAsyncKeyState(key_get_vk((Key)i));\r
223   }\r
224 }\r
225 \r
226 void update_key_state_old() {\r
227   for (int i = 0; i < (int)Key::COUNT; i++) {\r
228     key_state_old[i] = key_state[i];\r
229   }\r
230 }\r
231 \r
232 bool key_pressed(Key key) {\r
233   return key_state[(int)key] && !key_state_old[(int)key];\r
234 }\r
235 \r
236 bool key_down(Key key) {\r
237   return key_state[(int)key];\r
238 }\r
239 \r
240 bool key_up(Key key) {\r
241   return !key_state[(int)key];\r
242 }\r
243 \r
244 #ifdef CONSOLE\r
245 int main(int argc, char **argv) {\r
246 #else\r
247 int WinMain(HINSTANCE a0, HINSTANCE a1, LPSTR a2, int a3) {\r
248 #endif\r
249   start_notepad();\r
250   if (hwnd_notepad == NULL || hwnd_edit == NULL) {\r
251     puts("error");\r
252     return 1;\r
253   }\r
254   load_level(0);\r
255   while (true) {\r
256     dt = ((double)clock() - game_clock) / CLOCKS_PER_SEC * 1000;\r
257     game_clock = clock();\r
258     update_key_state();\r
259 \r
260     if (key_pressed(Key::Exit))\r
261       break;\r
262     if (key_pressed(Key::Redraw))\r
263       redraw();\r
264     if (key_down(Key::Left) && !player.collision(-1, 0))\r
265       player.move(-1, 0);\r
266     if (key_down(Key::Right) && !player.collision(1, 0))\r
267       player.move(+1, 0);\r
268     if (key_pressed(Key::Jump) && player.collision(0, 1))\r
269       player.move(0, -1);\r
270 \r
271     update_key_state_old();\r
272   }\r
273   close_notepad();\r
274 \r
275   return 0;\r
276 }