diff options
| author | Sopár Adrián <adrian.sopar@protonmail.com> | 2024-06-20 09:28:14 +0200 |
|---|---|---|
| committer | Sopár Adrián <adrian.sopar@protonmail.com> | 2024-06-20 09:28:14 +0200 |
| commit | 74ea6dc86646cee9915292d73d8c7afef01ef3e0 (patch) | |
| tree | 9a58866f7765dad8ba56f1f40b1fa031e9d2687d /src/game | |
First commit. This is mostly the state of the project as I left it around the end of 2019.HEADmaster
Diffstat (limited to 'src/game')
| -rw-r--r-- | src/game/commands.c | 61 | ||||
| -rw-r--r-- | src/game/commands.h | 24 | ||||
| -rw-r--r-- | src/game/entry.c | 152 | ||||
| -rw-r--r-- | src/game/entry.h | 9 | ||||
| -rw-r--r-- | src/game/game.c | 109 | ||||
| -rw-r--r-- | src/game/game.h | 67 | ||||
| -rw-r--r-- | src/game/operations.c | 144 | ||||
| -rw-r--r-- | src/game/operations.h | 44 |
8 files changed, 610 insertions, 0 deletions
diff --git a/src/game/commands.c b/src/game/commands.c new file mode 100644 index 0000000..7e0e865 --- /dev/null +++ b/src/game/commands.c @@ -0,0 +1,61 @@ +#include "commands.h" +#include <string.h> + +static struct cmd_res command_switch(struct game_state *state, int argc, char **argv); + +struct cmd_res run_command(struct game_state *state, char *command) +{ + int argc = 0; + char *argv[MAX_ARGS_COUNT]; + char *arg = command; + char *space; + int arg_length; + while ((space = strchr(arg, ' ')) != NULL) + { + if (*arg != ' ') + { + arg_length = space - arg; + argv[argc] = malloc(arg_length + 1); + strncpy(argv[argc], arg, arg_length); + argv[argc][arg_length] = 0; + arg = space + 1; + argc++; + } + } + //Last arg + arg_length = strlen(arg); + argv[argc] = malloc(arg_length + 1); + strncpy(argv[argc], arg, arg_length); + argv[argc][arg_length] = 0; + argc++; + + struct cmd_res response = command_switch(state, argc, argv); + for (int i = 0; i < argc; i++) + free(argv[i]); + return response; +} + +static struct cmd_res nothing(struct game_state *state, int argc, char **argv) +{ + struct cmd_res response; + response.type = CRT_FAIL; + strncpy(response.text, "There is no command you entered!", MAX_CR_TEXT_LENGTH); + return response; +} + +static struct cmd_res quit(struct game_state *state, int argc, char **argv) +{ + state->result = GR_QUIT; + struct cmd_res response; + response.type = CRT_QUIT; + *(response.text) = 0; + return response; +} + +static struct cmd_res command_switch(struct game_state *state, int argc, char **argv) +{ + if (!strcmp("", *argv)) + return nothing(state, argc, argv); + else if (!strcmp("q", *argv)) + return quit(state, argc, argv); +}
\ No newline at end of file diff --git a/src/game/commands.h b/src/game/commands.h new file mode 100644 index 0000000..8e2cc5f --- /dev/null +++ b/src/game/commands.h @@ -0,0 +1,24 @@ +#ifndef H_MAZE_GAME_COMMANDS +#define H_MAZE_GAME_COMMANDS + +#include "game.h" + +enum cmd_res_type +{ + CRT_SUCCESS, + CRT_FAIL, + CRT_QUIT +}; + +#define MAX_CR_TEXT_LENGTH 256 +#define MAX_ARGS_COUNT 100 + +struct cmd_res +{ + enum cmd_res_type type; + char text[MAX_CR_TEXT_LENGTH]; +}; + +struct cmd_res run_command(struct game_state *state, char *command); + +#endif
\ No newline at end of file diff --git a/src/game/entry.c b/src/game/entry.c new file mode 100644 index 0000000..50cf78c --- /dev/null +++ b/src/game/entry.c @@ -0,0 +1,152 @@ +#include "entry.h" +#include "game.h" +#include <stdlib.h> +#include <string.h> +#include <ncurses.h> +#include "utilities.h" +#include "color.h" +#include "maze_solver.h" + +static inline int mvaddwch(int y, int x, wchar_t wch) +{ + wchar_t arr[2]; + arr[0] = wch; + arr[1] = 0; + return mvaddwstr(y, x, arr); +} + +static inline int addwch(wchar_t wch) +{ + wchar_t arr[2]; + arr[0] = wch; + arr[1] = 0; + return addwstr(arr); +} + +static void darw_block(struct block *block) +{ + attron(COLOR_PAIR(block->color)); + if (block->bold) + attron(A_BOLD); + addwch(block->chr); + if (block->bold) + attroff(A_BOLD); +} + +static void mv_draw_block(int y, int x, struct block *block) +{ + int width = getmaxx(stdscr); + int height = getmaxy(stdscr) - 1; + if (x >= 0 && x < width && y >= 0 && y < height) + { + move(y, x); + darw_block(block); + } +} + +void draw_maze(struct maze_display *maze_draw, struct game_blocks *blocks) +{ + int width = getmaxx(stdscr); + int height = getmaxy(stdscr) - 1; + enum signs path_sign; + for (int y = 0; y < maze_draw->maze->height; y++) + { + int real_y = maze_draw->maze_pos.y + y; + if (real_y >= 0 && real_y < height) + { + if (maze_draw->maze_pos.x >= 0) + move(real_y, maze_draw->maze_pos.x); + for (int x = 0; x < maze_draw->maze->width && y < width; x++) + { + int real_x = maze_draw->maze_pos.x + x; + if (real_x == 0 && x > 0) + { + move(real_y, 0); + } + if (real_x >= 0 && real_x < width) + { + path_sign = maze_draw->signs[x][y]; + if (path_sign == RS_NONE || (path_sign == RS_PATH && !maze_draw->display_player_path)) //Maze + { + if (maze_draw->maze->map[x][y]) + darw_block(&(blocks->wall)); + else + darw_block(&(blocks->road)); + } + else + { + if (path_sign == RS_PATH) + darw_block(&(blocks->path)); + else if (path_sign == RS_SOLVE) + darw_block(&(blocks->solve)); + } + } + } + } + } + //Player + mv_draw_block( + maze_draw->maze_pos.y + maze_draw->player_pos.y, + maze_draw->maze_pos.x + maze_draw->player_pos.x, &(blocks->player)); + mv_draw_block( + maze_draw->maze_pos.y + maze_draw->maze->starting_point.y, + maze_draw->maze_pos.x + maze_draw->maze->starting_point.x, &(blocks->start)); + mv_draw_block( + maze_draw->maze_pos.y + maze_draw->maze->end_point.y, + maze_draw->maze_pos.x + maze_draw->maze->end_point.x, &(blocks->target)); +} + +static void own_clear() +{ + attron(COLOR_PAIR(CI_DEFAULT)); + int width = getmaxx(stdscr); + int height = getmaxy(stdscr) - 1; + for (int y = 0; y < height; y++) + for (int x = 0; x < width; x++) + mvaddch(y, x, ' '); +} + +enum game_res game(struct app *app) +{ + curs_set(0); + noecho(); + struct game_state *state = create_game_state(app->maze); + + while (1) + { + if (state->display->player_pos.x != state->new_player_pos.x || + state->display->player_pos.y != state->new_player_pos.y) //Does player moved? + { + state->display->signs[state->display->player_pos.x][state->display->player_pos.y] = RS_PATH; + state->display->player_pos = state->new_player_pos; + if (state->center) + state->new_maze_pos = get_player_center(state->display->player_pos); + if (state->display->player_pos.x == state->display->maze->end_point.x && + state->display->player_pos.y == state->display->maze->end_point.y) //Win? + state->win = true; + } + state->display->maze_pos = state->new_maze_pos; + //Draw! + own_clear(); + draw_maze(state->display, &(app->conf->blocks)); + if (state->win) + draw_line_win(); + else + draw_line_info(state->steps_taken, solve_maze(app->maze, state->display->player_pos, NULL)); + wrefresh(stdscr); + //Get user input! + wchar_t c = wgetch(stdscr); + struct binding *last_binding = &(app->conf->bindings[app->conf->count - 1]); + for (struct binding *binding = app->conf->bindings; binding <= last_binding; binding++) + { + if ((*(binding->cname) != 0 && strcmp(keyname(c), binding->cname) == 0) || c == binding->c) + { + if (binding->operation(state, binding->param) == OPR_QUIT) + { + return state->result; + } + } + } + } + return GR_QUIT; +} diff --git a/src/game/entry.h b/src/game/entry.h new file mode 100644 index 0000000..655f719 --- /dev/null +++ b/src/game/entry.h @@ -0,0 +1,9 @@ +#ifndef H_MAZE_GAME_ENTRY +#define H_MAZE_GAME_ENTRY + +#include "app.h" +#include "game.h" + +enum game_res game(struct app *app); + +#endif
\ No newline at end of file diff --git a/src/game/game.c b/src/game/game.c new file mode 100644 index 0000000..a9ac239 --- /dev/null +++ b/src/game/game.c @@ -0,0 +1,109 @@ +#include "game.h" +#include "color.h" +#include "utilities.h" +#include <string.h> + +void draw_line(int color, char *text, size_t length) +{ + int width = getmaxx(stdscr); + int height = getmaxy(stdscr) - 1; + char footer[width + 1]; + memset(footer, ' ', width); + footer[width] = 0; + //Display: + attron(COLOR_PAIR(color)); + mvprintw(height, 0, footer); + strncpy(footer, text, length); + mvprintw(height, 0, footer); +} + +void draw_line_info(int steps_taken, int steps_remaining) +{ + char buffer[getmaxx(stdscr) + 1]; + int length = sprintf(buffer, "%d/%d", steps_taken, steps_remaining); + draw_line(CI_LINE_INFO, buffer, length); +} + +void draw_line_win() +{ + char buffer[getmaxx(stdscr) + 1]; + int length = sprintf(buffer, "\u2714 Win! \u263A"); + draw_line(CI_LINE_SUCCESS, buffer, length); +} + +int get_command(char prompt, char *command) +{ + int width = getmaxx(stdscr); + int height = getmaxy(stdscr) - 1; + + char line[width + 1]; + memset(line, ' ', width); + line[width] = 0; + attron(COLOR_PAIR(CI_LINE_CMD)); + curs_set(1); + + char *current = command; + *(current++) = prompt; + *current = 0; + while (1) + { + mvaddstr(height, 0, line); + mvaddstr(height, 0, command); + refresh(); + wchar_t c = wgetch(stdscr); + if (c == KEY_BACKSPACE) + { + current--; + *current = 0; + if (current == command) + { + curs_set(0); + return 0; + } + } + else if (c == 10) + { + curs_set(0); + return 1; + } + else + { + *(current++) = c; + *current = 0; + } + } +} + +struct game_state *create_game_state(struct maze *maze) +{ + struct maze_display *display = malloc(sizeof(struct maze_display)); + + display->maze_pos.x = 0; + display->maze_pos.y = 0; + display->maze = maze; + display->player_pos = maze->starting_point; + display->display_player_path = true; + //Signs + int signs_length = sizeof_2d(maze->width, maze->height, sizeof(int)); + display->signs = malloc(signs_length); + memset(display->signs, (int)RS_NONE, signs_length); + init2d((void **)display->signs, maze->width, maze->height, sizeof(int)); + display->signs[display->player_pos.x][display->player_pos.y] = RS_PATH; + + struct game_state *state = malloc(sizeof(struct game_state)); + state->display = display; + + state->center = false; + state->win = false; + state->steps_taken = 0; + state->new_maze_pos = display->maze_pos; + state->new_player_pos = display->player_pos; + return state; +} + +struct array +{ + int width; + int height; + int *arr; +}; diff --git a/src/game/game.h b/src/game/game.h new file mode 100644 index 0000000..4b0de07 --- /dev/null +++ b/src/game/game.h @@ -0,0 +1,67 @@ +#ifndef H_MAZE_GAME_GAME +#define H_MAZE_GAME_GAME + +#include <stdlib.h> +#include <stdbool.h> +#include <ncurses.h> +#include "maze.h" + +enum game_res +{ + GR_MENU, + GR_QUIT +}; + +enum signs +{ + RS_NONE, + RS_SOLVE, + RS_PATH +}; + +struct maze_display +{ + struct point maze_pos; + struct point player_pos; + struct maze *maze; + enum signs **signs; + bool display_player_path; +}; + +struct game_state +{ + struct maze_display *display; + struct point new_maze_pos; + struct point new_player_pos; + int steps_taken; + bool center; + bool win; + char cmd_history[100][256]; + size_t cmd_count; + enum game_res result; +}; + +struct game_state *create_game_state(struct maze *maze); + +void draw_line_win(); + +void draw_line_info(int steps_taken, int steps_remaining); + +int get_command(char prompt, char *command); + +static inline int is_movable(struct maze_display *display, int x, int y) +{ + return display->maze->map[display->player_pos.x + x][display->player_pos.y + y] == 0; +} + +static inline struct point get_player_center(struct point player_pos) +{ + int width = getmaxx(stdscr); + int height = getmaxy(stdscr) - 1; + struct point maze_pos; + maze_pos.x = (width / 2) - player_pos.x; + maze_pos.y = (height / 2) - player_pos.y; + return maze_pos; +} + +#endif
\ No newline at end of file diff --git a/src/game/operations.c b/src/game/operations.c new file mode 100644 index 0000000..aa9424f --- /dev/null +++ b/src/game/operations.c @@ -0,0 +1,144 @@ +#include "operations.h" +#include <string.h> +#include "maze_generator.h" +#include "maze_solver.h" +#include "commands.h" + +enum op_res move_player(struct game_state *state, int data) +{ + if (state->win) + return OPR_NONE; + enum move move = (enum move)data; + if (move == MOVE_UP && is_movable(state->display, 0, -1)) + { + state->new_player_pos.y--; + state->steps_taken++; + } + else if (move == MOVE_DOWN && is_movable(state->display, 0, 1)) + { + state->new_player_pos.y++; + state->steps_taken++; + } + else if (move == MOVE_LEFT && is_movable(state->display, -1, 0)) + { + state->new_player_pos.x--; + state->steps_taken++; + } + else if (move == MOVE_RIGHT && is_movable(state->display, 1, 0)) + { + state->new_player_pos.x++; + state->steps_taken++; + } + return OPR_NONE; +} + +enum op_res move_maze(struct game_state *state, int data) +{ + switch ((enum move)data) + { + case MOVE_UP: + state->new_maze_pos.y--; + break; + case MOVE_DOWN: + state->new_maze_pos.y++; + break; + case MOVE_LEFT: + state->new_maze_pos.x--; + break; + case MOVE_RIGHT: + state->new_maze_pos.x++; + break; + case MOVE_BEGINNING: + { + state->new_maze_pos.x = 0; + state->new_maze_pos.y = 0; + } + break; + } + return OPR_NONE; +} + +enum op_res quit(struct game_state *state, int data) +{ + state->result = data; + return OPR_QUIT; +} + +enum op_res turn_display_switch(struct game_state *state, int data) +{ + switch ((enum display)data) + { + case DISP_PATH: + state->display->display_player_path = !(state->display->display_player_path); + break; + } + return OPR_NONE; +} + +enum op_res new_random(struct game_state *state, int data) +{ + struct maze_display *display = state->display; + generate_maze(display->maze); + display->player_pos = display->maze->starting_point; + state->new_player_pos = display->player_pos; + for (int x = 0; x < display->maze->width; x++) + { + for (int y = 0; y < display->maze->height; y++) + { + display->signs[x][y] = RS_NONE; + } + } + state->win = false; + state->steps_taken = 0; + return OPR_NONE; +} + +enum op_res center(struct game_state *state, int data) +{ + state->center = !state->center; + if (state->center) + state->new_maze_pos = get_player_center(state->display->player_pos); + return OPR_NONE; +} + +enum op_res help_by_n_move(struct game_state *state, int data) +{ + struct point path[3000]; + int count = solve_maze(state->display->maze, state->display->player_pos, path); + if (count > 0) + { + state->new_player_pos = path[1]; + state->steps_taken++; + } + return OPR_NONE; +} + +enum op_res solve(struct game_state *state, int data) +{ + struct point path[3000]; + int count = solve_maze(state->display->maze, state->display->player_pos, path); + for (int i = 0; i < count; i++) + { + state->display->signs[path[i].x][path[i].y] = RS_SOLVE; + } + return OPR_NONE; +} + +enum op_res start_command_prompt(struct game_state *state, int data) +{ + char command[256]; + if (get_command((char)data, command)) + { + struct cmd_res response = run_command(state, command + 1); + switch (response.type) + { + case CRT_SUCCESS: + break; + case CRT_FAIL: + break; + case CRT_QUIT: + return OPR_QUIT; + } + } + return OPR_NONE; +}
\ No newline at end of file diff --git a/src/game/operations.h b/src/game/operations.h new file mode 100644 index 0000000..2f2af47 --- /dev/null +++ b/src/game/operations.h @@ -0,0 +1,44 @@ +#ifndef H_MAZE_GAME_OPERATION +#define H_MAZE_GAME_OPERATION + +#include "game.h" + +enum op_res +{ + OPR_NONE, + OPR_QUIT +}; + +enum move +{ + MOVE_UP, + MOVE_DOWN, + MOVE_LEFT, + MOVE_RIGHT, + MOVE_BEGINNING +}; + +enum display +{ + DISP_PATH +}; + +enum op_res move_player(struct game_state *state, int data); + +enum op_res move_maze(struct game_state *state, int data); + +enum op_res quit(struct game_state *state, int data); + +enum op_res turn_display_switch(struct game_state *state, int data); + +enum op_res new_random(struct game_state *state, int data); + +enum op_res center(struct game_state *state, int data); + +enum op_res help_by_n_move(struct game_state *state, int data); + +enum op_res solve(struct game_state *state, int data); + +enum op_res start_command_prompt(struct game_state *state, int data); + +#endif
\ No newline at end of file |
