6 #include <Richedit.h>
\r
8 #pragma comment(lib, "user32.lib")
\r
13 #pragma comment(linker, "/subsystem:console")
\r
15 #pragma comment(linker, "/subsystem:windows")
\r
18 using namespace std;
\r
21 const int WIDTH = 56, HEIGHT = 29;
\r
26 double frame_time = 30;
\r
32 double get_dur(clock_t then) {
\r
33 double result = (double)(clock() - then) / CLOCKS_PER_SEC;
\r
34 return result * 1000;
\r
39 HWND hwnd_notepad = NULL;
\r
40 HWND hwnd_edit = NULL;
\r
43 int len = SendMessageA(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
\r
44 char *buffer = new char[len + 1];
\r
45 int read = SendMessageA(hwnd_edit, WM_GETTEXT, len + 1, (LPARAM)buffer);
\r
49 string result(buffer);
\r
55 SendMessage(hwnd_edit, EM_SETSEL, 0, get_text().size());
\r
58 void select_length(int from, int length) {
\r
59 SendMessage(hwnd_edit, EM_SETSEL, from, from + length);
\r
62 void select_from_to(int from, int to) {
\r
63 SendMessage(hwnd_edit, EM_SETSEL, from, to);
\r
66 void replace(string str) {
\r
67 SendMessage(hwnd_edit, EM_REPLACESEL, FALSE, (LPARAM)str.c_str());
\r
70 int get_pos(int x, int y) {
\r
71 return (y + 1) * (WIDTH + 4) + x + 1;
\r
74 char get_block(int x, int y) {
\r
75 return map[get_pos(x, y)];
\r
82 int x_spawn, y_spawn;
\r
86 int pos = get_pos(x, y);
\r
87 select_length(pos, 1);
\r
88 replace({ map[pos], 0 });
\r
92 int pos = get_pos(x, y);
\r
93 select_length(pos, 1);
\r
94 replace({ left ? '<' : '>', 0 });
\r
97 void move_to(int x, int y) {
\r
99 if (this->x > x) left = true;
\r
100 if (this->x < x) left = false;
\r
106 void move(int dx, int dy) {
\r
107 move_to(x + dx, y + dy);
\r
110 bool collision_x(int n) {
\r
111 if (x + n < 0 || x + n >= WIDTH)
\r
113 for (int i = 0; i != n; i += (n < 0 ? -1 : 1))
\r
114 if (get_block(x + i + (n < 0 ? -1 : 1), y) == 'X')
\r
118 bool collision_y(int n) {
\r
119 if (y + n < 0 || y + n >= HEIGHT)
\r
121 for (int i = 0; i != n; i += (n < 0 ? -1 : 1))
\r
122 if (get_block(x, y + i + (n < 0 ? -1 : 1)) == 'X')
\r
127 Player player { 0, 0 };
\r
131 std::string read_map(int lvl) {
\r
132 std::ifstream ifs("lvl/" + std::to_string(lvl) + ".txt",
\r
133 std::ios::in | std::ios::binary);
\r
136 ifs.seekg(0, std::ios::end);
\r
137 int length = ifs.tellg();
\r
138 ifs.seekg(0, std::ios::beg);
\r
139 char *buffer = new char[length + 1];
\r
140 ifs.read(buffer, length);
\r
142 buffer[length] = 0;
\r
143 std::string result(buffer);
\r
154 void load_level(int l) {
\r
158 for (int x = 0; x < WIDTH; x++) {
\r
159 for (int y = 0; y < HEIGHT; y++) {
\r
160 if (map[get_pos(x, y)] == 'S') {
\r
161 player.x_spawn = x;
\r
162 player.y_spawn = y;
\r
163 player.move_to(x, y);
\r
173 PROCESS_INFORMATION pi;
\r
175 BOOL CALLBACK ew_cb(HWND hwnd, LPARAM lp) {
\r
177 DWORD tid = GetWindowThreadProcessId(hwnd, &pid);
\r
178 if (pi.dwProcessId == pid && pi.dwThreadId == tid) {
\r
179 hwnd_notepad = hwnd;
\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
188 if (strcmp(buffer, "Edit") == 0) {
\r
195 void start_notepad() {
\r
196 ZeroMemory(&si, sizeof(si));
\r
197 si.cb = sizeof(si);
\r
198 ZeroMemory(&pi, sizeof(pi));
\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
211 printf("CreateProcess failed (%d).\n", GetLastError());
\r
214 EnumWindows(ew_cb, 0);
\r
215 EnumChildWindows(hwnd_notepad, ecw_cb, 0);
\r
216 SendMessage(hwnd_edit, EM_SETREADONLY, TRUE, NULL);
\r
218 void close_notepad() {
\r
219 TerminateProcess(pi.hProcess, 0);
\r
220 CloseHandle(pi.hProcess);
\r
221 CloseHandle(pi.hThread);
\r
235 bool key_state[(uint64_t)Key::COUNT];
\r
236 bool key_state_old[(uint64_t)Key::COUNT];
\r
238 int key_get_vk(Key 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
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
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
261 bool key_pressed(Key key) {
\r
262 return key_state[(int)key] && !key_state_old[(int)key];
\r
265 bool key_down(Key key) {
\r
266 return key_state[(int)key];
\r
269 bool key_up(Key key) {
\r
270 return !key_state[(int)key];
\r
275 clock_t jump_clock = clock();
\r
276 int jump_height = 3;
\r
277 double jump_time1 = 50;
\r
278 double jump_time2 = 100;
\r
279 int text_speed = 50;
\r
281 void update_play(bool can_jump = true, int x_min = 0, int x_max = WIDTH - 1) {
\r
282 if (key_down(Key::Left) &&
\r
283 !player.collision_x(-1) &&
\r
285 player.move(-1, 0);
\r
286 if (key_down(Key::Right) &&
\r
287 !player.collision_x(1) &&
\r
289 player.move(+1, 0);
\r
291 if (key_pressed(Key::Jump) &&
\r
293 player.jumping == 0 &&
\r
294 !player.collision_y(-1)) {
\r
295 player.jumping = 1;
\r
296 player.move(0, -1);
\r
297 jump_clock = clock();
\r
299 if (player.jumping != 0) {
\r
300 if (player.jumping < jump_height && get_dur(jump_clock) > jump_time1) {
\r
301 if (!player.collision_y(-1)) {
\r
302 player.move(0, -1);
\r
304 jump_clock = clock();
\r
306 player.jumping = jump_height;
\r
308 } else if (player.jumping == jump_height && get_dur(jump_clock) > jump_time2) {
\r
309 player.jumping = 0;
\r
312 if (!player.jumping && !player.collision_y(1))
\r
313 player.move(0, +1);
\r
315 char b = get_block(player.x, player.y);
\r
316 if (b == '/' || b == '\\' || b == '<' || b == '>')
\r
317 player.move_to(player.x_spawn, player.y_spawn);
\r
320 void print_text(int x, int y, string text, int delay) {
\r
321 for (int i = 0; i < text.size(); i++) {
\r
322 select_length(get_pos(x + i, y), 1);
\r
323 replace(text.substr(i, 1));
\r
329 static int progress = 0;
\r
330 switch (progress) {
\r
332 print_text(4, 2, "Move with left/right.", text_speed);
\r
337 update_play(false);
\r
338 if (player.x == 17) {
\r
339 print_text(4, 4, "Jump with up.", text_speed);
\r
340 print_text(4, 6, "Stand on x.", text_speed);
\r
346 if (player.x == 22) {
\r
347 print_text(4, 8, "Collect ? for ???.", text_speed);
\r
352 update_play(true, 0, 33);
\r
353 if (get_block(player.x, player.y) == '?') {
\r
354 print_text(4, 10, "Avoid /\\.", text_speed);
\r
360 if (player.x == 39) {
\r
361 print_text(4, 14, "Finish lvl by reaching O.", text_speed);
\r
367 if (get_block(player.x, player.y) == 'O') {
\r
375 static int progress = 0;
\r
376 switch (progress) {
\r
378 print_text(4, 2, "Also avoid > and <.", text_speed);
\r
387 void update_game() {
\r
399 int main(int argc, char **argv) {
\r
401 int WinMain(HINSTANCE a0, HINSTANCE a1, LPSTR a2, int a3) {
\r
404 if (hwnd_notepad == NULL || hwnd_edit == NULL) {
\r
412 //dt = ((double)clock() - game_clock) / CLOCKS_PER_SEC * 1000;
\r
413 if (get_dur(game_clock) < frame_time) continue;
\r
414 game_clock = clock();
\r
415 update_key_state();
\r
417 if (key_pressed(Key::Exit))
\r
419 if (key_pressed(Key::Redraw))
\r
424 update_key_state_old();
\r