/* * Naam: Jeroen Boxhoorn * UvAnetID: 16333969 * Studie: BSc Informatica * * This program loads in a maze from a text file and then lets you play that maze. * * Params when running the program: * - The path to the text file containing the maze. * * How to play the game: * - You are the '*' character. * - Use either WSAD or the arrow keys to navigate through the maze. * - The exit of the maze is marked with a '$'. * - Walls are '#'. * - Traps are 'X'. These kill you. * * You can quit the program at any time by pressing CTRL + C. * * Have fun playing! */ #include #include #include #include #include #include #include #include #include "rooster.h" typedef enum { GAME_QUIT, GAME_MAZE_RUNNER, GAME_SNAKE, GAME_MINESWEEPER } game; typedef struct { char name[100]; rooster *game_map; } game_maps; void toon_rooster_op_locatie(rooster *rp, int starting_x, int starting_y) { int height = rooster_hoogte(rp); for (int y = 0; y < height; y++) { char *rij = rooster_vraag_rij(rp, y); mvprintw(starting_y + y, starting_x, "%s", rij); free(rij); } refresh(); } /* Toont het gegeven rooster met ncurses. * * Input: * rp: een pointer naar het rooster. * * Side effect: * De console wordt geleegd en het rooster wordt erin gezet. */ void toon_rooster(rooster *rp) { clear(); toon_rooster_op_locatie(rp, 0, 0); } void update_grid(rooster *rp, char c, int x, int y) { if (rooster_plaats(rp, x, y, c) == 1) { mvaddch(y, x, c); } } void game_error(void) { endwin(); exit(EXIT_FAILURE); } void quit_game(rooster *menu) { if (menu != NULL) { rooster_klaar(menu); } endwin(); exit(EXIT_SUCCESS); } /* * Toont het victory screen. * * Side Effect: * De victory message wordt op een schone console geprint. */ void display_victory(void) { clear(); mvprintw(2,5, "YOU WON!!!!!"); refresh(); } /* * Toont het loss screen. * * Side Effect: * De loss message wordt op een schone console geprint. */ void display_loss(void) { clear(); mvprintw(2,5, "RIP, YOU DIED..."); refresh(); } /* * Toont het quit screen. * * Side Effect: * De quit message wordt op een schone console geprint. */ void display_quit(void) { clear(); mvprintw(2,5, "You quit the game"); refresh(); } /* * Toont het hackerman screen. * * Side Effect: * De hackerman message wordt op een schone console geprint. */ void display_hackerman(void) { clear(); mvprintw(2,5, "The hacker man strikes again..."); refresh(); } /* * Bepaalt afhankelijk van de eindtoestand van het rooster * welk afsluitscherm er getoond moet worden en toont dan dat rooster. * * Input: Het rooster om de toestand uit af te lezen. * * Side Effects: * Het end-of-game scherm wordt op een blanke console geprint. */ void game_exit_screen(rooster *rp) { toestand current_state = rooster_vraag_toestand(rp); switch (current_state) { case STATE_GEWONNEN: display_victory(); return; case STATE_VERLOREN: display_loss(); return; case GAME_QUIT: display_quit(); return; } display_hackerman(); } /* * Waits for the user to press an exit key 'q' before continuing. */ void graceful_exit(void) { mvprintw(5, 0, "Press 'q' to exit the game."); while (1) { switch (getch()) { case 'q': return; } } } void speel_snake(void) { mvprintw(0,0, "Snake has not yet been created"); graceful_exit(); } void speel_minesweeper() { mvprintw(0,0, "Minesweeper has not yet been created"); graceful_exit(); } /* Voert de benodigde veranderingen in het rooster door als de speler in een * bepaalde richting probeert te bewegen. * Input: * rp : een pointer naar het rooster * dx,dy: de richting waarin de speler probeert te bewegen. De vier mogelijk- * heden voor (dx,dy) zijn (-1,0), (1,0), (0,-1), (0,1) voor resp. * links, rechts, omhoog en omlaag. * * Side effect: het rooster wordt aangepast op basis van de handeling van * de speler. */ void maze_runner_beweeg(rooster *rp, int dx, int dy) { int playerx; int playery; rooster_zoek(rp, '*', &playerx, &playery); if (playerx == -1 || playery == -1) { printf("Player not found!"); exit(1); } if (rooster_bevat(rp, playerx + dx, playery + dy) == 1) { char new_location = rooster_kijk(rp, playerx + dx, playery + dy); switch (new_location) { case '#': break; case 'X': update_grid(rp, ' ', playerx, playery); rooster_zet_toestand(rp, STATE_VERLOREN); break; case ' ': update_grid(rp, ' ', playerx, playery); update_grid(rp, '*', playerx + dx, playery + dy); break; case '$': update_grid(rp, ' ', playerx, playery); rooster_zet_toestand(rp, STATE_GEWONNEN); break; } refresh(); } } /* * Speel een dolhof spel. * * Input: * rp: Een pointer naar een rooster met een valide doolhof erin. * * Side Effects: * Met WSAD en arrow keys kun je door het doolhof heen bewegen. * */ void maze_runner(rooster *rp) { while (rooster_vraag_toestand(rp) == STATE_AAN_HET_SPELEN) { switch (getch()) { case KEY_UP: // fallthrough case 'w': maze_runner_beweeg(rp, 0, -1); break; case KEY_DOWN: // fallthrough case 's': maze_runner_beweeg(rp, 0, 1); break; case KEY_LEFT: // fallthrough case 'a': maze_runner_beweeg(rp, -1, 0); break; case KEY_RIGHT: // fallthrough case 'd': maze_runner_beweeg(rp, 1, 0); break; case KEY_BACKSPACE: rooster_zet_toestand(rp, STATE_QUIT); break; } } } rooster *choose_maze(void) { // TODO: echt opties aanbieden in plaats van hardcoded 1 maze. // Alternatief is om random een maze te genereren. dit is miss beter. // 2. Open het doolhof bestand en lees het rooster. FILE *fh = fopen("assets/voorbeeld_doolhof.txt", "r"); if (fh == NULL) { perror("loading maze"); game_error(); } rooster *rp = rooster_lees(fh); fclose(fh); // 3. Bepaal of het lezen van het rooster is gelukt. if (rp == NULL) { fprintf(stderr, "Kan rooster niet maken.\n"); game_error(); } return rp; } /* * Speelt het spel met een gegeven rooster tot de toestand niet langer * AAN_HET_SPELEN is. */ void speel_maze(void) { // Voorbereiding. rooster *rp = choose_maze(); toon_rooster(rp); rooster_zet_toestand(rp, STATE_AAN_HET_SPELEN); // Game zelf. maze_runner(rp); // Exit game. game_exit_screen(rp); rooster_klaar(rp); graceful_exit(); } void launch_game(rooster *menu, const game game) { switch (game) { case GAME_MAZE_RUNNER: speel_maze(); return; case GAME_SNAKE: speel_snake(); return; case GAME_MINESWEEPER: speel_minesweeper(); return; case GAME_QUIT: quit_game(menu); } } void menu_highlight(rooster *rp, const game target, const int offset_x, const int offset_y) { switch (target) { case GAME_MAZE_RUNNER: // Fallthrough case GAME_SNAKE: // Fallthrough case GAME_MINESWEEPER: // Fallthrough case GAME_QUIT: // Fallthrough // TODO: Properly highlight this shit. mvprintw(offset_y + (int)target, offset_x, rooster_vraag_rij(rp, target)); } } game menu_try_move(const game selected_game, const int offset) { switch (selected_game + offset) { case GAME_MAZE_RUNNER: return GAME_MAZE_RUNNER; case GAME_SNAKE: return GAME_SNAKE; case GAME_MINESWEEPER: return GAME_MINESWEEPER; case GAME_QUIT: return GAME_QUIT; } return selected_game; } void navigate_menu(rooster *menu, const game default_game, const int offset_x, const int offset_y) { game selected_game = default_game; while (true) { switch (getch()) { case KEY_UP: // fallthrough case 'w': selected_game = menu_try_move(selected_game, -1); menu_highlight(menu, selected_game, offset_x, offset_y); break; case KEY_DOWN: // fallthrough case 's': selected_game = menu_try_move(selected_game, 1); menu_highlight(menu, selected_game, offset_x, offset_y); break; case KEY_ENTER: // select current game somehow launch_game(menu, GAME_QUIT); menu_highlight(menu, selected_game, offset_x, offset_y); break; case KEY_BACKSPACE: launch_game(menu, GAME_QUIT); break; } } } rooster *laad_menu(void) { char menu[] = "Maze Runner\n" " Snake \n" "Minesweeper\n" " Leave \n"; rooster *rp = rooster_maak(menu); return rp; } void toon_menu(rooster *menu, const game default_game, const int offset_x, const int offset_y) { toon_rooster_op_locatie(menu, offset_x, offset_y); menu_highlight(menu, default_game, offset_x, offset_y); refresh(); } void menu(void) { rooster *menu = laad_menu(); const game default_game = GAME_MAZE_RUNNER; while (true) { clear(); const int offset_x = 5; const int offset_y = 5; toon_menu(menu, default_game, offset_x, offset_y); navigate_menu(menu, default_game, offset_x, offset_y); } } void startup_sequence(void) { // TODO: Nice entry screen } int main(void) { // 4. Initialiseer ncurses setlocale(LC_ALL, ""); initscr(); cbreak(); // zodat je kunt onderbreken met Ctrl+C keypad(stdscr, TRUE); // luister ook naar extra toetsen zoals pijltjes noecho(); // druk niet de letters af die je intypt curs_set(0); // hides the cursor// Don't mask any mouse events // mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); // Don't mask any mouse events // printf("\033[?1003h\n"); // Makes the terminal report mouse movement events // 5. Speel het spel. startup_sequence(); menu(); // 6. Sluit af. quit_game(NULL); }