/*
* 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;
int num_allies;
struct mf_char **allies;
int waiting;
};
static int
_mf_enemy_step(struct mf_char *c)
{
struct mf_enemy *e = (struct mf_enemy *) 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;
}
for (j = 0; j < e->num_allies; ++j) {
if (e->allies[j] == c) {
/* Found self */
continue;
}
if (e->allies[j]->cur_x == c->cur_x + dx &&
e->allies[j]->cur_y == c->cur_y + dy) {
/* Another enemy currently in this direction */
goto next_dir;
}
if (e->allies[j]->new_x == c->cur_x + dx &&
e->allies[j]->new_y == c->cur_y + dy) {
/* Another enemy moving in this direction */
goto next_dir;
}
}
/* Move */
c->new_dir = dirs[i];
e->waiting = SDL_FALSE;
return 0;
next_dir:
continue;
}
c->new_dir = MF_CHAR_DIR_N_;
e->waiting = SDL_TRUE;
return 0;
}
static int
_mf_enemy_turn(struct mf_char *c)
{
struct mf_enemy *e = (struct mf_enemy *) c;
int dx;
int dy;
int i;
switch (c->cur_dir) {
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;
}
for (i = 0; i < e->num_allies; ++i) {
if (e->allies[i] == c) {
/* Found self */
continue;
}
if (e->allies[i]->cur_x == c->cur_x + dx &&
e->allies[i]->cur_y == c->cur_y + dy) {
/* Another enemy currently in this direction */
return 0;
}
if (e->allies[i]->new_x == c->cur_x + dx &&
e->allies[i]->new_y == c->cur_y + dy) {
/* Another enemy moving in this direction */
return 0;
}
}
/* Go straight */
c->new_dir = c->cur_dir;
return 0;
}
static int
_mf_enemy_update(struct mf_char *c)
{
struct mf_enemy *e = (struct mf_enemy *) c;
if (e->waiting == SDL_TRUE) {
return _mf_enemy_step(c);
} else {
return 0;
}
}
static int
_mf_enemy_render(struct mf_char *c __attribute__((__unused__)),
SDL_Renderer *renderer __attribute__((__unused__)))
{
return 0;
}
static void
_mf_enemy_destroy(struct mf_char *c __attribute__((__unused__)))
{
}
struct mf_char *
mf_enemy_new(struct mf_maze *maze, int cell_width, int maze_size,
int num_allies, struct mf_char **allies)
{
struct mf_char *c;
struct mf_enemy *e;
int collide;
int i;
mf_char_init(c, e, 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;
do {
collide = SDL_FALSE;
if (c->cur_x < maze_size * MF_ENEMY_MIN_DIST &&
c->cur_y < maze_size * MF_ENEMY_MIN_DIST) {
collide = SDL_TRUE;
} else {
for (i = 0; i < num_allies; ++i) {
if (allies[i] != NULL &&
c->cur_x == allies[i]->cur_x &&
c->cur_y == allies[i]->cur_y) {
collide = SDL_TRUE;
}
}
}
if (collide == SDL_TRUE) {
mf_enemy_random_jump(c, maze_size);
}
} while (collide == SDL_TRUE);
c->cur_dir = MF_CHAR_DIR_N_;
_mf_enemy_step(c);
c->cur_dir = c->new_dir;
e->num_allies = num_allies;
e->allies = allies;
e->waiting = SDL_FALSE;
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);
}