/* * Copyright (C) 2021 P. J. McDermott * * This file is part of Maze Fight * * Maze Fight is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Maze Fight is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Maze Fight. If not, see . */ #include #include #include "../char.h" #include "../defs.h" #include "../maze.h" #include "char.h" struct mf_enemy { struct mf_char parent; struct mf_char *next_enemy; }; static int _mf_enemy_update(struct mf_char *c) { struct mf_enemy *p = (struct mf_enemy *) c; if (p->next_enemy != NULL) { return mf_char_update(p->next_enemy); } else { return 0; } } static int _mf_enemy_step(struct mf_char *c) { enum _mf_char_dir dirs[4] = {MF_CHAR_DIR_U_, MF_CHAR_DIR_D_, MF_CHAR_DIR_L_, MF_CHAR_DIR_R_}; int i; int j; int t; enum _mf_char_dir back; int dx; int dy; /* Shuffle directions */ for (i = 0; i < 4; ++i) { j = rand() / (RAND_MAX / (i+1)); t = dirs[i]; dirs[i] = dirs[j]; dirs[j] = t; } /* Don't go backwards unless necessary */ switch (c->cur_dir) { case MF_CHAR_DIR_U_: back = MF_CHAR_DIR_D_; break; case MF_CHAR_DIR_D_: back = MF_CHAR_DIR_U_; break; case MF_CHAR_DIR_L_: back = MF_CHAR_DIR_R_; break; case MF_CHAR_DIR_R_: back = MF_CHAR_DIR_L_; break; default: back = MF_CHAR_DIR_N_; break; } for (i = 0; i < 3; ++i) { if (dirs[i] == back) { t = dirs[i]; dirs[i] = dirs[3]; dirs[3] = t; } } for (i = 0; i < 4; ++i) { switch (dirs[i]) { case MF_CHAR_DIR_U_: dx = 0; dy = -1; break; case MF_CHAR_DIR_D_: dx = 0; dy = 1; break; case MF_CHAR_DIR_L_: dx = -1; dy = 0; break; case MF_CHAR_DIR_R_: dx = 1; dy = 0; break; default: dx = 0; dy = 0; break; } if (mf_maze_is_wall(c->maze, c->cur_x, c->cur_y, dx, dy)) { /* Wall ahead; don't go this direction. */ continue; } /* Move */ c->new_dir = dirs[i]; return 0; } return 0; } static int _mf_enemy_turn(struct mf_char *c) { /* Go straight */ c->new_dir = c->cur_dir; return 0; } static void _mf_enemy_collide(struct mf_char *c) { /* Don't go forward unless necessary */ switch (c->cur_dir) { case MF_CHAR_DIR_U_: c->cur_dir = MF_CHAR_DIR_D_; break; case MF_CHAR_DIR_D_: c->cur_dir = MF_CHAR_DIR_U_; break; case MF_CHAR_DIR_L_: c->cur_dir = MF_CHAR_DIR_R_; break; case MF_CHAR_DIR_R_: c->cur_dir = MF_CHAR_DIR_L_; break; default: c->cur_dir = MF_CHAR_DIR_N_; break; } _mf_enemy_step(c); } static int _mf_enemy_render(struct mf_char *c, SDL_Renderer *renderer) { struct mf_enemy *p = (struct mf_enemy *) c; if (p->next_enemy != NULL) { return mf_char_render(p->next_enemy, renderer); } else { return 0; } } static void _mf_enemy_destroy(struct mf_char *c) { struct mf_enemy *p = (struct mf_enemy *) c; mf_char_destroy(&p->next_enemy); } struct mf_char * mf_enemy_new(struct mf_maze *maze, int cell_width, int maze_size, struct mf_char *prev_enemy) { struct mf_char *c; struct mf_enemy *p __attribute__((__unused__)); mf_char_init(c, p, enemy); c->maze = maze; c->cell_width = cell_width; c->speed = MF_ENEMY_SPEED; c->new_dir = MF_CHAR_DIR_N_; c->turning = 0; c->turn_time = MF_ENEMY_TURN_TIME; c->cur_x = 0; c->cur_y = 0; c->travel = 0; c->padding = MF_ENEMY_P; c->smile_y = MF_ENEMY_SMILE_Y; c->smile_r = MF_ENEMY_SMILE_R; c->eye_x = MF_ENEMY_EYE_X; c->eye_y = MF_ENEMY_EYE_Y; c->eye_r = MF_ENEMY_EYE_R; c->head_color.r = MF_COLOR_ELYR_R, c->head_color.g = MF_COLOR_ELYR_G; c->head_color.b = MF_COLOR_ELYR_B, c->head_color.a = MF_COLOR_ELYR_A; c->smil_color.r = MF_COLOR_ESML_R, c->smil_color.g = MF_COLOR_ESML_G; c->smil_color.b = MF_COLOR_ESML_B, c->smil_color.a = MF_COLOR_ESML_A; c->eyes_color.r = MF_COLOR_EEYE_R, c->eyes_color.g = MF_COLOR_EEYE_G; c->eyes_color.b = MF_COLOR_EEYE_B, c->eyes_color.a = MF_COLOR_EEYE_A; while (c->cur_x < maze_size * MF_ENEMY_MIN_DIST && c->cur_y < maze_size * MF_ENEMY_MIN_DIST) { mf_enemy_random_jump(c, maze_size); } c->cur_dir = MF_CHAR_DIR_N_; _mf_enemy_step(c); c->cur_dir = c->new_dir; if (prev_enemy != NULL) { ((struct mf_enemy *) prev_enemy)->next_enemy = c; } return c; } void mf_enemy_random_jump(struct mf_char *c, int maze_size) { c->cur_x = rand() / (RAND_MAX / maze_size); c->cur_y = rand() / (RAND_MAX / maze_size); }