summaryrefslogtreecommitdiffstats
path: root/src/char
diff options
context:
space:
mode:
Diffstat (limited to 'src/char')
-rw-r--r--src/char/char.c327
-rw-r--r--src/char/char.h74
-rw-r--r--src/char/local.mk4
-rw-r--r--src/char/player.c136
4 files changed, 541 insertions, 0 deletions
diff --git a/src/char/char.c b/src/char/char.c
new file mode 100644
index 0000000..09aa6bd
--- /dev/null
+++ b/src/char/char.c
@@ -0,0 +1,327 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <SDL.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../char.h"
+#include "char.h"
+
+struct mf_char *
+mf_char_new(size_t size)
+{
+ struct mf_char *c;
+
+ c = calloc(1, size);
+ if (c == NULL) {
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
+ "Couldn't create character: %s",
+ strerror(errno));
+ return NULL;
+ }
+
+ return c;
+}
+
+void
+mf_char_get_vector(struct mf_char *c, int *x, int *y, int *travel,
+ int *dx, int *dy)
+{
+ *x = c->cur_x;
+ *y = c->cur_y;
+ *travel = c->travel;
+ 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;
+ }
+}
+
+int
+mf_char_update(struct mf_char *c)
+{
+ int dx;
+ int dy;
+
+ if (c->travel > 0) {
+ /* Currently moving */
+ c->travel += c->speed;
+ if (c->travel >= c->cell_width) {
+ /* Reached next cell */
+ c->cur_x = c->new_x;
+ c->cur_y = c->new_y;
+ if (c->cur_dir == c->new_dir) {
+ /* Want to continue straight */
+ c->travel -= c->cell_width;
+ } else {
+ /* Want to stop or turn */
+ c->travel = 0;
+ }
+ } else {
+ /* Farther to go */
+ goto end;
+ }
+ }
+ if (c->new_dir != MF_CHAR_DIR_N_ && c->cur_dir != c->new_dir) {
+ /* Want to turn */
+ c->old_dir = c->cur_dir;
+ c->cur_dir = c->new_dir;
+ c->new_dir = MF_CHAR_DIR_N_;
+ c->turning = c->turn_time + 1;
+ }
+ if (c->turning > 0) {
+ /* Turning */
+ --c->turning;
+ }
+ if (c->turning == 0) {
+ /* Done turning */
+ if (c->new_dir != MF_CHAR_DIR_N_) {
+ /* Want to move */
+ switch (c->new_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;
+ }
+ c->new_dir = MF_CHAR_DIR_N_;
+ if (mf_maze_is_wall(c->maze, c->cur_x, c->cur_y,
+ dx, dy)) {
+ goto end;
+ }
+ c->new_x = c->cur_x + dx;
+ c->new_y = c->cur_y + dy;
+ c->travel += c->speed;
+ }
+ }
+
+ end:
+ return c->update(c);
+}
+
+int
+mf_char_render(struct mf_char *c, SDL_Renderer *renderer)
+{
+ int e = 0;
+ int cx;
+ int cy;
+ double fx;
+ double ofx;
+ int r;
+ int x;
+ int y;
+ int i;
+ int oy;
+ int fr;
+ int hy;
+ int ox;
+
+ cx = c->cur_x * c->cell_width + c->cell_width / 2;
+ cy = c->cur_y * c->cell_width + c->cell_width / 2;
+ switch (c->cur_dir) {
+ case MF_CHAR_DIR_U_:
+ cy -= c->travel;
+ if (c->old_dir == MF_CHAR_DIR_L_) {
+ fx = -2.0;
+ } else {
+ fx = 2.0;
+ }
+ break;
+ case MF_CHAR_DIR_D_: cy += c->travel; fx = 0.0; break;
+ case MF_CHAR_DIR_L_: cx -= c->travel; fx = -1.0; break;
+ case MF_CHAR_DIR_R_: cx += c->travel; fx = 1.0; break;
+ default: fx = 0.0; break;
+ }
+ switch (c->old_dir) {
+ case MF_CHAR_DIR_U_:
+ if (c->cur_dir == MF_CHAR_DIR_L_) {
+ ofx = -2.0;
+ } else {
+ ofx = 2.0;
+ }
+ break;
+ case MF_CHAR_DIR_D_: ofx = 0.0; break;
+ case MF_CHAR_DIR_L_: ofx = -1.0; break;
+ case MF_CHAR_DIR_R_: ofx = 1.0; break;
+ default: ofx = 0.0; break;
+ }
+ r = c->cell_width / 2 - c->padding;
+ fx = ofx + (fx - ofx) * (c->turn_time - c->turning) / c->turn_time;
+ fx *= r;
+
+ /*
+ * Head
+ */
+
+ if (SDL_SetRenderDrawColor(renderer,
+ c->head_color.r, c->head_color.g,
+ c->head_color.b, c->head_color.a) < 0) {
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
+ "Couldn't render character: %s",
+ SDL_GetError());
+ e = -1;
+ }
+
+#define _mf_char_px(X, Y) \
+ do { \
+ if (SDL_RenderDrawPoint(renderer, cx + X, cy + Y) < 0) { \
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \
+ "Couldn't render widget: %s", \
+ SDL_GetError()); \
+ e = -1; \
+ } \
+ } while (0)
+
+ /* TODO: This is one pixel larger than it should be. */
+ for (x = 0, y = r; y > x; ++x) {
+ y = round(sqrt((r-0.5)*(r-0.5) - (x-0.5)*(x-0.5)) + 0.5);
+ for (i = 0; i <= y; ++i) _mf_char_px( x, i);
+ for (i = 0; i >= 0-y; --i) _mf_char_px( x, i);
+ for (i = 0; i <= y; ++i) _mf_char_px(0-x, i);
+ for (i = 0; i >= 0-y; --i) _mf_char_px(0-x, i);
+ for (i = 0; i <= y; ++i) _mf_char_px( i, x);
+ for (i = 0; i <= y; ++i) _mf_char_px( i, 0-x);
+ for (i = 0; i >= 0-y; --i) _mf_char_px( i, x);
+ for (i = 0; i >= 0-y; --i) _mf_char_px( i, 0-x);
+ }
+
+#undef _mf_char_px
+
+ /*
+ * Smile
+ */
+
+ if (SDL_SetRenderDrawColor(renderer,
+ c->smil_color.r, c->smil_color.g,
+ c->smil_color.b, c->smil_color.a) < 0) {
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
+ "Couldn't render character: %s",
+ SDL_GetError());
+ e = -1;
+ }
+
+ oy = r * c->smile_y;
+ fr = r * c->smile_r;
+
+#define _mf_char_px(X, Y) \
+ do { \
+ hy = round(sqrt((r-0.5)*(r-0.5) - \
+ (X+fx-0.5)*(X+fx-0.5)) + 0.5); \
+ if (Y + oy < 0-hy || Y + oy > hy) continue; \
+ if (SDL_RenderDrawPoint(renderer, cx + fx + X, cy + oy + Y) \
+ < 0) { \
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \
+ "Couldn't render widget: %s", \
+ SDL_GetError()); \
+ e = -1; \
+ } \
+ } while (0)
+
+ for (x = 0, y = fr; y > x; ++x) {
+ y = round(sqrt((fr-0.5)*(fr-0.5) - (x-0.5)*(x-0.5)) + 0.5);
+ for (i = 0; i <= y; ++i) _mf_char_px( x, i);
+ for (i = 0; i <= y; ++i) _mf_char_px(0-x, i);
+ for (i = 0; i <= y; ++i) _mf_char_px( i, x);
+ for (i = 0; i >= 0-y; --i) _mf_char_px( i, x);
+ }
+
+#undef _mf_char_px
+
+ /*
+ * Eyes
+ */
+
+ if (SDL_SetRenderDrawColor(renderer,
+ c->eyes_color.r, c->eyes_color.g,
+ c->eyes_color.b, c->eyes_color.a) < 0) {
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
+ "Couldn't render character: %s",
+ SDL_GetError());
+ e = -1;
+ }
+
+ ox = r * c->eye_x;
+ oy = r * c->eye_y;
+ fr = r * c->eye_r;
+
+#define _mf_char_px(X, Y) \
+ do { \
+ hy = round(sqrt((r-0.5)*(r-0.5) - \
+ (X+fx-ox-0.5)*(X+fx-ox-0.5)) + 0.5); \
+ if (Y - oy >= 0-hy && Y - oy <= hy) { \
+ if (SDL_RenderDrawPoint(renderer, \
+ cx + fx - ox + X, cy - oy + Y) \
+ < 0) { \
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \
+ "Couldn't render widget: %s", \
+ SDL_GetError()); \
+ e = -1; \
+ } \
+ } \
+ hy = round(sqrt((r-0.5)*(r-0.5) - \
+ (X+fx+ox-0.5)*(X+fx+ox-0.5)) + 0.5); \
+ if (Y - oy >= 0-hy && Y - oy <= hy) { \
+ if (SDL_RenderDrawPoint(renderer, \
+ cx + fx + ox + X, cy - oy + Y) \
+ < 0) { \
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \
+ "Couldn't render widget: %s", \
+ SDL_GetError()); \
+ e = -1; \
+ } \
+ } \
+ } while (0)
+
+ for (x = 0, y = fr; y > x; ++x) {
+ y = round(sqrt((fr-0.5)*(fr-0.5) - (x-0.5)*(x-0.5)) + 0.5);
+ for (i = 0; i <= y; ++i) _mf_char_px( x, i);
+ for (i = 0; i >= 0-y; --i) _mf_char_px( x, i);
+ for (i = 0; i <= y; ++i) _mf_char_px(0-x, i);
+ for (i = 0; i >= 0-y; --i) _mf_char_px(0-x, i);
+ for (i = 0; i <= y; ++i) _mf_char_px( i, x);
+ for (i = 0; i <= y; ++i) _mf_char_px( i, 0-x);
+ for (i = 0; i >= 0-y; --i) _mf_char_px( i, x);
+ for (i = 0; i >= 0-y; --i) _mf_char_px( i, 0-x);
+ }
+
+#undef _mf_char_px
+
+ if (e < 0) {
+ return e;
+ }
+ return c->render(c, renderer);
+}
+
+void
+mf_char_destroy(struct mf_char **c_p)
+{
+ struct mf_char *c;
+
+ if (c_p == NULL || *c_p == NULL) {
+ return;
+ }
+ c = *c_p;
+
+ c->destroy(c);
+ free(c);
+ c = NULL;
+}
diff --git a/src/char/char.h b/src/char/char.h
new file mode 100644
index 0000000..f6c6b9f
--- /dev/null
+++ b/src/char/char.h
@@ -0,0 +1,74 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MF_CHAR_CHAR_H
+#define MF_CHAR_CHAR_H
+
+enum _mf_char_dir {
+ MF_CHAR_DIR_N_,
+ MF_CHAR_DIR_U_,
+ MF_CHAR_DIR_D_,
+ MF_CHAR_DIR_L_,
+ MF_CHAR_DIR_R_
+};
+
+struct mf_char {
+ struct mf_maze *maze;
+ int cell_width;
+ int speed;
+ enum _mf_char_dir cur_dir;
+ enum _mf_char_dir new_dir;
+ enum _mf_char_dir old_dir;
+ int turning;
+ int turn_time;
+ int cur_x;
+ int cur_y;
+ int new_x;
+ int new_y;
+ int travel;
+ int padding;
+ double smile_y;
+ double smile_r;
+ double eye_x;
+ double eye_y;
+ double eye_r;
+ SDL_Color head_color;
+ SDL_Color smil_color;
+ SDL_Color eyes_color;
+ int (*update)(struct mf_char *);
+ int (*render)(struct mf_char *, SDL_Renderer *);
+ void (*destroy)(struct mf_char *);
+};
+
+struct mf_char *
+mf_char_new(size_t size);
+
+#define mf_char_init(c, t_c, name) \
+ do { \
+ c = mf_char_new(sizeof(struct mf_##name)); \
+ if (c == NULL) { \
+ return NULL; \
+ }; \
+ c->update = &_mf_##name##_update; \
+ c->render = &_mf_##name##_render; \
+ c->destroy = &_mf_##name##_destroy; \
+ t_c = (struct mf_##name *) c; \
+ } while (0)
+
+#endif /* MF_CHAR_CHAR_H */
diff --git a/src/char/local.mk b/src/char/local.mk
new file mode 100644
index 0000000..92134a8
--- /dev/null
+++ b/src/char/local.mk
@@ -0,0 +1,4 @@
+mazefight_SOURCES += \
+ %reldir%/char.c \
+ %reldir%/char.h \
+ %reldir%/player.c
diff --git a/src/char/player.c b/src/char/player.c
new file mode 100644
index 0000000..9f6123d
--- /dev/null
+++ b/src/char/player.c
@@ -0,0 +1,136 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <SDL.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../char.h"
+#include "../defs.h"
+#include "../maze.h"
+#include "char.h"
+
+struct mf_player {
+ struct mf_char parent;
+};
+
+static int
+_mf_player_update(struct mf_char *c)
+{
+ int dx;
+ int dy;
+ int x;
+ int y;
+
+ 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;
+ }
+ x = c->cur_x - dx, y = c->cur_y - dy;
+ do {
+ x += dx, y += dy;
+ mf_maze_reveal_wall(c->maze, x, y, -1, 0);
+ mf_maze_reveal_wall(c->maze, x, y, 1, 0);
+ mf_maze_reveal_wall(c->maze, x, y, 0, -1);
+ mf_maze_reveal_wall(c->maze, x, y, 0, 1);
+ } while (!mf_maze_is_wall(c->maze, x, y, dx, dy));
+
+ return 0;
+}
+
+static int
+_mf_player_render(struct mf_char *c __attribute__((__unused__)),
+ SDL_Renderer *renderer __attribute__((__unused__)))
+{
+ return 0;
+}
+
+static void
+_mf_player_destroy(struct mf_char *c __attribute__((__unused__)))
+{
+}
+
+struct mf_char *
+mf_player_new(struct mf_maze *maze, int cell_width)
+{
+ struct mf_char *c;
+ struct mf_player *p __attribute__((__unused__));
+
+ mf_char_init(c, p, player);
+
+ c->maze = maze;
+ c->cell_width = cell_width;
+ c->speed = MF_PLAYER_SPEED;
+ c->new_dir = MF_CHAR_DIR_N_;
+ c->turning = 0;
+ c->turn_time = MF_PLAYER_TURN_TIME;
+ c->cur_x = 0;
+ c->cur_y = 0;
+ c->travel = 0;
+ c->padding = MF_PLAYER_P;
+ c->smile_y = MF_PLAYER_SMILE_Y;
+ c->smile_r = MF_PLAYER_SMILE_R;
+ c->eye_x = MF_PLAYER_EYE_X;
+ c->eye_y = MF_PLAYER_EYE_Y;
+ c->eye_r = MF_PLAYER_EYE_R;
+
+ c->head_color.r = MF_COLOR_PLYR_R, c->head_color.g = MF_COLOR_PLYR_G;
+ c->head_color.b = MF_COLOR_PLYR_B, c->head_color.a = MF_COLOR_PLYR_A;
+ c->smil_color.r = MF_COLOR_PSML_R, c->smil_color.g = MF_COLOR_PSML_G;
+ c->smil_color.b = MF_COLOR_PSML_B, c->smil_color.a = MF_COLOR_PSML_A;
+ c->eyes_color.r = MF_COLOR_PEYE_R, c->eyes_color.g = MF_COLOR_PEYE_G;
+ c->eyes_color.b = MF_COLOR_PEYE_B, c->eyes_color.a = MF_COLOR_PEYE_A;
+
+ if (mf_maze_is_wall(maze, 0, 0, 1, 0)) {
+ c->old_dir = c->cur_dir = MF_CHAR_DIR_D_;
+ } else {
+ c->old_dir = c->cur_dir = MF_CHAR_DIR_R_;
+ }
+
+ return c;
+}
+
+void
+mf_player_key_event(struct mf_char *c, SDL_Event *e)
+{
+ switch (e->type) {
+ case SDL_KEYDOWN:
+ switch (e->key.keysym.sym) {
+ case SDLK_UP:
+ c->new_dir = MF_CHAR_DIR_U_;
+ break;
+ case SDLK_DOWN:
+ c->new_dir = MF_CHAR_DIR_D_;
+ break;
+ case SDLK_LEFT:
+ c->new_dir = MF_CHAR_DIR_L_;
+ break;
+ case SDLK_RIGHT:
+ c->new_dir = MF_CHAR_DIR_R_;
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+}