summaryrefslogtreecommitdiff
path: root/kon/konrpg.c
diff options
context:
space:
mode:
Diffstat (limited to 'kon/konrpg.c')
-rw-r--r--kon/konrpg.c152
1 files changed, 152 insertions, 0 deletions
diff --git a/kon/konrpg.c b/kon/konrpg.c
new file mode 100644
index 0000000..f56c098
--- /dev/null
+++ b/kon/konrpg.c
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * konrpg.c
+ *
+ * Copyright (c) 2026 KonAki
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "konrpg.h"
+
+/*** directions ***/
+
+void kon_dirDelta(kon_dir_t dir, int *dx, int *dy)
+{
+ *dx = 0;
+ *dy = 0;
+ switch (dir) {
+ case KON_DIR_DOWN: *dy = 1; break;
+ case KON_DIR_LEFT: *dx = -1; break;
+ case KON_DIR_RIGHT: *dx = 1; break;
+ case KON_DIR_UP: *dy = -1; break;
+ }
+}
+
+kon_dir_t kon_dirOpposite(kon_dir_t dir)
+{
+ switch (dir) {
+ case KON_DIR_DOWN: return KON_DIR_UP;
+ case KON_DIR_LEFT: return KON_DIR_RIGHT;
+ case KON_DIR_RIGHT: return KON_DIR_LEFT;
+ case KON_DIR_UP: break;
+ }
+ return KON_DIR_DOWN;
+}
+
+/*** actors ***/
+
+void kon_actorInit(kon_actor_t *actor, int column, int row, kon_dir_t facing)
+{
+ kon_actor_t zero = {0};
+
+ *actor = zero;
+ actor->column = actor->fromColumn = column;
+ actor->row = actor->fromRow = row;
+ actor->facing = facing;
+ actor->progress = 1.0f;
+ actor->speed = 4.0f;
+}
+
+int kon_actorWalk(kon_actor_t *actor, const kon_tilemap_t *map, const uint8_t *solid, int solidCount, kon_dir_t dir, kon_blockFn blocked, void *user)
+{
+ int dx, dy, column, row, id;
+
+ if (!map || actor->moving) return 0;
+ actor->facing = dir;
+ kon_dirDelta(dir, &dx, &dy);
+ column = actor->column + dx;
+ row = actor->row + dy;
+
+ if (column < 0 || row < 0 || column >= map->columns || row >= map->rows) return 0;
+ id = kon_tilemapAt(map, column, row);
+ if (solid && id < solidCount && solid[id]) return 0;
+ if (blocked && blocked(column, row, user)) return 0;
+
+ actor->fromColumn = actor->column;
+ actor->fromRow = actor->row;
+ actor->column = column;
+ actor->row = row;
+ actor->moving = 1;
+ actor->progress = actor->carry * actor->speed;
+ if (actor->progress >= 1.0f) actor->progress = 0.999f;
+ actor->carry = 0.0f;
+ return 1;
+}
+
+int kon_actorUpdate(kon_actor_t *actor, float dt)
+{
+ if (!actor->moving) {
+ actor->carry = 0.0f;
+ return 0;
+ }
+ if (!(dt > 0.0f) || !(actor->speed > 0.0f)) return 0;
+
+ actor->progress += actor->speed * dt;
+ if (actor->progress < 1.0f) return 0;
+
+ actor->carry = (actor->progress - 1.0f) / actor->speed;
+ actor->progress = 1.0f;
+ actor->moving = 0;
+ return 1;
+}
+
+void kon_actorPixel(const kon_actor_t *actor, const kon_tilemap_t *map, float *x, float *y)
+{
+ float t = actor->moving ? actor->progress : 1.0f;
+ float fromX = (float)(actor->fromColumn * map->tileWidth), fromY = (float)(actor->fromRow * map->tileHeight);
+ float toX = (float)(actor->column * map->tileWidth), toY = (float)(actor->row * map->tileHeight);
+
+ *x = fromX + (toX - fromX) * t;
+ *y = fromY + (toY - fromY) * t;
+}
+
+void kon_actorFront(const kon_actor_t *actor, int *column, int *row)
+{
+ int dx, dy;
+
+ kon_dirDelta(actor->facing, &dx, &dy);
+ *column = actor->column + dx;
+ *row = actor->row + dy;
+}
+
+/*** events ***/
+
+int kon_eventAt(const kon_tileEvent_t *events, int count, int column, int row, int trigger)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (events[i].column != column || events[i].row != row) continue;
+ if (trigger >= 0 && (int)events[i].trigger != trigger) continue;
+ return i;
+ }
+ return -1;
+}
+
+int kon_eventBlocks(int column, int row, void *user)
+{
+ const kon_eventList_t *list = user;
+ int i;
+
+ for (i = 0; i < list->count; i++) {
+ if (list->events[i].blocks && list->events[i].column == column && list->events[i].row == row) return 1;
+ }
+ return 0;
+}