diff --git a/assets/voorbeeld_doolhof.txt b/assets/maze.txt similarity index 100% rename from assets/voorbeeld_doolhof.txt rename to assets/maze.txt diff --git a/grid_game_engine.c b/grid_game_engine.c new file mode 100644 index 0000000..d524226 --- /dev/null +++ b/grid_game_engine.c @@ -0,0 +1,153 @@ +/* + * Created by snapshot112 on 10/15/25. + * + * A game engine that can run and display games in square grids. + */ + +#include "grid_game_engine.h" + +#include +#include +#include + +#include "rooster.h" + +int modulo(const int number, const int mod) { + int result = number % mod; + if (result < 0) { + result += mod; //This is not how math is supposed to work C, damnit. + } + return result; +} + +void show_grid_on_offset(const rooster *gp, const int starting_x, const int starting_y) { + const int height = rooster_hoogte(gp); + + for (int y = 0; y < height; y++) { + char *rij = rooster_vraag_rij(gp, y); + mvprintw(starting_y + y, starting_x, "%s", rij); + free(rij); + } + refresh(); +} + +void show_grid(const rooster *rp) { + show_grid_on_offset(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); + } +} + +/* + * Shows the victory screen. + * + * Side Effect: + * Clears the console and prints the victory message. + */ +static void display_victory(void) { + clear(); + mvprintw(2,5, "YOU WON!!!!!"); + refresh(); +} + +/* + * Shows the GAME OVER screen. + * + * Side Effect: + * Clears the console and prints the GAME OVER message. + */ +static void display_loss(void) { + clear(); + mvprintw(2,5, "GAME OVER"); + refresh(); +} + +/* + * Shows the quit screen + * + * Side Effect: + * Clears the console and prints the quit message. + */ +static void display_quit(void) { + clear(); + mvprintw(2,5, "You quit the game"); + refresh(); +} + +/* + * Shows the hacker man screen + * + * Side Effect: + * Clears the console and prints the hacker man message. + */ +static void display_hackerman(void) { + clear(); + mvprintw(2,5, "The hacker man strikes again..."); + refresh(); +} + +void graceful_exit(void) { + mvprintw(5, 5, "Press 'q' to exit."); + while (1) { + switch (getch()) { + case 'q': + case 'Q': + return; + } + } +} + +void game_exit_screen(rooster *gp) { + toestand current_state = rooster_vraag_toestand(gp); + switch (current_state) { + case STATE_GEWONNEN: + display_victory(); + break; + case STATE_VERLOREN: + display_loss(); + break; + case STATE_QUIT: + display_quit(); + break; + default: + display_hackerman(); + } + graceful_exit(); +} + +static void init_ncurses() { + setlocale(LC_ALL, ""); + initscr(); + cbreak(); // So you can cancel the game with ctrl + c. + keypad(stdscr, TRUE); // Enable extra keys like the arrow keys. + noecho(); // Don't write the keyboard input to the console. + curs_set(0); // Hides the cursor. + + // 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 + + start_color(); + init_pair(BLACK, COLOR_BLACK, COLOR_BLACK); + init_pair(WHITE, COLOR_BLACK, COLOR_WHITE); + init_pair(BLUE, COLOR_BLACK, COLOR_BLUE); + init_pair(GREEN, COLOR_BLACK, COLOR_GREEN); + init_pair(CYAN, COLOR_BLACK, COLOR_CYAN); + init_pair(MAGENTA, COLOR_BLACK, COLOR_MAGENTA); + init_pair(YELLOW, COLOR_BLACK, COLOR_YELLOW); + init_pair(RED, COLOR_BLACK, COLOR_RED); +} + +static void cleanup_ncurses() { + endwin(); +} + +void init_engine(void) { + init_ncurses(); +} + +void cleanup_engine(void) { + cleanup_ncurses(); +} diff --git a/grid_game_engine.h b/grid_game_engine.h new file mode 100644 index 0000000..030a241 --- /dev/null +++ b/grid_game_engine.h @@ -0,0 +1,103 @@ +/* + * Created by snapshot112 on 10/15/25. + * + * A game engine that uses the can run and display games in rectangular grids. + * The graphics are made using ncursesw. + * + * Please make sure to initialize the game engine before running any games. + */ + +#ifndef MINIGAME_MENU_GRID_GAME_ENGINE_H +#define MINIGAME_MENU_GRID_GAME_ENGINE_H +#include "rooster.h" + +typedef enum { + BLACK = 1, + WHITE = 2, + BLUE = 3, + GREEN = 4, + CYAN = 5, + MAGENTA = 6, + YELLOW = 7, + RED = 8 +} game_colors; + +typedef struct { + char name[100]; + rooster *game_map; +} game_maps; + +/* + * A proper modulo function. + * The one provided by c: '%' doesn't work according to the mathematical definition. + */ +int modulo(int number, int mod); + +/* + * Displays the given grid with the given offset using ncurses. + * + * Input: + * gp: A pointer to the grid. + * + * Side effect: + * The console is cleared and the grid is printed. + */ +void show_grid_on_offset(const rooster *gp, int starting_x, int starting_y); + +/* + * Displays the given grid with ncurses. + * + * Input: + * gp: A pointer to the grid. + * + * Side effect: + * The console is cleared and the grid is printed. + */ +void show_grid(const rooster *gp); + +/* + * Updates a single location in the grid. + * + * Input: + * gp: A pointer to the grid. + * c: The character to update the location with. + * x: The x-coordinate of the spot you want to update. + * y: The y-coordinate of the spot you want to update. + * + * Side effect: + * The update gets applied both on the grid and on the screen. + */ +void update_grid(rooster *gp, char c, int x, int y); + +/* + * Display the ending screen that matches the end state of the grid. + * + * Input: + * gp: A pointer to the grid. + * + * Side Effects: + * The end of game screen gets displayed with a graceful exit. + */ +void game_exit_screen(rooster *gp); + +/* + * Waits for you to press 'q' before exiting the game. + * + * Side effect: Prints "Press 'q' to exit." game to the console. + */ +void graceful_exit(void); + +/* + * Initialize ncurses. + * + * This enables cbreak, noecho, hides the cursor and enables the extra keys. + * This also creates the color pairs needed for game_colors, + */ +void init_engine(void); + +/* + * Cleanup ncurses. + */ +void cleanup_engine(void); + +#endif //MINIGAME_MENU_GRID_GAME_ENGINE_H diff --git a/maze_runner.c b/maze_runner.c new file mode 100644 index 0000000..6727a87 --- /dev/null +++ b/maze_runner.c @@ -0,0 +1,128 @@ +// +// Created by snapshot112 on 10/15/25. +// + +#include "maze_runner.h" + +#include +#include + +#include "grid_game_engine.h" +#include "rooster.h" + +/* + * Reads in the maze from the assets file. + */ +static rooster *get_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/maze.txt", "r"); + if (fh == NULL) { + perror("loading maze"); + exit(EXIT_FAILURE); + } + 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"); + exit(EXIT_FAILURE); + } + + return rp; +} + +/* 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. + */ +static 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(); + } +} + +/* + * Speelt het spel met een gegeven rooster tot de toestand niet langer + * AAN_HET_SPELEN is. + */ +static void speel_maze(rooster *rp) { + while (rooster_vraag_toestand(rp) == STATE_AAN_HET_SPELEN) + { + switch (getch()) { + case KEY_UP: // fallthrough + case 'w': + case 'W': + maze_runner_beweeg(rp, 0, -1); + break; + case KEY_DOWN: // fallthrough + case 's': + case 'S': + maze_runner_beweeg(rp, 0, 1); + break; + case KEY_LEFT: // fallthrough + case 'a': + case 'A': + maze_runner_beweeg(rp, -1, 0); + break; + case KEY_RIGHT: // fallthrough + case 'd': + case 'D': + maze_runner_beweeg(rp, 1, 0); + break; + case KEY_BACKSPACE: + rooster_zet_toestand(rp, STATE_QUIT); + break; + } + } +} + +void maze_runner(void) { + // Voorbereiding. + rooster *rp = get_maze(); + show_grid(rp); + rooster_zet_toestand(rp, STATE_AAN_HET_SPELEN); + + // Game zelf. + speel_maze(rp); + + // Exit game. + game_exit_screen(rp); + rooster_klaar(rp); +} diff --git a/maze_runner.h b/maze_runner.h new file mode 100644 index 0000000..ddfbff7 --- /dev/null +++ b/maze_runner.h @@ -0,0 +1,39 @@ +/* + * Naam: Jeroen Boxhoorn + * UvAnetID: 16333969 + * Studie: BSc Informatica + * + * A game of maze runner configured to run on the grid game engine. + * + * Please make sure to include and initialize the game engine before calling maze_runner(); + * + * 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! + */ + +#ifndef MINIGAME_MENU_MAZE_RUNNER_H +#define MINIGAME_MENU_MAZE_RUNNER_H + +/* + * A game of maze runner configured to run on the grid game engine. + * + * Please make sure to include and initialize the game engine before calling maze_runner(); + * + * Side Effects: + * Clears the console and uses it to play a game of maze runner. + * + * Controls: + * use WSAD or arrow keys to move through the maze. + * Use BACKSPACE to exit the game early. + */ +void maze_runner(void); + +#endif //MINIGAME_MENU_MAZE_RUNNER_H diff --git a/minesweeper.c b/minesweeper.c new file mode 100644 index 0000000..60274ea --- /dev/null +++ b/minesweeper.c @@ -0,0 +1,16 @@ +// +// Created by snapshot112 on 10/15/25. +// + +#include "minesweeper.h" + +#include + +#include "grid_game_engine.h" + +void minesweeper() { + clear(); + mvprintw(0,0, "Minesweeper has not yet been created"); + graceful_exit(); + refresh(); +} diff --git a/minesweeper.h b/minesweeper.h new file mode 100644 index 0000000..6463556 --- /dev/null +++ b/minesweeper.h @@ -0,0 +1,30 @@ +/* + * Created by snapshot112 on 10/15/25. + * + * A game of minesweeper runner configured to run on the grid game engine. + * + * Please make sure to include and initialize the game engine before calling snake(); + */ + +#ifndef MINIGAME_MENU_MINESWEEPER_H +#define MINIGAME_MENU_MINESWEEPER_H + +/* + * A game of minesweeper configured to run on the grid game engine. + * + * Please make sure to include and initialize the game engine before calling snake(); + * + * Side Effects: + * Clears the console and uses it to play a game of minesweeper. + * + * Instructions: + * use WSAD or arrow keys to select a grid square. + * use SPACEBAR to open the current square. + * use 'f' to mark/unmark a square. + * use BACKSPACE to exit the game early. + * + * marked squares can't be opened. + */ +void minesweeper(void); + +#endif //MINIGAME_MENU_MINESWEEPER_H diff --git a/minigame_menu.c b/minigame_menu.c new file mode 100644 index 0000000..aaa1489 --- /dev/null +++ b/minigame_menu.c @@ -0,0 +1,173 @@ +// +// Created by snapshot112 on 10/15/25. +// + +#include "minigame_menu.h" + +#include +#include + +#include "grid_game_engine.h" +#include "maze_runner.h" +#include "minesweeper.h" +#include "rooster.h" +#include "snake.h" + +#define AMOUNT_OF_MENU_OPTIONS 4 + +static game SELECTED_GAME = GAME_MAZE_RUNNER; +static int OFFSET_Y = 5; +static int OFFSET_X = 5; + +/* + * Launch a game from the menu. + * + * Input: + * menu: A pointer to the menu grid. + * game: The game you want to launch. + */ +static void launch_game(rooster *menu, const game game) { + switch (game) { + case GAME_MAZE_RUNNER: + maze_runner(); + break; + case GAME_SNAKE: + snake(); + break; + case GAME_MINESWEEPER: + minesweeper(); + break; + } +} + +/* + * Highlight a valid menu option. + * + * Input: + * menu: A pointer to the menu grid. + * target: The menu option to highlight. + * offset_x: The x offset of the menu. + * offset_y: The y offset of the menu. + * + * Side effects: + * If a valid menu option is provided: It will be highlighted in green. + * If an invalid menu option is provided: Nothing happens + */ +static void menu_highlight(const rooster *menu) { + switch (SELECTED_GAME) { + case GAME_MAZE_RUNNER: + case GAME_SNAKE: + case GAME_MINESWEEPER: + case GAME_QUIT: + attron(COLOR_PAIR(GREEN)); + + char* row = rooster_vraag_rij(menu, SELECTED_GAME); + mvprintw(OFFSET_Y + (int)SELECTED_GAME, OFFSET_X, "%s", row); + free(row); + + attroff(COLOR_PAIR(GREEN)); + } +} + +/* + * Show the menu screen. + * + * Input: + * menu: A pointer to the menu grid. + * default_selection: The starting selection in the menu. + * offset_x: The x offset of the menu. + * offset_y: The y offset of the menu. + * + * Side Effects: + * Displays the menu + */ +static void show_menu(const rooster *menu) { + clear(); + show_grid_on_offset(menu, OFFSET_X, OFFSET_Y); + menu_highlight(menu); + refresh(); +} + +/* + * Select the game on a location determined by a given offset. + * Negative values go up and positive values go down. + * Out of bounds selections loop around. + * + * Input: + * selected_game: The currently selected game. + * offset: The amount offset the current selection by. + * + * Side effect: + * The game on the location of the given offset will be selected. + */ +static void menu_move(const int offset) { + SELECTED_GAME = modulo(SELECTED_GAME + offset, AMOUNT_OF_MENU_OPTIONS); +} + +/* + * Navigate through the menu. + * + * Input: + * menu: A pointer to the menu grid. + * + * Output: A code that reflects the current menu state. + * 0: Continue running. + * 1: Exit the menu. + * + * + * Side Effect: + * Changes the SELECTED_GAME as needed and launches selected games on select. + */ +static int navigate_menu(rooster *menu) { + switch (getch()) { + case KEY_UP: + case 'w': + case 'W': + menu_move(-1); + break; + case KEY_DOWN: + case 's': + case 'S': + menu_move(1); + break; + case KEY_ENTER: + case 'f': + case 'F': + if (SELECTED_GAME == GAME_QUIT) { + return 1; + } + launch_game(menu, SELECTED_GAME); + break; + case KEY_BACKSPACE: + return 1; + } + return 0; +} + +/* + * Create the menu grid. + * + * Output: + * A pointer to the menu grid. + */ +static rooster *initialize_menu(void) { + char menu[] = "Maze Runner\n" + " Snake \n" + "Minesweeper\n" + " Leave \n"; + rooster *rp = rooster_maak(menu); + return rp; +} + +void minigame_menu(void) { + rooster *menu = initialize_menu(); + + while (true) { + show_menu(menu); + if (navigate_menu(menu) == 1) { + break; + } + } + + rooster_klaar(menu); +} diff --git a/minigame_menu.h b/minigame_menu.h new file mode 100644 index 0000000..5c4c3cd --- /dev/null +++ b/minigame_menu.h @@ -0,0 +1,35 @@ +/* + * Created by snapshot112 on 10/15/25. + * + * A minigame menu for games configured to run on the grid game engine. + * + * Please make sure to include and initialize the game engine before calling menu(); + */ + +#ifndef MINIGAME_MENU_MINIGAME_MENU_H +#define MINIGAME_MENU_MINIGAME_MENU_H + +typedef enum { + GAME_MAZE_RUNNER = 0, + GAME_SNAKE = 1, + GAME_MINESWEEPER = 2, + GAME_QUIT = 3, +} game; + +/* + * A minigame menu for games configured to run on the grid game engine. + * + * Please make sure to include and initialize the game engine before calling menu(); + * + * Side Effects: + * Clears the console and uses it to display a minigame menu. + * + * Controls: + * 'w'/'arr_up: Next menu item. + * 's'/'arr_down': Previous menu item. + * 'f': Select current menu item. + * 'BACKSPACE': Exit the menu. + */ +void minigame_menu(void); + +#endif //MINIGAME_MENU_MINIGAME_MENU_H diff --git a/rooster.c b/rooster.c index b312092..609d07e 100644 --- a/rooster.c +++ b/rooster.c @@ -4,9 +4,6 @@ #include #include - -// TODO: End the eternal NULL checks. - /* * The rooster type this program is build around. */ @@ -17,14 +14,12 @@ typedef struct rooster_data { toestand state; } rooster; - rooster *rooster_maak(const char* input) { int width = 0; int height = 0; const size_t len = strlen(input) / sizeof(char); if (input == NULL || len == 0) { - perror("rooster_maak"); - exit(1); + return NULL; } for (int i = 0; input[i] != '\n'; i++) { @@ -35,14 +30,18 @@ rooster *rooster_maak(const char* input) { for (int i = 0; i < height; i = i + width + 1) { if ((int)strcspn(&input[i], "\n") != width) { - perror("rooster_maak"); - exit(1); - }; + return NULL; + } } const int grid_size = (width + 1) * height + 1; rooster *rp = malloc(sizeof(rooster)); + + if (rp == NULL) { + return NULL; + } + rp->rost = malloc(grid_size * sizeof(char)); rp->height = height; rp->width = width; @@ -68,10 +67,6 @@ rooster *rooster_maak(const char* input) { * 0 otherwise */ static int get_grid_sizes(FILE *fh, rooster *rost) { - if (fh == NULL) { - return 0; - } - while (getc(fh) != '\n') { if (feof(fh)) { return 0; @@ -242,18 +237,6 @@ int rooster_plaats(rooster *rp, int x, int y, char c) { return 0; } -char *rooster_als_string(const rooster *rp) { - if (rp != NULL && rp->rost != NULL) { - char *string = malloc(sizeof(rp->rost)); - if (string == NULL) { - return NULL; - } - memcpy(string, rp->rost, sizeof(rp->rost)); - return string; - } - return NULL; -} - char *rooster_vraag_rij(const rooster *rp, int y) { if (rp != NULL && rp->rost != NULL && rooster_bevat(rp, 0, y) == 1) { // we're going to remove the newline so this is long enough diff --git a/rooster.h b/rooster.h index 229dc87..9ff94ea 100644 --- a/rooster.h +++ b/rooster.h @@ -79,18 +79,6 @@ char *rooster_vraag_rij(const rooster *rp, int y); */ rooster *rooster_kopieer(const rooster *rp); -/* - * Haal het hele rooster op in de vorm van een string. - * - * Input: - * rp: Een pointer naar het rooster. - * - * Output: - * Een pointer naar een string met daarin het hele rooster, - * regels zijn gescheiden door '/n' karakters. - */ -char *rooster_als_string(const rooster *rp); - /* Vraag de huidige toestand van het spel op. Input: diff --git a/snake.c b/snake.c new file mode 100644 index 0000000..607e91a --- /dev/null +++ b/snake.c @@ -0,0 +1,16 @@ +// +// Created by snapshot112 on 10/15/25. +// + +#include "snake.h" + +#include + +#include "grid_game_engine.h" + +void snake(void) { + clear(); + mvprintw(0,0, "Snake has not yet been created"); + graceful_exit(); + refresh(); +} diff --git a/snake.h b/snake.h new file mode 100644 index 0000000..21cda6b --- /dev/null +++ b/snake.h @@ -0,0 +1,26 @@ +/* + * Created by snapshot112 on 10/15/25. + * + * A game of maze runner configured to run on the grid game engine. + * + * Please make sure to include and initialize the game engine before calling snake(); + */ + +#ifndef MINIGAME_MENU_SNAKE_H +#define MINIGAME_MENU_SNAKE_H + +/* + * A game of snake configured to run on the grid game engine. + * + * Please make sure to include and initialize the game engine before calling snake(); + * + * Side Effects: + * Clears the console and uses it to play a game of snake. + * + * Controls: + * Use WSAD or arrow keys to redirect the snake. + * Use BACKSPACE to exit the game early. + */ +void snake(void); + +#endif //MINIGAME_MENU_SNAKE_H diff --git a/spel b/spel index 0743e6b..3f4560f 100755 Binary files a/spel and b/spel differ diff --git a/spel.c b/spel.c index 68fb267..32031a0 100644 --- a/spel.c +++ b/spel.c @@ -3,454 +3,22 @@ * UvAnetID: 16333969 * Studie: BSc Informatica * - * This program loads in a maze from a text file and then lets you play that maze. + * A minigame menu that lets you play games on the grid game engine. * - * 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! + * Currently the following games are included: + * - maze runner + * - snake + * - minesweeper */ -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "rooster.h" - -typedef enum { - GAME_QUIT, - GAME_MAZE_RUNNER, - GAME_SNAKE, - GAME_MINESWEEPER -} game; - -typedef enum { - BLACK = 1, - WHITE = 2, - BLUE = 3, - GREEN = 4, - CYAN = 5, - MAGENTA = 6, - YELLOW = 7, - RED = 8//, - // LIME = 9 -} game_colors; - -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. - attron(COLOR_PAIR(HIGHLIGHT_COLOR)); - mvaddch(y0 + y, x0 + x * 2, ' '); - addch(' '); - attroff(COLOR_PAIR(kleur)); - char* row = rooster_vraag_rij(rp, target); - mvprintw(offset_y + (int)target, offset_x, row); - free(row); - } -} - -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: - case 'p': - // 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 -} +#include "grid_game_engine.h" +#include "minigame_menu.h" 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 - - start_color(); - init_pair(BLACK, COLOR_BLACK, COLOR_BLACK); - init_pair(WHITE, COLOR_BLACK, COLOR_WHITE); - init_pair(BLUE, COLOR_BLACK, COLOR_BLUE); - init_pair(GREEN, COLOR_BLACK, COLOR_GREEN); - init_pair(CYAN, COLOR_BLACK, COLOR_CYAN); - init_pair(MAGENTA, COLOR_BLACK, COLOR_MAGENTA); - init_pair(YELLOW, COLOR_BLACK, COLOR_YELLOW); - init_pair(RED, COLOR_BLACK, COLOR_RED); - // init_pair(LIME, COLOR_BLACK, COLOR_LIME); - + init_engine(); // 5. Speel het spel. - startup_sequence(); - menu(); + minigame_menu(); - // 6. Sluit af. - quit_game(NULL); + cleanup_engine(); }