summaryrefslogtreecommitdiffstats
path: root/src/char/char.c
diff options
context:
space:
mode:
authorP. J. McDermott <pj@pehjota.net>2021-08-08 19:37:53 (EDT)
committer P. J. McDermott <pj@pehjota.net>2021-08-08 19:37:53 (EDT)
commit9080d731d73b8ffbb1598f622e3bdd05e8f1938e (patch)
treefe19814b3c1365f72d9122f93677ce4a76bbe6bf /src/char/char.c
parentc2bac04684e11dad54cb1dba224fb860e879834c (diff)
downloadmazefight-9080d731d73b8ffbb1598f622e3bdd05e8f1938e.zip
mazefight-9080d731d73b8ffbb1598f622e3bdd05e8f1938e.tar.gz
mazefight-9080d731d73b8ffbb1598f622e3bdd05e8f1938e.tar.bz2
char: New "class", absorbing player
Diffstat (limited to 'src/char/char.c')
-rw-r--r--src/char/char.c327
1 files changed, 327 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;
+}