/* 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; }