Mercurial > molko
changeset 434:4e78f045e8c0
rpg: cleanup hierarchy
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sat, 15 Oct 2022 21:24:17 +0200 |
parents | 862b15c3a3ae |
children | 556c8e2ff995 |
files | GNUmakefile examples/example-action/example-action.c examples/example-message/example-message.c examples/example/character-john.c examples/example/spell-fire.c libmlk-rpg/assets/sql/character-load.sql libmlk-rpg/assets/sql/character-save.sql libmlk-rpg/assets/sql/init.sql libmlk-rpg/assets/sql/property-load.sql libmlk-rpg/assets/sql/property-remove.sql libmlk-rpg/assets/sql/property-save.sql libmlk-rpg/assets/sql/quest-remove.sql libmlk-rpg/assets/sql/quest-save.sql libmlk-rpg/assets/sql/quest-step-load.sql libmlk-rpg/assets/sql/quest-step-save.sql libmlk-rpg/mlk/rpg/battle-bar-default.c libmlk-rpg/mlk/rpg/battle-bar-default.h libmlk-rpg/mlk/rpg/battle-bar.c libmlk-rpg/mlk/rpg/battle-bar.h libmlk-rpg/mlk/rpg/battle-entity-state-attacking.c libmlk-rpg/mlk/rpg/battle-entity-state-attacking.h libmlk-rpg/mlk/rpg/battle-entity-state-blinking.c libmlk-rpg/mlk/rpg/battle-entity-state-blinking.h libmlk-rpg/mlk/rpg/battle-entity-state-moving.c libmlk-rpg/mlk/rpg/battle-entity-state-moving.h libmlk-rpg/mlk/rpg/battle-entity-state-normal.c libmlk-rpg/mlk/rpg/battle-entity-state-normal.h libmlk-rpg/mlk/rpg/battle-entity-state.c libmlk-rpg/mlk/rpg/battle-entity-state.h libmlk-rpg/mlk/rpg/battle-entity.c libmlk-rpg/mlk/rpg/battle-entity.h libmlk-rpg/mlk/rpg/battle-indicator.c libmlk-rpg/mlk/rpg/battle-indicator.h libmlk-rpg/mlk/rpg/battle-message.c libmlk-rpg/mlk/rpg/battle-message.h libmlk-rpg/mlk/rpg/battle-state-ai.c libmlk-rpg/mlk/rpg/battle-state-ai.h libmlk-rpg/mlk/rpg/battle-state-attacking.c libmlk-rpg/mlk/rpg/battle-state-attacking.h libmlk-rpg/mlk/rpg/battle-state-check.c libmlk-rpg/mlk/rpg/battle-state-check.h libmlk-rpg/mlk/rpg/battle-state-closing.c libmlk-rpg/mlk/rpg/battle-state-closing.h libmlk-rpg/mlk/rpg/battle-state-item.c libmlk-rpg/mlk/rpg/battle-state-item.h libmlk-rpg/mlk/rpg/battle-state-lost.c libmlk-rpg/mlk/rpg/battle-state-lost.h libmlk-rpg/mlk/rpg/battle-state-menu.c libmlk-rpg/mlk/rpg/battle-state-menu.h libmlk-rpg/mlk/rpg/battle-state-opening.c libmlk-rpg/mlk/rpg/battle-state-opening.h libmlk-rpg/mlk/rpg/battle-state-rendering.c libmlk-rpg/mlk/rpg/battle-state-rendering.h libmlk-rpg/mlk/rpg/battle-state-selection.c libmlk-rpg/mlk/rpg/battle-state-selection.h libmlk-rpg/mlk/rpg/battle-state-victory.c libmlk-rpg/mlk/rpg/battle-state-victory.h libmlk-rpg/mlk/rpg/battle-state.c libmlk-rpg/mlk/rpg/battle-state.h libmlk-rpg/mlk/rpg/battle.c libmlk-rpg/mlk/rpg/battle.h libmlk-rpg/mlk/rpg/character.c libmlk-rpg/mlk/rpg/character.h libmlk-rpg/mlk/rpg/equipment.c libmlk-rpg/mlk/rpg/equipment.h libmlk-rpg/mlk/rpg/inventory.c libmlk-rpg/mlk/rpg/inventory.h libmlk-rpg/mlk/rpg/item.c libmlk-rpg/mlk/rpg/item.h libmlk-rpg/mlk/rpg/map-file.c libmlk-rpg/mlk/rpg/map-file.h libmlk-rpg/mlk/rpg/map.c libmlk-rpg/mlk/rpg/map.h libmlk-rpg/mlk/rpg/message.c libmlk-rpg/mlk/rpg/message.h libmlk-rpg/mlk/rpg/property.c libmlk-rpg/mlk/rpg/property.h libmlk-rpg/mlk/rpg/quest.c libmlk-rpg/mlk/rpg/quest.h libmlk-rpg/mlk/rpg/rpg.c libmlk-rpg/mlk/rpg/rpg.h libmlk-rpg/mlk/rpg/save.c libmlk-rpg/mlk/rpg/save.h libmlk-rpg/mlk/rpg/selection.c libmlk-rpg/mlk/rpg/selection.h libmlk-rpg/mlk/rpg/spell.c libmlk-rpg/mlk/rpg/spell.h libmlk-rpg/mlk/rpg/team.c libmlk-rpg/mlk/rpg/team.h libmlk-rpg/mlk/rpg/tileset-file.c libmlk-rpg/mlk/rpg/tileset-file.h libmlk-rpg/mlk/rpg/tileset.c libmlk-rpg/mlk/rpg/tileset.h libmlk-rpg/mlk/rpg/walksprite.c libmlk-rpg/mlk/rpg/walksprite.h src/libmlk-rpg/assets/sql/character-load.sql src/libmlk-rpg/assets/sql/character-save.sql src/libmlk-rpg/assets/sql/init.sql src/libmlk-rpg/assets/sql/property-load.sql src/libmlk-rpg/assets/sql/property-remove.sql src/libmlk-rpg/assets/sql/property-save.sql src/libmlk-rpg/assets/sql/quest-remove.sql src/libmlk-rpg/assets/sql/quest-save.sql src/libmlk-rpg/assets/sql/quest-step-load.sql src/libmlk-rpg/assets/sql/quest-step-save.sql src/libmlk-rpg/rpg/battle-bar-default.c src/libmlk-rpg/rpg/battle-bar-default.h src/libmlk-rpg/rpg/battle-bar.c src/libmlk-rpg/rpg/battle-bar.h src/libmlk-rpg/rpg/battle-entity-state-attacking.c src/libmlk-rpg/rpg/battle-entity-state-attacking.h src/libmlk-rpg/rpg/battle-entity-state-blinking.c src/libmlk-rpg/rpg/battle-entity-state-blinking.h src/libmlk-rpg/rpg/battle-entity-state-moving.c src/libmlk-rpg/rpg/battle-entity-state-moving.h src/libmlk-rpg/rpg/battle-entity-state-normal.c src/libmlk-rpg/rpg/battle-entity-state-normal.h src/libmlk-rpg/rpg/battle-entity-state.c src/libmlk-rpg/rpg/battle-entity-state.h src/libmlk-rpg/rpg/battle-entity.c src/libmlk-rpg/rpg/battle-entity.h src/libmlk-rpg/rpg/battle-indicator.c src/libmlk-rpg/rpg/battle-indicator.h src/libmlk-rpg/rpg/battle-message.c src/libmlk-rpg/rpg/battle-message.h src/libmlk-rpg/rpg/battle-state-ai.c src/libmlk-rpg/rpg/battle-state-ai.h src/libmlk-rpg/rpg/battle-state-attacking.c src/libmlk-rpg/rpg/battle-state-attacking.h src/libmlk-rpg/rpg/battle-state-check.c src/libmlk-rpg/rpg/battle-state-check.h src/libmlk-rpg/rpg/battle-state-closing.c src/libmlk-rpg/rpg/battle-state-closing.h src/libmlk-rpg/rpg/battle-state-item.c src/libmlk-rpg/rpg/battle-state-item.h src/libmlk-rpg/rpg/battle-state-lost.c src/libmlk-rpg/rpg/battle-state-lost.h src/libmlk-rpg/rpg/battle-state-menu.c src/libmlk-rpg/rpg/battle-state-menu.h src/libmlk-rpg/rpg/battle-state-opening.c src/libmlk-rpg/rpg/battle-state-opening.h src/libmlk-rpg/rpg/battle-state-rendering.c src/libmlk-rpg/rpg/battle-state-rendering.h src/libmlk-rpg/rpg/battle-state-selection.c src/libmlk-rpg/rpg/battle-state-selection.h src/libmlk-rpg/rpg/battle-state-victory.c src/libmlk-rpg/rpg/battle-state-victory.h src/libmlk-rpg/rpg/battle-state.c src/libmlk-rpg/rpg/battle-state.h src/libmlk-rpg/rpg/battle.c src/libmlk-rpg/rpg/battle.h src/libmlk-rpg/rpg/character.c src/libmlk-rpg/rpg/character.h src/libmlk-rpg/rpg/equipment.c src/libmlk-rpg/rpg/equipment.h src/libmlk-rpg/rpg/inventory.c src/libmlk-rpg/rpg/inventory.h src/libmlk-rpg/rpg/item.c src/libmlk-rpg/rpg/item.h src/libmlk-rpg/rpg/map-file.c src/libmlk-rpg/rpg/map-file.h src/libmlk-rpg/rpg/map.c src/libmlk-rpg/rpg/map.h src/libmlk-rpg/rpg/message.c src/libmlk-rpg/rpg/message.h src/libmlk-rpg/rpg/property.c src/libmlk-rpg/rpg/property.h src/libmlk-rpg/rpg/quest.c src/libmlk-rpg/rpg/quest.h src/libmlk-rpg/rpg/rpg.c src/libmlk-rpg/rpg/rpg.h src/libmlk-rpg/rpg/save.c src/libmlk-rpg/rpg/save.h src/libmlk-rpg/rpg/selection.c src/libmlk-rpg/rpg/selection.h src/libmlk-rpg/rpg/spell.c src/libmlk-rpg/rpg/spell.h src/libmlk-rpg/rpg/team.c src/libmlk-rpg/rpg/team.h src/libmlk-rpg/rpg/tileset-file.c src/libmlk-rpg/rpg/tileset-file.h src/libmlk-rpg/rpg/tileset.c src/libmlk-rpg/rpg/tileset.h src/libmlk-rpg/rpg/walksprite.c src/libmlk-rpg/rpg/walksprite.h tests/test-character.c tests/test-map.c tests/test-save-quest.c tests/test-save.c tests/test-tileset.c |
diffstat | 190 files changed, 9071 insertions(+), 9072 deletions(-) [+] |
line wrap: on
line diff
--- a/GNUmakefile Sat Oct 15 21:19:25 2022 +0200 +++ b/GNUmakefile Sat Oct 15 21:24:17 2022 +0200 @@ -44,7 +44,7 @@ -Ilibmlk-util \ -Ilibmlk-core \ -Ilibmlk-ui \ - -Isrc/libmlk-rpg \ + -Ilibmlk-rpg \ -I. \ $(SDL2_INCS) \ $(SDL2_IMAGE_INCS) \ @@ -254,59 +254,59 @@ # {{{ libmlk-rpg LIBMLK_RPG := libmlk-rpg.a -LIBMLK_RPG_SRCS := src/libmlk-rpg/rpg/battle-bar-default.c \ - src/libmlk-rpg/rpg/battle-bar.c \ - src/libmlk-rpg/rpg/battle-entity-state-attacking.c \ - src/libmlk-rpg/rpg/battle-entity-state-blinking.c \ - src/libmlk-rpg/rpg/battle-entity-state-moving.c \ - src/libmlk-rpg/rpg/battle-entity-state-normal.c \ - src/libmlk-rpg/rpg/battle-entity-state.c \ - src/libmlk-rpg/rpg/battle-entity.c \ - src/libmlk-rpg/rpg/battle-indicator.c \ - src/libmlk-rpg/rpg/battle-message.c \ - src/libmlk-rpg/rpg/battle-state-ai.c \ - src/libmlk-rpg/rpg/battle-state-attacking.c \ - src/libmlk-rpg/rpg/battle-state-check.c \ - src/libmlk-rpg/rpg/battle-state-closing.c \ - src/libmlk-rpg/rpg/battle-state-item.c \ - src/libmlk-rpg/rpg/battle-state-lost.c \ - src/libmlk-rpg/rpg/battle-state-menu.c \ - src/libmlk-rpg/rpg/battle-state-opening.c \ - src/libmlk-rpg/rpg/battle-state-rendering.c \ - src/libmlk-rpg/rpg/battle-state-selection.c \ - src/libmlk-rpg/rpg/battle-state-victory.c \ - src/libmlk-rpg/rpg/battle-state.c \ - src/libmlk-rpg/rpg/battle.c \ - src/libmlk-rpg/rpg/character.c \ - src/libmlk-rpg/rpg/equipment.c \ - src/libmlk-rpg/rpg/inventory.c \ - src/libmlk-rpg/rpg/item.c \ - src/libmlk-rpg/rpg/map-file.c \ - src/libmlk-rpg/rpg/map.c \ - src/libmlk-rpg/rpg/message.c \ - src/libmlk-rpg/rpg/property.c \ - src/libmlk-rpg/rpg/quest.c \ - src/libmlk-rpg/rpg/rpg.c \ - src/libmlk-rpg/rpg/save.c \ - src/libmlk-rpg/rpg/selection.c \ - src/libmlk-rpg/rpg/spell.c \ - src/libmlk-rpg/rpg/team.c \ - src/libmlk-rpg/rpg/tileset-file.c \ - src/libmlk-rpg/rpg/tileset.c \ - src/libmlk-rpg/rpg/walksprite.c +LIBMLK_RPG_SRCS := libmlk-rpg/mlk/rpg/battle-bar-default.c \ + libmlk-rpg/mlk/rpg/battle-bar.c \ + libmlk-rpg/mlk/rpg/battle-entity-state-attacking.c \ + libmlk-rpg/mlk/rpg/battle-entity-state-blinking.c \ + libmlk-rpg/mlk/rpg/battle-entity-state-moving.c \ + libmlk-rpg/mlk/rpg/battle-entity-state-normal.c \ + libmlk-rpg/mlk/rpg/battle-entity-state.c \ + libmlk-rpg/mlk/rpg/battle-entity.c \ + libmlk-rpg/mlk/rpg/battle-indicator.c \ + libmlk-rpg/mlk/rpg/battle-message.c \ + libmlk-rpg/mlk/rpg/battle-state-ai.c \ + libmlk-rpg/mlk/rpg/battle-state-attacking.c \ + libmlk-rpg/mlk/rpg/battle-state-check.c \ + libmlk-rpg/mlk/rpg/battle-state-closing.c \ + libmlk-rpg/mlk/rpg/battle-state-item.c \ + libmlk-rpg/mlk/rpg/battle-state-lost.c \ + libmlk-rpg/mlk/rpg/battle-state-menu.c \ + libmlk-rpg/mlk/rpg/battle-state-opening.c \ + libmlk-rpg/mlk/rpg/battle-state-rendering.c \ + libmlk-rpg/mlk/rpg/battle-state-selection.c \ + libmlk-rpg/mlk/rpg/battle-state-victory.c \ + libmlk-rpg/mlk/rpg/battle-state.c \ + libmlk-rpg/mlk/rpg/battle.c \ + libmlk-rpg/mlk/rpg/character.c \ + libmlk-rpg/mlk/rpg/equipment.c \ + libmlk-rpg/mlk/rpg/inventory.c \ + libmlk-rpg/mlk/rpg/item.c \ + libmlk-rpg/mlk/rpg/map-file.c \ + libmlk-rpg/mlk/rpg/map.c \ + libmlk-rpg/mlk/rpg/message.c \ + libmlk-rpg/mlk/rpg/property.c \ + libmlk-rpg/mlk/rpg/quest.c \ + libmlk-rpg/mlk/rpg/rpg.c \ + libmlk-rpg/mlk/rpg/save.c \ + libmlk-rpg/mlk/rpg/selection.c \ + libmlk-rpg/mlk/rpg/spell.c \ + libmlk-rpg/mlk/rpg/team.c \ + libmlk-rpg/mlk/rpg/tileset-file.c \ + libmlk-rpg/mlk/rpg/tileset.c \ + libmlk-rpg/mlk/rpg/walksprite.c LIBMLK_RPG_OBJS := $(LIBMLK_RPG_SRCS:.c=.o) LIBMLK_RPG_DEPS := $(LIBMLK_RPG_SRCS:.c=.d) -LIBMLK_RPG_DATA_SRCS := src/libmlk-rpg/assets/sql/character-load.sql \ - src/libmlk-rpg/assets/sql/character-save.sql \ - src/libmlk-rpg/assets/sql/init.sql \ - src/libmlk-rpg/assets/sql/property-load.sql \ - src/libmlk-rpg/assets/sql/property-remove.sql \ - src/libmlk-rpg/assets/sql/property-save.sql \ - src/libmlk-rpg/assets/sql/quest-remove.sql \ - src/libmlk-rpg/assets/sql/quest-save.sql \ - src/libmlk-rpg/assets/sql/quest-step-load.sql \ - src/libmlk-rpg/assets/sql/quest-step-save.sql +LIBMLK_RPG_DATA_SRCS := libmlk-rpg/assets/sql/character-load.sql \ + libmlk-rpg/assets/sql/character-save.sql \ + libmlk-rpg/assets/sql/init.sql \ + libmlk-rpg/assets/sql/property-load.sql \ + libmlk-rpg/assets/sql/property-remove.sql \ + libmlk-rpg/assets/sql/property-save.sql \ + libmlk-rpg/assets/sql/quest-remove.sql \ + libmlk-rpg/assets/sql/quest-save.sql \ + libmlk-rpg/assets/sql/quest-step-load.sql \ + libmlk-rpg/assets/sql/quest-step-save.sql LIBMLK_RPG_DATA_OBJS := $(addsuffix .h,$(basename $(LIBMLK_RPG_DATA_SRCS))) $(LIBMLK_RPG_DATA_OBJS): BCC_OPTS := -cs0
--- a/examples/example-action/example-action.c Sat Oct 15 21:19:25 2022 +0200 +++ b/examples/example-action/example-action.c Sat Oct 15 21:24:17 2022 +0200 @@ -38,8 +38,8 @@ #include <mlk/ui/theme.h> #include <mlk/ui/ui.h> -#include <rpg/message.h> -#include <rpg/rpg.h> +#include <mlk/rpg/message.h> +#include <mlk/rpg/rpg.h> #include <assets/sprites/chest.h> #include <assets/sprites/people.h>
--- a/examples/example-message/example-message.c Sat Oct 15 21:19:25 2022 +0200 +++ b/examples/example-message/example-message.c Sat Oct 15 21:24:17 2022 +0200 @@ -32,8 +32,8 @@ #include <mlk/ui/theme.h> #include <mlk/ui/ui.h> -#include <rpg/message.h> -#include <rpg/rpg.h> +#include <mlk/rpg/message.h> +#include <mlk/rpg/rpg.h> #define W (1280) #define H (720)
--- a/examples/example/character-john.c Sat Oct 15 21:19:25 2022 +0200 +++ b/examples/example/character-john.c Sat Oct 15 21:24:17 2022 +0200 @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <rpg/character.h> +#include <mlk/rpg/character.h> #include "character-john.h" #include "spell-fire.h"
--- a/examples/example/spell-fire.c Sat Oct 15 21:19:25 2022 +0200 +++ b/examples/example/spell-fire.c Sat Oct 15 21:24:17 2022 +0200 @@ -25,11 +25,11 @@ #include <mlk/ui/align.h> -#include <rpg/battle-state-check.h> -#include <rpg/battle-state-rendering.h> -#include <rpg/battle.h> -#include <rpg/character.h> -#include <rpg/spell.h> +#include <mlk/rpg/battle-state-check.h> +#include <mlk/rpg/battle-state-rendering.h> +#include <mlk/rpg/battle.h> +#include <mlk/rpg/character.h> +#include <mlk/rpg/spell.h> #include "registry.h" #include "spell-fire.h"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/assets/sql/character-load.sql Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,30 @@ +-- +-- character-load.sql -- load a character data +-- +-- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> +-- +-- Permission to use, copy, modify, and/or distribute this software for any +-- purpose with or without fee is hereby granted, provided that the above +-- copyright notice and this permission notice appear in all copies. +-- +-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-- + +SELECT hp + , mp + , level + , team_order + , bonus_hp + , bonus_mp + , bonus_atk + , bonus_def + , bonus_agt + , bonus_luck + FROM character + WHERE name = ?
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/assets/sql/character-save.sql Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,44 @@ +-- +-- character-save.sql -- save or replace character +-- +-- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> +-- +-- Permission to use, copy, modify, and/or distribute this software for any +-- purpose with or without fee is hereby granted, provided that the above +-- copyright notice and this permission notice appear in all copies. +-- +-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-- + +INSERT OR REPLACE INTO character( + name, + hp, + mp, + level, + team_order, + bonus_hp, + bonus_mp, + bonus_atk, + bonus_def, + bonus_agt, + bonus_luck +) +VALUES( + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ? +)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/assets/sql/init.sql Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,55 @@ +-- +-- init.sql -- initialize database +-- +-- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> +-- +-- Permission to use, copy, modify, and/or distribute this software for any +-- purpose with or without fee is hereby granted, provided that the above +-- copyright notice and this permission notice appear in all copies. +-- +-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-- + +BEGIN EXCLUSIVE TRANSACTION; + +CREATE TABLE IF NOT EXISTS property( + id INTEGER PRIMARY KEY AUTOINCREMENT, + key TEXT NOT NULL UNIQUE, + value TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS character( + name TEXT PRIMARY KEY, + hp INTEGER NOT NULL, + mp INTEGER NOT NULL, + level INTEGER NOT NULL, + team_order INTEGER DEFAULT -1, + bonus_hp INTEGER DEFAULT 0, + bonus_mp INTEGER DEFAULT 0, + bonus_atk INTEGER DEFAULT 0, + bonus_def INTEGER DEFAULT 0, + bonus_agt INTEGER DEFAULT 0, + bonus_luck INTEGER DEFAULT 0 +); + +CREATE TABLE IF NOT EXISTS quest( + name TEXT PRIMARY KEY +); + +CREATE TABLE IF NOT EXISTS quest_step( + name TEXT PRIMARY KEY, + percent INTEGER DEFAULT 0, + quest_name TEXT NOT NULL, + FOREIGN KEY(quest_name) REFERENCES quest(name) +); + +INSERT OR IGNORE INTO property(key, value) VALUES ('molko.create-date', strftime('%s','now')); +INSERT OR IGNORE INTO property(key, value) VALUES ('molko.update-date', strftime('%s','now')); + +COMMIT;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/assets/sql/property-load.sql Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,21 @@ +-- +-- property-load.sql -- get a property +-- +-- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> +-- +-- Permission to use, copy, modify, and/or distribute this software for any +-- purpose with or without fee is hereby granted, provided that the above +-- copyright notice and this permission notice appear in all copies. +-- +-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-- + +SELECT value + FROM property + WHERE key = ?
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/assets/sql/property-remove.sql Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,21 @@ +-- +-- property-remove.sql -- remove a property +-- +-- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> +-- +-- Permission to use, copy, modify, and/or distribute this software for any +-- purpose with or without fee is hereby granted, provided that the above +-- copyright notice and this permission notice appear in all copies. +-- +-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-- + +DELETE + FROM property + WHERE key = ?
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/assets/sql/property-save.sql Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,26 @@ +-- +-- property-save.sql -- set a property +-- +-- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> +-- +-- Permission to use, copy, modify, and/or distribute this software for any +-- purpose with or without fee is hereby granted, provided that the above +-- copyright notice and this permission notice appear in all copies. +-- +-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-- + +INSERT OR REPLACE INTO property( + key, + value +) +VALUES( + ?, + ? +)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/assets/sql/quest-remove.sql Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,21 @@ +-- +-- quest-remove.sql -- remove a quest entirely +-- +-- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> +-- +-- Permission to use, copy, modify, and/or distribute this software for any +-- purpose with or without fee is hereby granted, provided that the above +-- copyright notice and this permission notice appear in all copies. +-- +-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-- + +DELETE + FROM quest + WHERE name = ?
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/assets/sql/quest-save.sql Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,24 @@ +-- +-- quest-save.sql -- create parent quest entry +-- +-- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> +-- +-- Permission to use, copy, modify, and/or distribute this software for any +-- purpose with or without fee is hereby granted, provided that the above +-- copyright notice and this permission notice appear in all copies. +-- +-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-- + +INSERT INTO quest( + name +) +VALUES( + ? +)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/assets/sql/quest-step-load.sql Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,21 @@ +-- +-- quest-step-load.sql -- remove a quest entirely +-- +-- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> +-- +-- Permission to use, copy, modify, and/or distribute this software for any +-- purpose with or without fee is hereby granted, provided that the above +-- copyright notice and this permission notice appear in all copies. +-- +-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-- + +SELECT percent + FROM quest_step + WHERE name = ?
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/assets/sql/quest-step-save.sql Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,27 @@ +-- +-- quest-step-save.sql -- save a quest step +-- +-- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> +-- +-- Permission to use, copy, modify, and/or distribute this software for any +-- purpose with or without fee is hereby granted, provided that the above +-- copyright notice and this permission notice appear in all copies. +-- +-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-- + +INSERT INTO quest_step( + quest_name, + name, + percent +) VALUES( + ?, + ?, + ? +)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-bar-default.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,693 @@ +/* + * battle-bar-default.c -- default battle status bar and menu implementation + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/event.h> +#include <mlk/core/font.h> +#include <mlk/core/sprite.h> +#include <mlk/core/trace.h> +#include <mlk/core/util.h> +#include <mlk/core/window.h> + +#include <mlk/ui/align.h> +#include <mlk/ui/theme.h> + +#include "battle-bar-default.h" +#include "battle-bar.h" +#include "battle-state-item.h" +#include "battle-state-selection.h" +#include "battle.h" +#include "character.h" +#include "inventory.h" +#include "item.h" +#include "spell.h" + +#define THEME(bar) ((bar)->theme ? (bar)->theme : theme_default()) + +struct geo { + int x, y; + unsigned int w, h; +}; + +static inline void +dimensions(struct geo geo[2], const struct battle_bar_default *bar) +{ + /* 0 == main menu */ + geo[0].w = bar->w * 0.2; + geo[0].h = bar->h; + geo[0].x = bar->x + (bar->w / 2) - (geo[0].w / 2); + geo[0].y = window.h - bar->h; + + /* 1 == status frame */ + geo[1].x = geo[0].x + geo[0].w; + geo[1].y = geo[0].y; + geo[1].w = (bar->w - geo[0].w) / 2; + geo[1].h = bar->h; +} + +/* + * The following validate_* functions are called when the user has validated a + * selection depending on the current menu (e.g. Magic, Items). + * + * They change the battle state to the appropriate one. + */ + +static void +validate_attack(struct battle_bar_default *bar, struct battle *bt, const struct selection *sel) +{ + (void)bar; + + struct character *target; + + if (sel->index_side == 0) + target = bt->enemies[sel->index_character]->ch; + else + target = bt->team[sel->index_character]->ch; + + battle_attack(bt, battle_current(bt)->ch, target); +} + +static void +validate_magic(struct battle_bar_default *bar, struct battle *bt, const struct selection *sel) +{ + struct character *source = battle_current(bt)->ch; + const struct spell *spell = source->spells[bar->grid.selected]; + + battle_cast(bt, source, spell, sel); +} + +static void +validate_item(struct battle_bar_default *bar, struct battle *bt, const struct selection *sel) +{ + struct inventory_slot *slot; + struct battle_entity *source, *target; + + if (bar->grid.selected >= INVENTORY_ITEM_MAX) + return; + if (!(slot = &bt->inventory->items[bar->grid.selected])) + return; + + source = battle_current(bt); + target = sel->index_side == 0 + ? bt->enemies[sel->index_character] + : bt->team[sel->index_character]; + + /* TODO: battle_use? */ + battle_state_item(bt, source, target, slot); +} + +/* + * The following functions are used to switch to the battle selection state + * using the appropriate selector algorithm. For example, an item can only be + * used on a unique target while a spell can have multiple choices. + */ + +static void +switch_selection_attack(struct battle_bar_default *bar, struct battle *bt) +{ + struct selection sel = { + .allowed_kinds = SELECTION_KIND_ONE, + .allowed_sides = SELECTION_SIDE_ENEMY, + .index_side = 0 + }; + + /* Disable handling anymore. */ + bar->state = BATTLE_BAR_DEFAULT_STATE_NONE; + + selection_first(&sel, bt); + battle_state_selection(bt, &sel); +} + +static void +switch_selection_spell(struct battle_bar_default *bar, struct battle *bt) +{ + const struct character *ch = battle_current(bt)->ch; + const struct spell *sp = ch->spells[bar->grid.selected]; + struct selection sel = {0}; + + if (bar->grid.selected > CHARACTER_SPELL_MAX) + return; + if (!(sp = ch->spells[bar->grid.selected]) || sp->mp > (unsigned int)ch->mp) + return; + + /* Use the spell selection algorithm to fill default values. */ + spell_select(sp, bt, &sel); + battle_state_selection(bt, &sel); + + /* A cursor should be present. */ + if (!sprite_ok(BATTLE_THEME(bt)->sprites[THEME_SPRITE_CURSOR])) + tracef("battle: no cursor sprite in theme"); +} + +static void +switch_selection_item(struct battle *bt) +{ + const struct selection slt = { + .allowed_kinds = SELECTION_KIND_ONE, + .allowed_sides = SELECTION_SIDE_TEAM | SELECTION_SIDE_ENEMY, + .index_side = 1, + .index_character = battle_index(bt) + }; + + battle_state_selection(bt, &slt); +} + +/* + * The following functions actually draw the bar and their components depending + * on the current selected menu. + */ + +static void +draw_help(const struct battle_bar_default *bar, const char *what) +{ + struct label label = {0}; + unsigned int lw = 0, lh = 0; + + label.flags = LABEL_FLAGS_SHADOW; + label.text = what; + label_query(&label, &lw, &lh); + label.x = bar->grid.x + (bar->grid.w / 2) - (lw / 2); + label.y = bar->grid.y - lh - THEME(bar)->padding; + label_draw(&label); +} + +static void +draw_spell_help(const struct battle_bar_default *bar, const struct battle *bt) +{ + const struct character *ch = battle_current(bt)->ch; + const struct spell *sp; + + if (bar->grid.selected >= CHARACTER_SPELL_MAX) + return; + if (!(sp = ch->spells[bar->grid.selected])) + return; + + draw_help(bar, sp->description); +} + +static void +draw_item_help(const struct battle_bar_default *bar, const struct battle *bt) +{ + const struct inventory_slot *slot; + + if (bar->grid.selected >= INVENTORY_ITEM_MAX) + return; + + slot = &bt->inventory->items[bar->grid.selected]; + + if (!slot->item) + return; + + draw_help(bar, slot->item->description); +} + +static void +draw_status_character_stats(const struct battle_bar_default *bar, + const struct character *ch, + int x, + int y, + unsigned int h) +{ + const struct theme *theme = THEME(bar); + struct label label; + unsigned int spacing, lw, lh; + char line[64]; + + /* Compute spacing between elements. */ + spacing = h - (font_height(theme->fonts[THEME_FONT_INTERFACE]) * 3); + spacing /= 4; + + /* Reuse the same label. */ + label.theme = theme; + label.text = line; + label.flags = LABEL_FLAGS_SHADOW; + + /* Name. */ + snprintf(line, sizeof (line), "%s", ch->name); + label_query(&label, &lw, &lh); + label.x = x + theme->padding; + label.y = y + spacing; + label_draw(&label); + + /* HP. */ + snprintf(line, sizeof (line), "%d/%u", ch->hp, ch->hpmax); + label_query(&label, &lw, &lh); + label.x = x + theme->padding; + label.y = label.y + lh + spacing; + label_draw(&label); + + /* MP. */ + snprintf(line, sizeof (line), "%d/%u", ch->mp, ch->mpmax); + label_query(&label, &lw, &lh); + label.x = x + theme->padding; + label.y = label.y + lh + spacing; + label_draw(&label); + + /* Status. */ + /* TODO: list all status. */ +} + +static void +draw_status_character(const struct battle_bar_default *bar, + const struct battle *bt, + const struct character *ch, + const struct geo *geo, + unsigned int index) +{ + int x, y; + unsigned int w, h; + + /* Compute bounding box for rendering. */ + w = geo->w / bt->teamsz; + h = geo->h; + x = geo->x + (index * w); + y = geo->y; + + draw_status_character_stats(bar, ch, x, y, h); +} + +static void +draw_status_characters(const struct battle_bar_default *bar, + const struct battle *bt, + const struct geo *geo) +{ + const struct battle_entity *et; + unsigned int index = 0; + + BATTLE_TEAM_FOREACH(bt, et) { + if (character_ok(et->ch)) + draw_status_character(bar, bt, et->ch, geo, index); + + ++index; + } +} + +static void +draw_status(const struct battle_bar_default *bar, const struct battle *bt, const struct geo *geo) +{ + frame_draw(&(const struct frame) { + .x = geo->x, + .y = geo->y, + .w = geo->w, + .h = geo->h + }); + + draw_status_characters(bar, bt, geo); +} + +static void +draw_menu(const struct battle_bar_default *bar, const struct geo *geo) +{ + struct { + unsigned int w, h; + enum align align; + struct label label; + } buttons[] = { + { + .align = ALIGN_TOP, + .label = { + .text = "Attack", + .flags = LABEL_FLAGS_SHADOW + } + }, + { + .align = ALIGN_RIGHT, + .label = { + .text = "Magic", + .flags = LABEL_FLAGS_SHADOW + } + }, + { + .align = ALIGN_BOTTOM, + .label = { + .text = "Objects", + .flags = LABEL_FLAGS_SHADOW + } + }, + { + .align = ALIGN_LEFT, + .label = { + .text = "Special", + .flags = LABEL_FLAGS_SHADOW + } + } + }; + + const struct theme *theme = THEME(bar); + int bx, by; + unsigned int bw, bh; + + /* Compute bounding box with margins removed. */ + bx = geo->x + theme->padding; + by = geo->y + theme->padding; + bw = geo->w - theme->padding * 2; + bh = geo->h - theme->padding * 2; + + /* Draw menu frame. */ + frame_draw(&(const struct frame) { + .x = geo->x, + .y = geo->y, + .w = geo->w, + .h = geo->h + }); + + for (size_t i = 0; i < UTIL_SIZE(buttons); ++i) { + buttons[i].label.theme = theme; + + label_query(&buttons[i].label, &buttons[i].w, &buttons[i].h); + + /* Change theme if it's selected. */ + if ((size_t)bar->menu == i) + buttons[i].label.flags |= LABEL_FLAGS_SELECTED; + else + buttons[i].label.flags &= ~LABEL_FLAGS_SELECTED; + + align(buttons[i].align, + &buttons[i].label.x, &buttons[i].label.y, buttons[i].w, buttons[i].h, + bx, by, bw, bh); + label_draw(&buttons[i].label); + } +} + +/* + * This function is called only in the first level of the bar menu: selecting + * one of the Attack, Magic, Item and Special items. + */ +static void +handle_keydown_menu(struct battle_bar_default *bar, struct battle *bt, const union event *ev) +{ + (void)bt; + + switch (ev->key.key) { + case KEY_UP: + bar->menu = BATTLE_BAR_DEFAULT_MENU_ATTACK; + break; + case KEY_RIGHT: + bar->menu = BATTLE_BAR_DEFAULT_MENU_MAGIC; + break; + case KEY_DOWN: + bar->menu = BATTLE_BAR_DEFAULT_MENU_ITEM; + break; + case KEY_LEFT: + bar->menu = BATTLE_BAR_DEFAULT_MENU_SPECIAL; + break; + case KEY_ENTER: + /* + * At this step, attack does not require opening the sub menu so + * we change selection state immediately if needed. + */ + switch (bar->menu) { + case BATTLE_BAR_DEFAULT_MENU_ATTACK: + switch_selection_attack(bar, bt); + break; + case BATTLE_BAR_DEFAULT_MENU_ITEM: + battle_bar_default_open_item(bar, bt); + break; + case BATTLE_BAR_DEFAULT_MENU_MAGIC: + battle_bar_default_open_magic(bar, bt, battle_current(bt)->ch); + break; + default: + break; + } + break; + default: + break; + } +} + +/* + * This function is called when we're selecting a submenu entry from Items + * and Magic. + */ +static void +handle_keydown_grid(struct battle_bar_default *bar, struct battle *bt, const union event *ev) +{ + /* Go back to main menu if I press escape. */ + if (ev->key.key == KEY_ESCAPE) + bar->state = BATTLE_BAR_DEFAULT_STATE_MENU; + else if (gridmenu_handle(&bar->grid, ev)) { + switch (bar->menu) { + case BATTLE_BAR_DEFAULT_MENU_MAGIC: + switch_selection_spell(bar, bt); + break; + case BATTLE_BAR_DEFAULT_MENU_ITEM: + switch_selection_item(bt); + break; + default: + break; + } + } +} + +static void +handle_keydown(struct battle_bar_default *bar, struct battle *bt, const union event *ev) +{ + assert(ev->type == EVENT_KEYDOWN); + + static void (*handlers[])(struct battle_bar_default *, struct battle *, const union event *) = { + [BATTLE_BAR_DEFAULT_STATE_MENU] = handle_keydown_menu, + [BATTLE_BAR_DEFAULT_STATE_GRID] = handle_keydown_grid + }; + + if (handlers[bar->state]) + handlers[bar->state](bar, bt, ev); +} + +#if 0 + +static void +handle_clickdown(struct battle_bar_default *bar, struct battle *bt, const union event *ev) +{ + assert(ev->type == EVENT_CLICKDOWN); + + (void)bar; + (void)bt; + + switch (bar->state) { + case BATTLE_BAR_DEFAULT_STATE_MENU: + /* We are selecting a main menu entry. */ + /* TODO: implement click here too. */ + break; + case BATTLE_BAR_DEFAULT_STATE_SUB: + /* We are in the sub menu (objects/spells). */ + if (bar->sub_grid.state == GRIDMENU_STATE_ACTIVATED) + default: + break; + } + + return 0; +} + +#endif + +static void +self_start(struct battle_bar *bar, struct battle *bt) +{ + (void)bt; + + battle_bar_default_start(bar->data); +} + +static void +self_select(struct battle_bar *bar, struct battle *bt, const struct selection *sel) +{ + battle_bar_default_select(bar->data, bt, sel); +} + +static void +self_handle(struct battle_bar *bar, struct battle *bt, const union event *ev) +{ + battle_bar_default_handle(bar->data, bt, ev); +} + +static void +self_draw(const struct battle_bar *bar, const struct battle *bt) +{ + battle_bar_default_draw(bar->data, bt); +} + +void +battle_bar_default_init(struct battle_bar_default *bar) +{ + assert(bar); + + struct geo geo[2]; + + memset(bar, 0, sizeof (*bar)); + + bar->w = window.w; + bar->h = window.h * 0.12; + bar->x = 0; + bar->y = window.h - bar->h; + + dimensions(geo, bar); + + gridmenu_init(&bar->grid, 2, 2, NULL, 0); + gridmenu_resize(&bar->grid, bar->x, geo[0].y, geo[1].w, bar->h); + bar->grid.theme = bar->theme; +} + +void +battle_bar_default_open_magic(struct battle_bar_default *bar, const struct battle *bt, struct character *ch) +{ + assert(bar); + assert(bt); + assert(ch); + + (void)bt; + + bar->items = alloc_rearray0(bar->items, bar->itemsz, + CHARACTER_SPELL_MAX, sizeof (*bar->items)); + bar->itemsz = CHARACTER_SPELL_MAX; + bar->state = BATTLE_BAR_DEFAULT_STATE_GRID; + + for (size_t i = 0; i < CHARACTER_SPELL_MAX; ++i) + if (ch->spells[i]) + bar->items[i] = ch->spells[i]->name; + + bar->grid.items = bar->items; + bar->grid.itemsz = bar->itemsz; +} + +void +battle_bar_default_open_item(struct battle_bar_default *bar, const struct battle *bt) +{ + assert(bar); + assert(bt); + + /* TODO: not implemented yet. */ + (void)bar; + (void)bt; +#if 0 + for (size_t i = 0; i < INVENTORY_ITEM_MAX; ++i) { + if (bt->inventory->items[i].item) { + snprintf(bar->sub_items[i], sizeof (bar->sub_items[i]), "%-16s %u", + bt->inventory->items[i].item->name, bt->inventory->items[i].amount); + bar->sub_grid.menu[i] = bar->sub_items[i]; + } + } + + bar->state = BATTLE_BAR_DEFAULT_STATE_GRID; +#endif +} + +void +battle_bar_default_start(struct battle_bar_default *bar) +{ + assert(bar); + + bar->menu = BATTLE_BAR_DEFAULT_MENU_ATTACK; + bar->state = BATTLE_BAR_DEFAULT_STATE_MENU; +} + +/* + * Apply the battle selection for the current menu item. This function is called + * from the battle-state-selection state when the user validated the selection. + */ +void +battle_bar_default_select(struct battle_bar_default *bar, struct battle *bt, const struct selection *sel) +{ + assert(bar); + assert(bt); + assert(sel); + + static void (*validate[])(struct battle_bar_default *, struct battle *, const struct selection *) = { + [BATTLE_BAR_DEFAULT_MENU_ATTACK] = validate_attack, + [BATTLE_BAR_DEFAULT_MENU_ITEM] = validate_item, + [BATTLE_BAR_DEFAULT_MENU_MAGIC] = validate_magic, + [BATTLE_BAR_DEFAULT_MENU_SPECIAL] = NULL + }; + + if (validate[bar->menu]) + validate[bar->menu](bar, bt, sel); +} + +void +battle_bar_default_handle(struct battle_bar_default *bar, struct battle *bt, const union event *ev) +{ + assert(bar); + assert(bt); + assert(ev); + + static void (*handlers[])(struct battle_bar_default *, struct battle *, const union event *) = { + [EVENT_KEYDOWN] = handle_keydown, + [EVENT_NUM] = NULL + }; + + if (handlers[ev->type]) + handlers[ev->type](bar, bt, ev); +} + +void +battle_bar_default_draw(const struct battle_bar_default *bar, const struct battle *bt) +{ + assert(bar); + assert(bt); + + struct geo geo[2]; + + dimensions(geo, bar); + draw_menu(bar, &geo[0]); + draw_status(bar, bt, &geo[1]); + + if (bar->state == BATTLE_BAR_DEFAULT_STATE_GRID) { + switch (bar->menu) { + case BATTLE_BAR_DEFAULT_MENU_MAGIC: + draw_spell_help(bar, bt); + break; + case BATTLE_BAR_DEFAULT_MENU_ITEM: + draw_item_help(bar, bt); + break; + default: + break; + } + } + + /* Sub menu is only shown if state is set to it. */ + if (bar->state == BATTLE_BAR_DEFAULT_STATE_GRID) + gridmenu_draw(&bar->grid); +} + +void +battle_bar_default_finish(struct battle_bar_default *bar) +{ + assert(bar); + + free(bar->items); + memset(bar, 0, sizeof (*bar)); +} + +void +battle_bar_default(struct battle_bar_default *self, struct battle_bar *bar) +{ + assert(self); + assert(bar); + + memset(bar, 0, sizeof (*bar)); + + bar->data = self; + bar->start = self_start; + bar->select = self_select; + bar->handle = self_handle; + bar->draw = self_draw; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-bar-default.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,93 @@ +/* + * battle-bar-default.h -- default battle status bar and menu implementation + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_BAR_DEFAULT_H +#define MLK_RPG_BATTLE_BAR_DEFAULT_H + +#include <mlk/core/core.h> + +#include <mlk/ui/gridmenu.h> + +struct battle; +struct battle_bar; +struct character; +struct selection; +struct theme; + +union event; + +enum battle_bar_default_menu { + BATTLE_BAR_DEFAULT_MENU_ATTACK, + BATTLE_BAR_DEFAULT_MENU_MAGIC, + BATTLE_BAR_DEFAULT_MENU_ITEM, + BATTLE_BAR_DEFAULT_MENU_SPECIAL +}; + +enum battle_bar_default_state { + BATTLE_BAR_DEFAULT_STATE_NONE, + BATTLE_BAR_DEFAULT_STATE_MENU, + BATTLE_BAR_DEFAULT_STATE_GRID +}; + +struct battle_bar_default { + int x; + int y; + unsigned int w; + unsigned int h; + struct theme *theme; + enum battle_bar_default_state state; + enum battle_bar_default_menu menu; + + /* Private fields. */ + const char **items; + size_t itemsz; + struct gridmenu grid; +}; + +CORE_BEGIN_DECLS + +void +battle_bar_default_init(struct battle_bar_default *); + +void +battle_bar_default_open_magic(struct battle_bar_default *, const struct battle *, struct character *); + +void +battle_bar_default_open_item(struct battle_bar_default *, const struct battle *); + +void +battle_bar_default_start(struct battle_bar_default *); + +void +battle_bar_default_select(struct battle_bar_default *, struct battle *, const struct selection *); + +void +battle_bar_default_handle(struct battle_bar_default *, struct battle *, const union event *); + +void +battle_bar_default_draw(const struct battle_bar_default *, const struct battle *); + +void +battle_bar_default_finish(struct battle_bar_default *); + +void +battle_bar_default(struct battle_bar_default *, struct battle_bar *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_BATTLE_BAR_DEFAULT_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-bar.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,84 @@ +/* + * battle-bar.c -- abstract battle bar + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include "battle-bar.h" + +void +battle_bar_start(struct battle_bar *bar, struct battle *bt) +{ + assert(bar); + assert(bt); + + if (bar->start) + bar->start(bar, bt); +} + +void +battle_bar_select(struct battle_bar *bar, struct battle *bt, const struct selection *sel) +{ + assert(bar); + assert(bt); + assert(sel); + + if (bar->select) + bar->select(bar, bt, sel); + +} + +void +battle_bar_handle(struct battle_bar *bar, struct battle *bt, const union event *ev) +{ + assert(bar); + assert(bt); + assert(ev); + + if (bar->handle) + bar->handle(bar, bt, ev); +} + +void +battle_bar_update(struct battle_bar *bar, struct battle *bt, unsigned int ticks) +{ + assert(bar); + assert(bt); + + if (bar->update) + bar->update(bar, bt, ticks); +} + +void +battle_bar_draw(const struct battle_bar *bar, const struct battle *bt) +{ + assert(bar); + assert(bt); + + if (bar->draw) + bar->draw(bar, bt); +} + +void +battle_bar_finish(struct battle_bar *bar, struct battle *bt) +{ + assert(bar); + assert(bt); + + if (bar->finish) + bar->finish(bar, bt); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-bar.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,61 @@ +/* + * battle-bar.h -- abstract battle bar + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_BAR_H +#define MLK_RPG_BATTLE_BAR_H + +#include <mlk/core/core.h> + +struct battle; +struct selection; + +union event; + +struct battle_bar { + void *data; + void (*start)(struct battle_bar *, struct battle *); + void (*select)(struct battle_bar *, struct battle *, const struct selection *); + void (*handle)(struct battle_bar *, struct battle *, const union event *); + void (*update)(struct battle_bar *, struct battle *, unsigned int); + void (*draw)(const struct battle_bar *, const struct battle *); + void (*finish)(struct battle_bar *, struct battle *); +}; + +CORE_BEGIN_DECLS + +void +battle_bar_start(struct battle_bar *, struct battle *); + +void +battle_bar_select(struct battle_bar *, struct battle *, const struct selection *); + +void +battle_bar_handle(struct battle_bar *, struct battle *, const union event *); + +void +battle_bar_update(struct battle_bar *, struct battle *, unsigned int); + +void +battle_bar_draw(const struct battle_bar *, const struct battle *); + +void +battle_bar_finish(struct battle_bar *, struct battle *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_BATTLE_BAR_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-entity-state-attacking.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,101 @@ +/* + * battle-entity-state-attacking.h -- the entity is attacking + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/animation.h> +#include <mlk/core/panic.h> +#include <mlk/core/sprite.h> + +#include "battle-entity-state-attacking.h" +#include "battle-entity-state.h" +#include "battle-entity.h" + +struct self { + struct battle_entity_state_attacking data; + struct battle_entity_state state; +}; + +static int +update(struct battle_entity_state *st, struct battle_entity *et, unsigned int ticks) +{ + (void)et; + + return battle_entity_state_attacking_update(st->data, ticks); +} + +static void +draw(const struct battle_entity_state *st, const struct battle_entity *et) +{ + battle_entity_state_attacking_draw(st->data, et); +} + +static void +finish(struct battle_entity_state *st, struct battle_entity *et) +{ + (void)et; + + free(st->data); +} + +void +battle_entity_state_attacking_init(struct battle_entity_state_attacking *atk, const struct sprite *which) +{ + assert(atk); + assert(sprite_ok(which)); + + animation_init(&atk->anim, which, 100); + animation_start(&atk->anim); +} + +int +battle_entity_state_attacking_update(struct battle_entity_state_attacking *atk, unsigned int ticks) +{ + assert(atk); + + return animation_update(&atk->anim, ticks); +} + +void +battle_entity_state_attacking_draw(const struct battle_entity_state_attacking *atk, const struct battle_entity *et) +{ + assert(atk); + assert(battle_entity_ok(et)); + + animation_draw(&atk->anim, et->x, et->y); +} + +void +battle_entity_state_attacking(struct battle_entity *et, const struct sprite *which) +{ + assert(battle_entity_ok(et)); + assert(sprite_ok(which)); + + struct self *self; + + self = alloc_new0(sizeof (*self)); + self->state.data = self; + self->state.update = update; + self->state.draw = draw; + self->state.finish = finish; + + battle_entity_state_attacking_init(&self->data, which); + battle_entity_switch(et, &self->state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-entity-state-attacking.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,43 @@ +/* + * battle-entity-state-attacking.c -- the entity is attacking + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_ENTITY_STATE_ATTACKING_H +#define MLK_RPG_BATTLE_ENTITY_STATE_ATTACKING_H + +#include <mlk/core/animation.h> + +struct battle_entity; +struct sprite; + +struct battle_entity_state_attacking { + struct animation anim; +}; + +void +battle_entity_state_attacking_init(struct battle_entity_state_attacking *, const struct sprite *); + +int +battle_entity_state_attacking_update(struct battle_entity_state_attacking *, unsigned int); + +void +battle_entity_state_attacking_draw(const struct battle_entity_state_attacking *, const struct battle_entity *); + +void +battle_entity_state_attacking(struct battle_entity *, const struct sprite *); + +#endif /* !MLK_RPG_BATTLE_ENTITY_STATE_ATTACKING_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-entity-state-blinking.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,97 @@ +/* + * battle-entity-state-blinking.c -- the entity is blinking + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/panic.h> +#include <mlk/core/sprite.h> +#include <mlk/core/texture.h> + +#include "battle-entity-state-blinking.h" +#include "battle-entity-state.h" +#include "battle-entity.h" +#include "character.h" + +#define TRANSPARENT (150) +#define OPAQUE (255) + +struct self { + struct battle_entity_state_blinking data; + struct battle_entity_state state; +}; + +static int +update(struct battle_entity_state *st, struct battle_entity *et, unsigned int ticks) +{ + (void)et; + + return battle_entity_state_blinking_update(st->data, ticks); +} + +static void +finish(struct battle_entity_state *st, struct battle_entity *et) +{ + (void)et; + + free(st->data); +} + +void +battle_entity_state_blinking_init(struct battle_entity_state_blinking *blk, struct battle_entity *et) +{ + assert(blk); + assert(battle_entity_ok(et)); + + blk->tex = et->ch->sprites[CHARACTER_SPRITE_NORMAL]->texture; + texture_set_alpha_mod(blk->tex, TRANSPARENT); +} + +int +battle_entity_state_blinking_update(struct battle_entity_state_blinking *blk, unsigned int ticks) +{ + assert(blk); + + blk->elapsed += ticks; + + if (blk->elapsed >= 80) { + blk->count += 1; + blk->elapsed = 0; + } + + texture_set_alpha_mod(blk->tex, blk->count % 2 == 0 ? TRANSPARENT : OPAQUE); + + return blk->count >= 3; +} + +void +battle_entity_state_blinking(struct battle_entity *et) +{ + assert(battle_entity_ok(et)); + + struct self *self; + + self = alloc_new0(sizeof (*self)); + self->state.data = self; + self->state.update = update; + self->state.finish = finish; + + battle_entity_state_blinking_init(&self->data, et); + battle_entity_switch(et, &self->state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-entity-state-blinking.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,40 @@ +/* + * battle-entity-state-blinking.h -- the entity is blinking + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_ENTITY_STATE_BLINKING_H +#define MLK_RPG_BATTLE_ENTITY_STATE_BLINKING_H + +struct battle_entity; +struct texture; + +struct battle_entity_state_blinking { + struct texture *tex; + unsigned int elapsed; + unsigned int count; +}; + +void +battle_entity_state_blinking_init(struct battle_entity_state_blinking *, struct battle_entity *et); + +int +battle_entity_state_blinking_update(struct battle_entity_state_blinking *, unsigned int); + +void +battle_entity_state_blinking(struct battle_entity *); + +#endif /* !MLK_RPG_BATTLE_ENTITY_STATE_BLINKING_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-entity-state-moving.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,129 @@ +/* + * battle-entity-state-moving.c -- the entity is moving + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <math.h> +#include <stdlib.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/panic.h> + +#include "battle-entity-state-moving.h" +#include "battle-entity-state.h" +#include "battle-entity.h" +#include "character.h" +#include "walksprite.h" + +#define SPEED 800 +#define SEC 1000 +#define WALK 40 + +struct self { + struct battle_entity_state_moving data; + struct battle_entity_state state; +}; + +static inline unsigned int +orientation(const struct battle_entity_state_moving *mv, const struct battle_entity *et) +{ + /* TODO: support diagonal. */ + /* See: walksprite definitions. */ + return mv->x < et->x ? 6 : 2; +} + +static int +update(struct battle_entity_state *st, struct battle_entity *et, unsigned int ticks) +{ + return battle_entity_state_moving_update(st->data, et, ticks); +} + +static void +draw(const struct battle_entity_state *st, const struct battle_entity *et) +{ + battle_entity_state_moving_draw(st->data, et); +} + +static void +finish(struct battle_entity_state *st, struct battle_entity *et) +{ + (void)et; + + free(st->data); +} + +void +battle_entity_state_moving_init(struct battle_entity_state_moving *mv, struct battle_entity *et, int dstx, int dsty) +{ + assert(mv); + assert(battle_entity_ok(et)); + + walksprite_init(&mv->ws, et->ch->sprites[CHARACTER_SPRITE_NORMAL], 40); + mv->x = dstx; + mv->y = dsty; +} + +int +battle_entity_state_moving_update(struct battle_entity_state_moving *mv, struct battle_entity *et, unsigned int ticks) +{ + assert(mv); + assert(battle_entity_ok(et)); + + int step_x, step_y, delta_x, delta_y; + + delta_x = mv->x < et->x ? -1 : +1; + delta_y = mv->y < et->y ? -1 : +1; + step_x = fmin(SPEED * ticks / SEC, abs(et->x - mv->x)); + step_y = fmin(SPEED * ticks / SEC, abs(et->y - mv->y)); + + et->x += delta_x * step_x; + et->y += delta_y * step_y; + + if (et->x != mv->x || et->y != mv->y) + walksprite_update(&mv->ws, ticks); + else + walksprite_reset(&mv->ws); + + return et->x == mv->x && et->y == mv->y; +} + +void +battle_entity_state_moving_draw(const struct battle_entity_state_moving *mv, const struct battle_entity *et) +{ + assert(mv); + assert(battle_entity_ok(et)); + + /* TODO: compute orientation. */ + walksprite_draw(&mv->ws, orientation(mv, et), et->x, et->y); +} + +void +battle_entity_state_moving(struct battle_entity *et, int dstx, int dsty) +{ + assert(battle_entity_ok(et)); + + struct self *self; + + self = alloc_new0(sizeof (*self)); + self->state.data = self; + self->state.update = update; + self->state.draw = draw; + self->state.finish = finish; + + battle_entity_state_moving_init(&self->data, et, dstx, dsty); + battle_entity_switch(et, &self->state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-entity-state-moving.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,44 @@ +/* + * battle-entity-state-moving.h -- the entity is moving + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_ENTITY_STATE_MOVING_H +#define MLK_RPG_BATTLE_ENTITY_STATE_MOVING_H + +#include <mlk/rpg/walksprite.h> + +struct battle_entity; + +struct battle_entity_state_moving { + struct walksprite ws; + int x; + int y; +}; + +void +battle_entity_state_moving_init(struct battle_entity_state_moving *, struct battle_entity *, int, int); + +int +battle_entity_state_moving_update(struct battle_entity_state_moving *, struct battle_entity *, unsigned int); + +void +battle_entity_state_moving_draw(const struct battle_entity_state_moving *, const struct battle_entity *); + +void +battle_entity_state_moving(struct battle_entity *, int, int); + +#endif /* !MLK_RPG_BATTLE_ENTITY_STATE_MOVING_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-entity-state-normal.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,36 @@ +/* + * battle-entity-state-normal.c -- the entity is normal + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include "battle-entity-state-normal.h" +#include "battle-entity-state.h" +#include "battle-entity.h" + +/* TODO: animate characters when they are inactive. */ + +void +battle_entity_state_normal(struct battle_entity *et) +{ + assert(battle_entity_ok(et)); + + /* Not needed yet. */ + static struct battle_entity_state st; + + battle_entity_switch(et, &st); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-entity-state-normal.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,28 @@ +/* + * battle-entity-state-normal.h -- the entity is normal + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_ENTITY_STATE_NORMAL_H +#define MLK_RPG_BATTLE_ENTITY_STATE_NORMAL_H + +struct battle_entity; + +void +battle_entity_state_normal(struct battle_entity *); + +#endif /* !MLK_RPG_BATTLE_ENTITY_STATE_NORMAL_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-entity-state.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,55 @@ +/* + * battle-entity-state.c -- abstract battle entity state + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include "battle-entity.h" +#include "battle-entity-state.h" + +int +battle_entity_state_update(struct battle_entity_state *st, struct battle_entity *et, unsigned int ticks) +{ + assert(st); + assert(battle_entity_ok(et)); + + if (st->update) + return st->update(st, et, ticks); + + return 1; +} + +void +battle_entity_state_draw(const struct battle_entity_state *st, const struct battle_entity *et) +{ + assert(st); + assert(battle_entity_ok(et)); + + if (st->draw) + st->draw(st, et); + else + battle_entity_draw_sprite(et); +} + +void +battle_entity_state_finish(struct battle_entity_state *st, struct battle_entity *et) +{ + assert(battle_entity_ok(et)); + + if (st->finish) + st->finish(st, et); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-entity-state.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,47 @@ +/* + * battle-entity-state.h -- abstract battle entity state + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_ENTITY_STATE_H +#define MLK_RPG_BATTLE_ENTITY_STATE_H + +#include <mlk/core/core.h> + +struct battle_entity; +struct sprite; + +struct battle_entity_state { + void *data; + int (*update)(struct battle_entity_state *, struct battle_entity *, unsigned int); + void (*draw)(const struct battle_entity_state *, const struct battle_entity *); + void (*finish)(struct battle_entity_state *, struct battle_entity *); +}; + +CORE_BEGIN_DECLS + +int +battle_entity_state_update(struct battle_entity_state *, struct battle_entity *, unsigned int); + +void +battle_entity_state_draw(const struct battle_entity_state *, const struct battle_entity *); + +void +battle_entity_state_finish(struct battle_entity_state *, struct battle_entity *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_BATTLE_ENTITY_STATE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-entity.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,119 @@ +/* + * battle-entity.c -- in game battle entity + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include <mlk/core/sprite.h> +#include <mlk/core/texture.h> + +#include <mlk/ui/theme.h> + +#include "battle.h" +#include "battle-entity.h" +#include "battle-entity-state.h" +#include "battle-entity-state-normal.h" +#include "character.h" + +static void +draw_name(const struct battle_entity *et, const struct battle *bt) +{ + struct label label = et->name; + + label.theme = BATTLE_THEME(bt); + + if (et == battle_current(bt)) + label.flags |= LABEL_FLAGS_SELECTED; + else + label.flags &= ~LABEL_FLAGS_SELECTED; + + label_draw(&label); +} + +void +battle_entity_init(struct battle_entity *et) +{ + assert(et); + + character_reset(et->ch); + texture_set_alpha_mod(et->ch->sprites[CHARACTER_SPRITE_NORMAL]->texture, 255); + + battle_entity_state_normal(et); +} + +int +battle_entity_ok(const struct battle_entity *et) +{ + return et && character_ok(et->ch); +} + +void +battle_entity_switch(struct battle_entity *et, struct battle_entity_state *st) +{ + assert(et); + assert(st); + + if (et->state) + battle_entity_state_finish(et->state, et); + + et->state = st; +} + +int +battle_entity_update(struct battle_entity *et, unsigned int ticks) +{ + assert(et); + + return battle_entity_state_update(et->state, et, ticks); +} + +void +battle_entity_draw_sprite(const struct battle_entity *et) +{ + struct sprite *sprite = et->ch->sprites[CHARACTER_SPRITE_NORMAL]; + int row; + + /* + * Ennemies are usually defined with a single image as such the + * sprite may contain only one cell/row. Otherwise if the user + * have provided a structured sprite, use appropriate row. + */ + if (sprite->nrows >= 6) + row = 6; + else + row = 0; + + sprite_draw(sprite, row, 0, et->x, et->y); +} + +void +battle_entity_draw(const struct battle_entity *et, const struct battle *bt) +{ + assert(et); + assert(bt); + + draw_name(et, bt); + battle_entity_state_draw(et->state, et); +} + +void +battle_entity_finish(struct battle_entity *et) +{ + assert(et); + + battle_entity_state_finish(et->state, et); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-entity.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,63 @@ +/* + * battle-entity.h -- in game battle entity + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_ENTITY_H +#define MLK_RPG_BATTLE_ENTITY_H + +#include <mlk/core/core.h> + +#include <mlk/ui/label.h> + +struct battle; +struct battle_entity_state; +struct character; + +struct battle_entity { + struct character *ch; + int x; + int y; + struct label name; + struct battle_entity_state *state; +}; + +CORE_BEGIN_DECLS + +void +battle_entity_init(struct battle_entity *); + +int +battle_entity_ok(const struct battle_entity *); + +void +battle_entity_switch(struct battle_entity *, struct battle_entity_state *); + +int +battle_entity_update(struct battle_entity *, unsigned int); + +void +battle_entity_draw(const struct battle_entity *, const struct battle *); + +void +battle_entity_draw_sprite(const struct battle_entity *); + +void +battle_entity_finish(struct battle_entity *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_BATTLE_ENTITY_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-indicator.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,134 @@ +/* + * battle-indicator.c -- drawable for rendering a hp/mp count usage + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include <string.h> + +#include <mlk/core/color.h> +#include <mlk/core/font.h> +#include <mlk/core/panic.h> + +#include <mlk/ui/theme.h> + +#include "battle-indicator.h" + +#define THEME(bti) ((bti)->theme ? (bti)->theme : theme_default()) +#define STEP (2) +#define DELAY (5) + +static inline unsigned int +inc(int cmp, int tgt) +{ + return tgt > cmp ? fmin(cmp + STEP, tgt) : fmax(cmp - STEP, tgt); +} + +static inline int +colored(const struct battle_indicator *bti) +{ + /* Only check r, g, b and ignore alpha. */ + return COLOR_R(bti->cur) == COLOR_R(bti->color) && + COLOR_G(bti->cur) == COLOR_G(bti->color) && + COLOR_B(bti->cur) == COLOR_B(bti->color); +} + +void +battle_indicator_start(struct battle_indicator *bti) +{ + assert(bti); + + char buf[128]; + const struct theme *theme = THEME(bti); + + snprintf(buf, sizeof (buf), "%u", bti->amount); + + bti->cur = 0xffffffff; + bti->elapsed = 0; + bti->alpha = 250; + + if (font_render(theme->fonts[THEME_FONT_INTERFACE], &bti->tex[0], buf, bti->cur) < 0|| + font_render(theme->fonts[THEME_FONT_INTERFACE], &bti->tex[1], buf, 0x000000ff) < 0) + panic(); +} + +int +battle_indicator_completed(const struct battle_indicator *bti) +{ + assert(battle_indicator_ok(bti)); + + return colored(bti) && bti->alpha == 0; +} + +int +battle_indicator_ok(const struct battle_indicator *bti) +{ + return bti && texture_ok(&bti->tex[0]) && texture_ok(&bti->tex[1]); +} + +int +battle_indicator_update(struct battle_indicator *bti, unsigned int ticks) +{ + assert(battle_indicator_ok(bti)); + + bti->elapsed += ticks; + + if (bti->elapsed > DELAY) { + bti->elapsed = 0; + + if (!colored(bti)) { + /* Update colors first. */ + bti->cur = COLOR_HEX( + inc(COLOR_R(bti->cur), COLOR_R(bti->color)), + inc(COLOR_G(bti->cur), COLOR_G(bti->color)), + inc(COLOR_B(bti->cur), COLOR_B(bti->color)), + 255 + ); + + texture_set_color_mod(&bti->tex[0], bti->cur); + } else { + /* Update alpha next. */ + bti->alpha -= 10; + + texture_set_alpha_mod(&bti->tex[0], bti->alpha); + texture_set_alpha_mod(&bti->tex[1], bti->alpha); + } + } + + return battle_indicator_completed(bti); +} + +void +battle_indicator_draw(const struct battle_indicator *bti, int x, int y) +{ + assert(battle_indicator_ok(bti)); + + texture_draw(&bti->tex[1], x + 1, y + 1); + texture_draw(&bti->tex[0], x, y); +} + +void +battle_indicator_finish(struct battle_indicator *bti) +{ + assert(bti); + + texture_finish(&bti->tex[0]); + texture_finish(&bti->tex[1]); + + memset(bti, 0, sizeof (*bti)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-indicator.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,62 @@ +/* + * battle-indicator.h -- drawable for rendering a hp/mp count usage + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_INDICATOR_H +#define MLK_RPG_BATTLE_INDICATOR_H + +#include <mlk/core/core.h> +#include <mlk/core/texture.h> + +#define BATTLE_INDICATOR_HP_COLOR (0xa5303000) +#define BATTLE_INDICATOR_MP_COLOR (0xa23e8c00) + +struct theme; + +struct battle_indicator { + unsigned int color; + unsigned int amount; + const struct theme *theme; + unsigned int cur; + unsigned int elapsed; + unsigned int alpha; + struct texture tex[2]; +}; + +CORE_BEGIN_DECLS + +void +battle_indicator_start(struct battle_indicator *); + +int +battle_indicator_completed(const struct battle_indicator *); + +int +battle_indicator_ok(const struct battle_indicator *); + +int +battle_indicator_update(struct battle_indicator *, unsigned int); + +void +battle_indicator_draw(const struct battle_indicator *, int, int); + +void +battle_indicator_finish(struct battle_indicator *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_BATTLE_INDICATOR_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-message.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,69 @@ +/* + * battle-message.c -- automatic top center message in battle + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include <mlk/core/window.h> + +#include <mlk/ui/align.h> +#include <mlk/ui/frame.h> +#include <mlk/ui/label.h> + +#include "battle-message.h" + +#define DELAY 1500 + +int +battle_message_update(struct battle_message *msg, unsigned int ticks) +{ + assert(msg); + + msg->elapsed += ticks; + + return msg->elapsed >= DELAY; +} + +void +battle_message_draw(const struct battle_message *msg) +{ + assert(msg); + + struct frame f = {0}; + struct label l = {0}; + unsigned int lw = 0, lh = 0; + + /* Prepare message frame. */ + f.w = window.w / 3; + f.h = window.h / 15; + f.theme = msg->theme; + + /* Center on top. */ + align(ALIGN_TOP, &f.x, &f.y, f.w, f.h, 0, 20, window.w, window.h); + + /* Prepare message label box. */ + l.text = msg->text; + l.flags = LABEL_FLAGS_SHADOW; + l.theme = msg->theme; + label_query(&l, &lw, &lh); + + /* Align the text in the box. */ + align(ALIGN_CENTER, &l.x, &l.y, lw, lh, f.x, f.y, f.w, f.h); + + frame_draw(&f); + label_draw(&l); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-message.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,42 @@ +/* + * battle-message.h -- automatic top center message in battle + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_MESSAGE_H +#define MLK_RPG_BATTLE_MESSAGE_H + +#include <mlk/core/core.h> + +struct theme; + +struct battle_message { + const char *text; + struct theme *theme; + unsigned int elapsed; +}; + +CORE_BEGIN_DECLS + +int +battle_message_update(struct battle_message *, unsigned int); + +void +battle_message_draw(const struct battle_message *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_BATTLE_MESSAGE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-ai.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,92 @@ +/* + * battle-state-ai.c -- battle state (enemy is playing) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> + +#include <mlk/core/alloc.h> + +#include "battle-state-ai.h" +#include "battle-state.h" +#include "battle.h" +#include "character.h" + +static int +update(struct battle_state *st, struct battle *bt, unsigned int ticks) +{ + (void)st; + (void)ticks; + + battle_state_ai_update(bt); + + return 0; +} + +static void +draw(const struct battle_state *st, const struct battle *bt) +{ + (void)st; + + battle_state_ai_draw(bt); +} + +static void +finish(struct battle_state *st, struct battle *bt) +{ + (void)bt; + + free(st); +} + +void +battle_state_ai_update(struct battle *bt) +{ + assert(battle_ok(bt)); + + struct character *ch = battle_current(bt)->ch; + + /* + * Immediately invoke the enemy exec strategy and put the battle state + * to check. + */ + character_exec(ch, bt); +} + +void +battle_state_ai_draw(const struct battle *bt) +{ + assert(battle_ok(bt)); + + battle_draw_component(bt, BATTLE_COMPONENT_ALL); +} + +void +battle_state_ai(struct battle *bt) +{ + assert(bt); + + struct battle_state *self; + + self = alloc_new0(sizeof (*self)); + self->data = bt; + self->update = update; + self->draw = draw; + self->finish = finish; + + battle_switch(bt, self); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-ai.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,33 @@ +/* + * battle-state-ai.h -- battle state (enemy is playing) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_STATE_AI_H +#define MLK_RPG_BATTLE_STATE_AI_H + +struct battle; + +void +battle_state_ai_update(struct battle *); + +void +battle_state_ai_draw(const struct battle *); + +void +battle_state_ai(struct battle *); + +#endif /* !MLK_RPG_BATTLE_STATE_AI_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-attacking.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,176 @@ +/* + * battle-state-attacking.c -- battle state (entity is moving for attacking) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/panic.h> +#include <mlk/core/sprite.h> + +#include "battle-entity-state-attacking.h" +#include "battle-entity-state-blinking.h" +#include "battle-entity-state-moving.h" +#include "battle-entity-state-normal.h" +#include "battle-entity-state.h" +#include "battle-state-attacking.h" +#include "battle-state-check.h" +#include "battle-state.h" +#include "battle.h" +#include "character.h" + +struct self { + struct battle_state_attacking data; + struct battle_state state; +}; + +static void +damage(const struct battle_entity *source, struct battle_entity *target, struct battle *bt) +{ + (void)source; + + /* TODO: math calculation here.*/ + target->ch->hp -= 50; + + if (target->ch->hp < 0) + target->ch->hp = 0; + + battle_indicator_hp(bt, target->ch, 50); +} + +static int +update(struct battle_state *st, struct battle *bt, unsigned int ticks) +{ + battle_state_attacking_update(st->data, bt, ticks); + + return 0; +} + +static void +draw(const struct battle_state *st, const struct battle *bt) +{ + battle_state_attacking_draw(st->data, bt); +} + +static void +finish(struct battle_state *st, struct battle *bt) +{ + (void)bt; + + free(st->data); +} + +void +battle_state_attacking_init(struct battle_state_attacking *atk, + struct battle_entity *source, + struct battle_entity *target) +{ + assert(atk); + assert(battle_entity_ok(source)); + assert(battle_entity_ok(target)); + + int x, y; + + /* Starts this state with advancing. */ + atk->source = source; + atk->target = target; + atk->origin_x = source->x; + atk->origin_y = source->y; + + /* We go to the enemy. */ + x = target->x + target->ch->sprites[CHARACTER_SPRITE_NORMAL]->cellw; + y = target->y; + + /* If it is an enemy we don't move it but blink instead. */ + if (source->ch->exec) { + atk->status = BATTLE_STATE_ATTACKING_BLINKING; + battle_entity_state_blinking(source); + } else + battle_entity_state_moving(source, x, y); +} + +void +battle_state_attacking_update(struct battle_state_attacking *atk, struct battle *bt, unsigned int ticks) +{ + assert(atk); + assert(bt); + + battle_update_component(bt, ticks, BATTLE_COMPONENT_ALL); + + if (!battle_entity_update(atk->source, 0)) + return; + + switch (atk->status) { + case BATTLE_STATE_ATTACKING_ADVANCING: + /* + * Current entity state is battle-entity-state-moving but it is + * already updated from the game itself so pass 0 just to check + * if it has finished moving. + */ + atk->status = BATTLE_STATE_ATTACKING_DAMAGING; + + /* TODO: determine sprite to use about equipment. */ + battle_entity_state_attacking(atk->source, atk->source->ch->sprites[CHARACTER_SPRITE_SWORD]); + break; + case BATTLE_STATE_ATTACKING_DAMAGING: + /* Move back to original position. */ + atk->status = BATTLE_STATE_ATTACKING_RETURNING; + damage(atk->source, atk->target, bt); + battle_entity_state_moving(atk->source, atk->origin_x, atk->origin_y); + break; + case BATTLE_STATE_ATTACKING_RETURNING: + case BATTLE_STATE_ATTACKING_BLINKING: + /* Just wait. */ + battle_entity_state_normal(atk->source); + damage(atk->source, atk->target, bt); + battle_state_check(bt); + break; + default: + break; + } +} + +void +battle_state_attacking_draw(const struct battle_state_attacking *atk, const struct battle *bt) +{ + assert(atk); + assert(battle_ok(bt)); + + (void)atk; + + battle_draw_component(bt, BATTLE_COMPONENT_ALL); +} + +void +battle_state_attacking(struct battle_entity *source, struct battle_entity *target, struct battle *bt) +{ + assert(battle_entity_ok(source)); + assert(battle_entity_ok(target)); + assert(bt); + + struct self *self; + + self = alloc_new0(sizeof (*self)); + self->state.data = self; + self->state.update = update; + self->state.draw = draw; + self->state.finish = finish; + + battle_state_attacking_init(&self->data, source, target); + battle_switch(bt, &self->state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-attacking.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,57 @@ +/* + * battle-state-attacking.h -- battle state (entity is moving for attacking) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_STATE_ATTACKING_H +#define MLK_RPG_BATTLE_STATE_ATTACKING_H + +struct battle; +struct battle_entity; + +enum battle_state_attacking_status { + /* For team. */ + BATTLE_STATE_ATTACKING_ADVANCING, + BATTLE_STATE_ATTACKING_DAMAGING, + BATTLE_STATE_ATTACKING_RETURNING, + + /* For enemies. */ + BATTLE_STATE_ATTACKING_BLINKING, +}; + +struct battle_state_attacking { + enum battle_state_attacking_status status; + struct battle_entity *source; + struct battle_entity *target; + int origin_x; + int origin_y; +}; + +void +battle_state_attacking_init(struct battle_state_attacking *, + struct battle_entity *, + struct battle_entity *); + +void +battle_state_attacking_update(struct battle_state_attacking *, struct battle *, unsigned int); + +void +battle_state_attacking_draw(const struct battle_state_attacking *, const struct battle *); + +void +battle_state_attacking(struct battle_entity *, struct battle_entity *, struct battle *); + +#endif /* !#define MLK_RPG_BATTLE_STATE_ATTACKING_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-check.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,207 @@ +/* + * battle-state-check.c -- battle state (check status) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/panic.h> +#include <mlk/core/sprite.h> +#include <mlk/core/texture.h> +#include <mlk/core/trace.h> + +#include "battle-state-check.h" +#include "battle-state-lost.h" +#include "battle-state-victory.h" +#include "battle-state.h" +#include "battle.h" +#include "character.h" + +struct fadeout { + struct character *ch; + int x; + int y; + struct drawable dw; + unsigned int alpha; + unsigned int elapsed; +}; + +static int +fadeout_update(struct drawable *dw, unsigned int ticks) +{ + struct fadeout *fade = dw->data; + + fade->elapsed += ticks; + + if (fade->elapsed >= 8) { + fade->elapsed = 0; + + if (fade->alpha == 0) + return 1; + + fade->alpha -= 10; + } + + return 0; +} + +static void +fadeout_draw(struct drawable *dw) +{ + const struct fadeout *fade = dw->data; + struct sprite *sprite = fade->ch->sprites[CHARACTER_SPRITE_NORMAL]; + + texture_set_alpha_mod(sprite->texture, fade->alpha); + sprite_draw(sprite, 0, 0, fade->x, fade->y); + texture_set_alpha_mod(sprite->texture, 255); +} + +static void +fadeout_finish(struct drawable *dw) +{ + free(dw->data); +} + +static void +fadeout(struct battle *bt, struct battle_entity *et) +{ + struct fadeout *fade; + + if (!bt->effects) { + tracef("can't create a fadeout effect without a drawable_stack"); + return; + } + + fade = alloc_new0(sizeof (*fade)); + fade->ch = et->ch; + fade->x = et->x; + fade->y = et->y; + fade->alpha = 250; + fade->dw.data = fade; + fade->dw.draw = fadeout_draw; + fade->dw.update = fadeout_update; + fade->dw.finish = fadeout_finish; + + if (drawable_stack_add(bt->effects, &fade->dw) < 0) + free(fade); +} + +static int +is_dead(const struct battle *bt) +{ + const struct battle_entity *et; + + BATTLE_TEAM_FOREACH(bt, et) { + if (!character_ok(et->ch)) + continue; + if (et->ch->hp > 0) + return 0; + } + + return 1; +} + +static int +is_won(const struct battle *bt) +{ + const struct battle_entity *et; + + BATTLE_ENEMY_FOREACH(bt, et) + if (character_ok(et->ch)) + return 0; + + return 1; +} + +static void +clean(struct battle *bt) +{ + for (size_t i = 0; i < bt->enemiesz; ++i) { + if (bt->enemies[i] && character_ok(bt->enemies[i]->ch) && bt->enemies[i]->ch->hp == 0) { + fadeout(bt, bt->enemies[i]); + bt->enemies[i] = NULL; + } + } +} + +static int +update(struct battle_state *st, struct battle *bt, unsigned int ticks) +{ + (void)st; + (void)ticks; + + battle_state_check_update(bt); + + return 0; +} + +static void +draw(const struct battle_state *st, const struct battle *bt) +{ + (void)st; + + battle_state_check_draw(bt); +} + +static void +finish(struct battle_state *st, struct battle *bt) +{ + (void)bt; + + free(st); +} + +void +battle_state_check_update(struct battle *bt) +{ + assert(battle_ok(bt)); + + clean(bt); + + if (is_dead(bt)) + battle_state_lost(bt); + else if (is_won(bt)) + battle_state_victory(bt); + else + battle_next(bt); +} + +void +battle_state_check_draw(const struct battle *bt) +{ + assert(battle_ok(bt)); + + battle_draw_component(bt, BATTLE_COMPONENT_ALL); +} + +void +battle_state_check(struct battle *bt) +{ + assert(battle_ok(bt)); + + struct battle_state *self; + + self = alloc_new0(sizeof (*self)); + self->data = bt; + self->update = update; + self->draw = draw; + self->finish = finish; + + battle_switch(bt, self); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-check.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,33 @@ +/* + * battle-state-check.h -- battle state (check status) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_STATE_CHECK_H +#define MLK_RPG_BATTLE_STATE_CHECK_H + +struct battle; + +void +battle_state_check_update(struct battle *); + +void +battle_state_check_draw(const struct battle *); + +void +battle_state_check(struct battle *); + +#endif /* !MLK_RPG_BATTLE_STATE_CHECK_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-closing.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,140 @@ +/* + * battle-state-closing.c -- battle state (closing) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/music.h> +#include <mlk/core/painter.h> +#include <mlk/core/panic.h> +#include <mlk/core/texture.h> +#include <mlk/core/window.h> + +#include "battle-state-closing.h" +#include "battle.h" + +struct self { + struct battle_state_closing data; + struct battle_state state; +}; + +static int +update(struct battle_state *st, struct battle *bt, unsigned int ticks) +{ + (void)bt; + + return battle_state_closing_update(st->data, ticks); +} + +static void +draw(const struct battle_state *st, const struct battle *bt) +{ + (void)bt; + + battle_state_closing_draw(st->data, bt); +} + +static void +finish(struct battle_state *st, struct battle *bt) +{ + (void)bt; + + battle_state_closing_finish(st->data); + free(st->data); +} + +void +battle_state_closing_init(struct battle_state_closing *cls) +{ + assert(cls); + + if (texture_new(&cls->texture, window.w, window.h) < 0) + panic(); + + PAINTER_BEGIN(&cls->texture); + texture_set_blend_mode(&cls->texture, TEXTURE_BLEND_BLEND); + painter_set_color(0x000000ff); + painter_clear(); + painter_draw_rectangle(0, 0, window.w, window.h); + PAINTER_END(); + + texture_set_alpha_mod(&cls->texture, 0); +} + +int +battle_state_closing_update(struct battle_state_closing *cls, unsigned int ticks) +{ + assert(cls); + + cls->elapsed += ticks; + + /* TODO: ??? */ + if (cls->elapsed > 8) { + cls->elapsed = 0; + + if (cls->alpha == 255) { + /* TODO: since OpenAL, no notion of global music. */ +#if 0 + music_stop(0); +#endif + return 1; + } + + cls->alpha += 5; + texture_set_alpha_mod(&cls->texture, cls->alpha); + } + + return 0; +} + +void +battle_state_closing_draw(const struct battle_state_closing *cls, const struct battle *bt) +{ + assert(cls); + + battle_draw_component(bt, BATTLE_COMPONENT_ALL); + texture_draw(&cls->texture, 0, 0); +} + +void +battle_state_closing_finish(struct battle_state_closing *cls) +{ + assert(cls); + + texture_finish(&cls->texture); + memset(cls, 0, sizeof (*cls)); +} + +void +battle_state_closing(struct battle *bt) +{ + assert(bt); + + struct self *self; + + self = alloc_new0(sizeof (*self)); + self->state.data = self; + self->state.update = update; + self->state.draw = draw; + self->state.finish = finish; + + battle_state_closing_init(&self->data); + battle_switch(bt, &self->state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-closing.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,47 @@ +/* + * battle-state-closing.h -- battle state (closing) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_STATE_CLOSING_H +#define MLK_RPG_BATTLE_STATE_CLOSING_H + +#include <mlk/core/texture.h> + +struct battle; + +struct battle_state_closing { + struct texture texture; + unsigned int alpha; + unsigned int elapsed; +}; + +void +battle_state_closing_init(struct battle_state_closing *); + +int +battle_state_closing_update(struct battle_state_closing *, unsigned int); + +void +battle_state_closing_draw(const struct battle_state_closing *, const struct battle *); + +void +battle_state_closing_finish(struct battle_state_closing *); + +void +battle_state_closing(struct battle *); + +#endif /* !MLK_RPG_BATTLE_STATE_CLOSING_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-item.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,147 @@ +/* + * battle-state-item.c -- battle state (using item) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/panic.h> + +#include "battle-entity-state-moving.h" +#include "battle-entity-state-normal.h" +#include "battle-entity-state.h" +#include "battle-message.h" +#include "battle-state-item.h" +#include "battle-state.h" +#include "battle.h" +#include "inventory.h" +#include "item.h" + +struct self { + struct battle_state_item data; + struct battle_state state; +}; + +static int +update(struct battle_state *st, struct battle *bt, unsigned int ticks) +{ + return battle_state_item_update(st->data, bt, ticks); +} + +static void +draw(const struct battle_state *st, const struct battle *bt) +{ + (void)bt; + + battle_state_item_draw(st->data); +} + +static void +finish(struct battle_state *st, struct battle *bt) +{ + (void)bt; + + free(st->data); +} + +void +battle_state_item_init(struct battle_state_item *it, + struct battle *bt, + struct battle_entity *source, + struct battle_entity *target, + struct inventory_slot *slot) +{ + assert(it); + assert(bt); + assert(battle_entity_ok(source)); + assert(battle_entity_ok(target)); + assert(slot); + + it->source = source; + it->target = target; + it->slot = slot; + it->origin_x = it->source->x; + + it->msg.text = slot->item->name; + it->msg.theme = bt->theme; + + battle_entity_state_moving(it->source, it->origin_x - 100, it->source->y); +} + +int +battle_state_item_update(struct battle_state_item *it, struct battle *bt, unsigned int ticks) +{ + assert(it); + assert(bt); + + switch (it->status) { + case BATTLE_STATE_ITEM_ADVANCING: + /* Entity is updating from battle, so just inspect its status. */ + if (battle_entity_update(it->source, 0)) { + it->status = BATTLE_STATE_ITEM_MESSAGE; + battle_entity_state_normal(it->source); + } + break; + case BATTLE_STATE_ITEM_MESSAGE: + if (battle_message_update(&it->msg, ticks)) { + it->status = BATTLE_STATE_ITEM_RETURNING; + battle_entity_state_moving(it->source, it->origin_x, it->source->y); + } + break; + default: + if (battle_entity_update(it->source, 0)) { + battle_entity_state_normal(it->source); + battle_use(bt, it->slot->item, it->source->ch, it->target->ch); + } + break; + } + + return 0; +} + +void +battle_state_item_draw(struct battle_state_item *it) +{ + assert(it); + + if (it->status == BATTLE_STATE_ITEM_MESSAGE) + battle_message_draw(&it->msg); +} + +void +battle_state_item(struct battle *bt, + struct battle_entity *source, + struct battle_entity *target, + struct inventory_slot *slot) +{ + assert(battle_entity_ok(source)); + assert(battle_entity_ok(target)); + assert(slot); + assert(bt); + + struct self *self; + + self = alloc_new0(sizeof (*self)); + self->state.data = self; + self->state.update = update; + self->state.draw = draw; + self->state.finish = finish; + + battle_state_item_init(&self->data, bt, source, target, slot); + battle_switch(bt, &self->state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-item.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,63 @@ +/* + * battle-state-item.h -- battle state (using item) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_STATE_ITEM_H +#define MLK_RPG_BATTLE_STATE_ITEM_H + +#include <mlk/rpg/battle-message.h> + +struct battle; +struct battle_entity; +struct inventory_slot; + +enum battle_state_item_status { + BATTLE_STATE_ITEM_ADVANCING, + BATTLE_STATE_ITEM_MESSAGE, + BATTLE_STATE_ITEM_RETURNING +}; + +struct battle_state_item { + enum battle_state_item_status status; + struct battle_message msg; + struct battle_entity *source; + struct battle_entity *target; + struct inventory_slot *slot; + int origin_x; +}; + +void +battle_state_item_init(struct battle_state_item *, + struct battle *, + struct battle_entity *, + struct battle_entity *, + struct inventory_slot *); + +int +battle_state_item_update(struct battle_state_item *, struct battle *, unsigned int); + +void +battle_state_item_draw(struct battle_state_item *); + +void +battle_state_item(struct battle *, + struct battle_entity *, + struct battle_entity *, + struct inventory_slot *); + + +#endif /* !MLK_RPG_BATTLE_STATE_ITEM_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-lost.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,134 @@ +/* + * battle-state-lost.c -- battle state (lost) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/music.h> +#include <mlk/core/panic.h> +#include <mlk/core/window.h> + +#include "battle-state-closing.h" +#include "battle-state-lost.h" +#include "battle-state.h" +#include "battle.h" + +struct self { + struct battle_state_lost data; + struct battle_state state; +}; + +static void +handle(struct battle_state *st, struct battle *bt, const union event *ev) +{ + (void)bt; + + battle_state_lost_handle(st->data, ev); +} + +static int +update(struct battle_state *st, struct battle *bt, unsigned int ticks) +{ + return battle_state_lost_update(st->data, bt, ticks); +} + +static void +draw(const struct battle_state *st, const struct battle *bt) +{ + (void)bt; + + battle_state_lost_draw(st->data, bt); +} + +void +battle_state_lost_init(struct battle_state_lost *lost, struct battle *bt) +{ + assert(lost); + assert(bt); + + lost->text = "You have been defeated..."; + + lost->msg.lines = &lost->text; + lost->msg.linesz = 1; + lost->msg.theme = bt->theme; + lost->msg.flags = MESSAGE_FLAGS_AUTOMATIC | + MESSAGE_FLAGS_FADEIN | + MESSAGE_FLAGS_FADEOUT; + lost->msg.timeout = MESSAGE_TIMEOUT_DEFAULT; + lost->msg.delay = MESSAGE_DELAY_DEFAULT; + + message_start(&lost->msg); + message_query(&lost->msg, NULL, &lost->msg.h); + + lost->msg.w = window.w * 0.6; + lost->msg.y = window.h * 0.1; + lost->msg.x = (window.w - lost->msg.w) / 2; + + bt->status = BATTLE_STATUS_LOST; + + if (bt->music[2]) + music_play(bt->music[2], MUSIC_NONE); +} + +void +battle_state_lost_handle(struct battle_state_lost *lost, const union event *ev) +{ + assert(lost); + assert(ev); + + message_handle(&lost->msg, ev); +} + +int +battle_state_lost_update(struct battle_state_lost *lost, struct battle *bt, unsigned int ticks) +{ + assert(lost); + assert(bt); + + if (message_update(&lost->msg, ticks)) + battle_state_closing(bt); + + return 0; +} + +void +battle_state_lost_draw(struct battle_state_lost *lost, const struct battle *bt) +{ + assert(lost); + assert(battle_ok(bt)); + + battle_draw_component(bt, BATTLE_COMPONENT_ALL); + message_draw(&lost->msg); +} + +void +battle_state_lost(struct battle *bt) +{ + assert(bt); + + struct self *self; + + self = alloc_new0(sizeof (*self)); + self->state.data = self; + self->state.handle = handle; + self->state.update = update; + self->state.draw = draw; + + battle_state_lost_init(&self->data, bt); + battle_switch(bt, &self->state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-lost.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,48 @@ +/* + * battle-state-lost.h -- battle state (lost) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_STATE_LOST_H +#define MLK_RPG_BATTLE_STATE_LOST_H + +#include <mlk/rpg/message.h> + +union event; + +struct battle; + +struct battle_state_lost { + const char *text; + struct message msg; +}; + +void +battle_state_lost_init(struct battle_state_lost *, struct battle *); + +void +battle_state_lost_handle(struct battle_state_lost *, const union event *); + +int +battle_state_lost_update(struct battle_state_lost *, struct battle *, unsigned int); + +void +battle_state_lost_draw(struct battle_state_lost *, const struct battle *); + +void +battle_state_lost(struct battle *); + +#endif /* !MLK_RPG_BATTLE_STATE_LOST_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-menu.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,104 @@ +/* + * battle-state-menu.h -- battle state (menu) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> + +#include <mlk/core/alloc.h> + +#include "battle-bar.h" +#include "battle-state-menu.h" +#include "battle-state.h" +#include "battle.h" + +static void +handle(struct battle_state *st, struct battle *bt, const union event *ev) +{ + (void)st; + + battle_state_menu_handle(bt, ev); +} + +static int +update(struct battle_state *st, struct battle *bt, unsigned int ticks) +{ + (void)st; + + battle_state_menu_update(bt, ticks); + + return 0; +} + +static void +draw(const struct battle_state *st, const struct battle *bt) +{ + (void)st; + + battle_state_menu_draw(bt); +} + +static void +finish(struct battle_state *st, struct battle *bt) +{ + (void)bt; + + free(st); +} + +void +battle_state_menu_handle(struct battle *bt, const union event *ev) +{ + assert(bt); + assert(ev); + + battle_bar_handle(bt->bar, bt, ev); +} + +void +battle_state_menu_update(struct battle *bt, unsigned int ticks) +{ + assert(battle_ok(bt)); + + battle_update_component(bt, ticks, BATTLE_COMPONENT_ALL); +} + +void +battle_state_menu_draw(const struct battle *bt) +{ + assert(battle_ok(bt)); + + battle_draw_component(bt, BATTLE_COMPONENT_ALL); +} + +void +battle_state_menu(struct battle *bt) +{ + assert(bt); + + struct battle_state *state; + + state = alloc_new0(sizeof (*state)); + state->data = bt; + state->handle = handle; + state->update = update; + state->draw = draw; + state->finish = finish; + + battle_bar_start(bt->bar, bt); + battle_switch(bt, state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-menu.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,38 @@ +/* + * battle-state-menu.c -- battle state (menu) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_STATE_MENU_H +#define MLK_RPG_BATTLE_STATE_MENU_H + +struct battle; + +union event; + +void +battle_state_menu_handle(struct battle *, const union event *); + +void +battle_state_menu_update(struct battle *, unsigned int); + +void +battle_state_menu_draw(const struct battle *); + +void +battle_state_menu(struct battle *); + +#endif /* !MLK_RPG_BATTLE_STATE_MENU_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-opening.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,111 @@ +/* + * battle-state-opening.c -- battle state (opening) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/painter.h> +#include <mlk/core/panic.h> +#include <mlk/core/window.h> + +#include "battle-state-check.h" +#include "battle-state-opening.h" +#include "battle-state.h" +#include "battle.h" + +#define DELAY (1000U) + +struct self { + /* Always keep first. */ + struct battle_state_opening data; + struct battle_state state; +}; + +static int +update(struct battle_state *st, struct battle *bt, unsigned int ticks) +{ + (void)bt; + + return battle_state_opening_update(st->data, bt, ticks); +} + +static void +draw(const struct battle_state *st, const struct battle *bt) +{ + (void)bt; + + battle_state_opening_draw(st->data, bt); +} + +static void +finish(struct battle_state *st, struct battle *bt) +{ + (void)bt; + + free(st->data); +} + +int +battle_state_opening_update(struct battle_state_opening *op, struct battle *bt, unsigned int ticks) +{ + op->elapsed += ticks; + + /* + * Those function will effectively change state accordingly to the + * order of playing. + */ + if (op->elapsed >= DELAY) + battle_state_check(bt); + + return 0; +} + +void +battle_state_opening_draw(const struct battle_state_opening *op, const struct battle *bt) +{ + assert(op); + assert(bt); + + const unsigned int w = window.w; + const unsigned int h = window.h / 2; + const unsigned int ch = op->elapsed * h / DELAY; + + battle_draw_component(bt, BATTLE_COMPONENT_BACKGROUND | BATTLE_COMPONENT_ENTITIES); + + /* Draw some bezels opening. */ + painter_set_color(0x000000ff); + painter_draw_rectangle(0, 0, w, h - ch); + painter_draw_rectangle(0, h + ch, w, h - ch); +} + +void +battle_state_opening(struct battle *bt) +{ + assert(bt); + + struct self *self; + + self = alloc_new0(sizeof (*self)); + self->state.data = self; + self->state.update = update; + self->state.draw = draw; + self->state.finish = finish; + + battle_switch(bt, &self->state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-opening.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,37 @@ +/* + * battle-state-opening.h -- battle state (opening) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_STATE_OPENING_H +#define MLK_RPG_BATTLE_STATE_OPENING_H + +struct battle; + +struct battle_state_opening { + unsigned int elapsed; +}; + +int +battle_state_opening_update(struct battle_state_opening *, struct battle *, unsigned int); + +void +battle_state_opening_draw(const struct battle_state_opening *, const struct battle *); + +void +battle_state_opening(struct battle *); + +#endif /* !MLK_RPG_BATTLE_STATE_OPENING_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-rendering.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,114 @@ +/* + * battle-state-rendering.c -- battle state (rendering an action) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/drawable.h> + +#include "battle-state-rendering.h" +#include "battle.h" + +struct self { + struct battle_state_rendering data; + struct battle_state state; +}; + +static int +update(struct battle_state *st, struct battle *bt, unsigned int ticks) +{ + battle_state_rendering_update(st->data, bt, ticks); + + return 0; +} + +static void +draw(const struct battle_state *st, const struct battle *bt) +{ + battle_state_rendering_draw(st->data, bt); +} + +static void +finish(struct battle_state *st, struct battle *bt) +{ + (void)bt; + + battle_state_rendering_finish(st->data); + free(st->data); +} + +void +battle_state_rendering_init(struct battle_state_rendering *rdr, struct drawable *dw) +{ + assert(rdr); + assert(dw); + + rdr->drawable = dw; +} + +int +battle_state_rendering_update(struct battle_state_rendering *rdr, struct battle *bt, unsigned int ticks) +{ + assert(rdr); + assert(battle_ok(bt)); + + battle_update_component(bt, BATTLE_COMPONENT_ALL, ticks); + + if (drawable_update(rdr->drawable, ticks)) { + drawable_end(rdr->drawable); + return 1; + } + + return 0; +} + +void +battle_state_rendering_draw(const struct battle_state_rendering *rdr, const struct battle *bt) +{ + assert(rdr); + + battle_draw_component(bt, BATTLE_COMPONENT_ALL); + drawable_draw(rdr->drawable); +} + +void +battle_state_rendering_finish(struct battle_state_rendering *rdr) +{ + assert(rdr); + + drawable_finish(rdr->drawable); +} + +void +battle_state_rendering(struct battle *bt, struct drawable *dw) +{ + assert(bt); + assert(dw); + + struct self *self; + + self = alloc_new0(sizeof (*self)); + self->state.data = self; + self->state.update = update; + self->state.draw = draw; + self->state.finish = finish; + + battle_state_rendering_init(&self->data, dw); + battle_switch(bt, &self->state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-rendering.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,44 @@ +/* + * battle-state-rendering.h -- battle state (rendering an action) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_STATE_RENDERING_H +#define MLK_RPG_BATTLE_STATE_RENDERING_H + +struct battle; +struct drawable; + +struct battle_state_rendering { + struct drawable *drawable; +}; + +void +battle_state_rendering_init(struct battle_state_rendering *, struct drawable *); + +int +battle_state_rendering_update(struct battle_state_rendering *, struct battle *, unsigned int); + +void +battle_state_rendering_draw(const struct battle_state_rendering *, const struct battle *); + +void +battle_state_rendering_finish(struct battle_state_rendering *); + +void +battle_state_rendering(struct battle *, struct drawable *); + +#endif /* !MLK_RPG_BATTLE_STATE_RENDERING_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-selection.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,231 @@ +/* + * battle-state-selection.c -- battle state (selection) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/event.h> +#include <mlk/core/panic.h> +#include <mlk/core/sprite.h> +#include <mlk/core/util.h> + +#include <mlk/ui/theme.h> + +#include "battle-bar.h" +#include "battle-state-item.h" +#include "battle-state-menu.h" +#include "battle-state-selection.h" +#include "battle-state.h" +#include "battle.h" +#include "character.h" +#include "inventory.h" +#include "selection.h" +#include "spell.h" + +struct self { + struct battle_state_selection data; + struct battle_state state; +}; + +static void +select_adj_in(struct battle_state_selection *slt, struct battle_entity **entities, size_t entitiesz, int step) +{ + assert(slt->select.index_character != (unsigned int)-1); + + unsigned int newselection = slt->select.index_character; + + if (step < 0) { + while (newselection > 0) { + if (character_ok(entities[--newselection]->ch)) { + slt->select.index_character = newselection; + break; + } + } + } else { + while (newselection < entitiesz) { + if (character_ok(entities[++newselection]->ch)) { + slt->select.index_character = newselection; + break; + } + } + } +} + +static void +select_adj(struct battle_state_selection *slt, const struct battle *bt, int step) +{ + if (slt->select.index_side == 0) + select_adj_in(slt, bt->enemies, bt->enemiesz, step); + else + select_adj_in(slt, bt->team, bt->teamsz, step); +} + +static void +handle_keydown(struct battle_state_selection *stl, struct battle *bt, const union event *ev) +{ + assert(ev->type == EVENT_KEYDOWN); + + switch (ev->key.key) { + case KEY_ESCAPE: + battle_state_menu(bt); + break; + case KEY_ENTER: + battle_bar_select(bt->bar, bt, &stl->select); + break; + case KEY_LEFT: + if (stl->select.allowed_sides & SELECTION_SIDE_ENEMY) + stl->select.index_side = 0; + break; + case KEY_RIGHT: + if (stl->select.allowed_sides & SELECTION_SIDE_TEAM) + stl->select.index_side = 1; + break; + case KEY_UP: + select_adj(stl, bt, -1); + break; + case KEY_DOWN: + select_adj(stl, bt, +1); + break; + case KEY_TAB: + if (stl->select.allowed_kinds == SELECTION_KIND_BOTH) + stl->select.index_character = -1; + break; + default: + break; + } +} + +static void +draw_cursor(const struct battle *bt, const struct battle_entity *et) +{ + const struct theme *theme = BATTLE_THEME(bt); + const struct sprite *cursor = theme->sprites[THEME_SPRITE_CURSOR]; + int x, y; + unsigned int lh; + + if (!cursor) + return; + + label_query(&et->name, NULL, &lh); + + x = et->name.x - cursor->cellw - theme->padding; + y = et->name.y + (((int)(lh) - (int)(cursor->cellh)) / 2); + + sprite_draw(cursor, 1, 2, x, y); +} + +static void +draw_cursors(const struct battle *bt, + struct battle_entity * const *entities, + size_t entitiesz) +{ + for (size_t i = 0; i < entitiesz; ++i) { + const struct battle_entity *et = entities[i]; + + if (et && character_ok(et->ch)) + draw_cursor(bt, et); + } +} + +static void +handle(struct battle_state *st, struct battle *bt, const union event *ev) +{ + battle_state_selection_handle(st->data, bt, ev); +} + +static void +draw(const struct battle_state *st, const struct battle *bt) +{ + battle_state_selection_draw(st->data, bt); +} + +static void +finish(struct battle_state *st, struct battle *bt) +{ + (void)bt; + + free(st->data); +} + +void +battle_state_selection_init(struct battle_state_selection *stl, const struct selection *select) +{ + assert(stl); + assert(select); + + memcpy(&stl->select, select, sizeof (*select)); +} + +void +battle_state_selection_handle(struct battle_state_selection *stl, struct battle *bt, const union event *ev) +{ + assert(stl); + assert(bt); + assert(ev); + + switch (ev->type) { + case EVENT_KEYDOWN: + handle_keydown(stl, bt, ev); + break; + default: + break; + } +} + +void +battle_state_selection_draw(const struct battle_state_selection *stl, const struct battle *bt) +{ + assert(stl); + assert(bt); + + battle_draw_component(bt, BATTLE_COMPONENT_ALL); + + if (stl->select.index_character == -1U) { + /* All selected. */ + if (stl->select.index_side == 0) + draw_cursors(bt, bt->enemies, bt->enemiesz); + else + draw_cursors(bt, bt->team, bt->teamsz); + } else { + /* Select one. */ + if (stl->select.index_side == 0) + draw_cursor(bt, bt->enemies[stl->select.index_character]); + else + draw_cursor(bt, bt->team[stl->select.index_character]); + } +} + +void +battle_state_selection(struct battle *bt, const struct selection *select) +{ + assert(bt); + assert(select); + + struct self *self; + + self = alloc_new0(sizeof (*self)); + self->state.data = self; + self->state.handle = handle; + self->state.draw = draw; + self->state.finish = finish; + + battle_state_selection_init(&self->data, select); + battle_switch(bt, &self->state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-selection.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,44 @@ +/* + * battle-state-selection.h -- battle state (selection) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_STATE_SELECTION_H +#define MLK_RPG_BATTLE_STATE_SELECTION_H + +#include <mlk/rpg/selection.h> + +struct battle; + +union event; + +struct battle_state_selection { + struct selection select; +}; + +void +battle_state_selection_init(struct battle_state_selection *, const struct selection *); + +void +battle_state_selection_handle(struct battle_state_selection *, struct battle *, const union event *); + +void +battle_state_selection_draw(const struct battle_state_selection *, const struct battle *); + +void +battle_state_selection(struct battle *, const struct selection *); + +#endif /* !MLK_RPG_BATTLE_STATE_SELECTION_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-victory.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,136 @@ +/* + * battle-state-victory.c -- battle state (victory) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/music.h> +#include <mlk/core/panic.h> +#include <mlk/core/window.h> + +#include "battle-state-closing.h" +#include "battle-state-victory.h" +#include "battle-state.h" +#include "battle.h" + +struct self { + struct battle_state_victory data; + struct battle_state state; +}; + +static void +handle(struct battle_state *st, struct battle *bt, const union event *ev) +{ + (void)bt; + + battle_state_victory_handle(st->data, ev); +} + +static int +update(struct battle_state *st, struct battle *bt, unsigned int ticks) +{ + (void)bt; + + return battle_state_victory_update(st->data, bt, ticks); +} + +static void +draw(const struct battle_state *st, const struct battle *bt) +{ + (void)bt; + + battle_state_victory_draw(st->data, bt); +} + +void +battle_state_victory_init(struct battle_state_victory *vic, struct battle *bt) +{ + assert(bt); + + vic->text = "Victory!"; + + vic->msg.lines = &vic->text; + vic->msg.linesz = 1; + vic->msg.theme = bt->theme; + vic->msg.flags = MESSAGE_FLAGS_AUTOMATIC | + MESSAGE_FLAGS_FADEIN | + MESSAGE_FLAGS_FADEOUT; + vic->msg.timeout = MESSAGE_TIMEOUT_DEFAULT; + vic->msg.delay = MESSAGE_DELAY_DEFAULT; + + message_start(&vic->msg); + message_query(&vic->msg, NULL, &vic->msg.h); + + vic->msg.w = window.w * 0.6; + vic->msg.y = window.h * 0.1; + vic->msg.x = (window.w - vic->msg.w) / 2; + + bt->status = BATTLE_STATUS_WON; + + if (bt->music[1]) + music_play(bt->music[1], MUSIC_NONE); +} + +void +battle_state_victory_handle(struct battle_state_victory *vic, const union event *ev) +{ + assert(vic); + + message_handle(&vic->msg, ev); +} + +int +battle_state_victory_update(struct battle_state_victory *vic, struct battle *bt, unsigned int ticks) +{ + assert(vic); + assert(bt); + + battle_update_component(bt, BATTLE_COMPONENT_ALL, ticks); + + if (message_update(&vic->msg, ticks)) + battle_state_closing(bt); + + return 0; +} + +void +battle_state_victory_draw(const struct battle_state_victory *vic, const struct battle *bt) +{ + assert(vic); + + battle_draw_component(bt, BATTLE_COMPONENT_ALL); + message_draw(&vic->msg); +} + +void +battle_state_victory(struct battle *bt) +{ + assert(bt); + + struct self *self; + + /* TODO: compute money, xp and drop. */ + self = alloc_new0(sizeof (*self)); + self->state.data = self; + self->state.handle = handle; + self->state.update = update; + self->state.draw = draw; + + battle_state_victory_init(&self->data, bt); + battle_switch(bt, &self->state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state-victory.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,48 @@ +/* + * battle-state-victory.h -- battle state (victory) + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_STATE_VICTORY_H +#define MLK_RPG_BATTLE_STATE_VICTORY_H + +#include <mlk/rpg/message.h> + +struct battle; + +union event; + +struct battle_state_victory { + const char *text; + struct message msg; +}; + +void +battle_state_victory_init(struct battle_state_victory *, struct battle *); + +void +battle_state_victory_handle(struct battle_state_victory *, const union event *); + +int +battle_state_victory_update(struct battle_state_victory *, struct battle *, unsigned int); + +void +battle_state_victory_draw(const struct battle_state_victory *, const struct battle *); + +void +battle_state_victory(struct battle *); + +#endif /* !MLK_RPG_BATTLE_STATE_VICTORY_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,64 @@ +/* + * battle-state.c -- battle abstract state + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include "battle-state.h" + +void +battle_state_handle(struct battle_state *st, struct battle *bt, const union event *ev) +{ + assert(st); + assert(bt); + assert(ev); + + if (st->handle) + st->handle(st, bt, ev); +} + +int +battle_state_update(struct battle_state *st, struct battle *bt, unsigned int ticks) +{ + assert(st); + assert(bt); + + if (st->update) + return st->update(st, bt, ticks); + + return 0; +} + +void +battle_state_draw(const struct battle_state *st, const struct battle *bt) +{ + assert(st); + assert(bt); + + if (st->draw) + st->draw(st, bt); +} + +void +battle_state_finish(struct battle_state *st, struct battle *bt) +{ + assert(st); + assert(bt); + + if (st->finish) + st->finish(st, bt); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle-state.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,55 @@ +/* + * battle-state.h -- battle abstract state + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_STATE_H +#define MLK_RPG_BATTLE_STATE_H + +#include <mlk/core/core.h> + +struct battle; +struct character; +struct inventory_slot; +struct selection; + +union event; + +struct battle_state { + void *data; + void (*handle)(struct battle_state *, struct battle *, const union event *); + int (*update)(struct battle_state *, struct battle *, unsigned int); + void (*draw)(const struct battle_state *, const struct battle *); + void (*finish)(struct battle_state *, struct battle *); +}; + +CORE_BEGIN_DECLS + +void +battle_state_handle(struct battle_state *, struct battle *, const union event *); + +int +battle_state_update(struct battle_state *, struct battle *, unsigned int); + +void +battle_state_draw(const struct battle_state *, const struct battle *); + +void +battle_state_finish(struct battle_state *, struct battle *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_BATTLE_STATE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,502 @@ +/* + * battle.c -- battles + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/event.h> +#include <mlk/core/font.h> +#include <mlk/core/music.h> +#include <mlk/core/sprite.h> +#include <mlk/core/texture.h> +#include <mlk/core/trace.h> +#include <mlk/core/util.h> +#include <mlk/core/window.h> + +#include <mlk/ui/align.h> +#include <mlk/ui/frame.h> +#include <mlk/ui/label.h> +#include <mlk/ui/theme.h> + +#include "battle-bar.h" +#include "battle-indicator.h" +#include "battle-state-ai.h" +#include "battle-state-attacking.h" +#include "battle-state-check.h" +#include "battle-state-menu.h" +#include "battle-state-opening.h" +#include "battle-state.h" +#include "battle.h" +#include "character.h" +#include "inventory.h" +#include "item.h" +#include "spell.h" + +struct indicator { + struct drawable dw; + struct battle_indicator bti; +}; + +static int +indicator_update(struct drawable *dw, unsigned int ticks) +{ + struct indicator *id = dw->data; + + return battle_indicator_update(&id->bti, ticks); +} + +static void +indicator_draw(struct drawable *dw) +{ + const struct indicator *id = dw->data; + + battle_indicator_draw(&id->bti, dw->x, dw->y); +} + +static void +indicator_free(struct drawable *dw) +{ + struct indicator *id = dw->data; + + battle_indicator_finish(&id->bti); + free(id); +} + +static struct battle_entity * +find(struct battle *bt, const struct character *ch) +{ + struct battle_entity *et; + + BATTLE_TEAM_FOREACH(bt, et) + if (et->ch == ch) + return et; + BATTLE_ENEMY_FOREACH(bt, et) + if (et->ch == ch) + return et; + + return NULL; +} + +static struct battle_entity * +random_select(struct battle_entity **group, size_t groupsz) +{ + struct battle_entity *ret = NULL, *et = NULL; + + do { + et = group[util_nrand(0, groupsz - 1)]; + + if (et && et->ch) + ret = et; + } while (!ret); + + return ret; +} + +static int +cmp_order(const void *d1, const void *d2) +{ + const struct battle_entity *et1 = *(const struct battle_entity **)d1; + const struct battle_entity *et2 = *(const struct battle_entity **)d2; + + return et2->ch->agt < et1->ch->agt; +} + +static int +is_team(const struct battle *bt, const struct character *ch) +{ + for (size_t i = 0; i < bt->teamsz; ++i) + if (bt->team[i] && bt->team[i]->ch == ch) + return 1; + + return 0; +} + +static void +positionate_name(struct battle_entity *et, const struct battle *bt) +{ + unsigned int lw; + struct sprite *sprite; + + /* Show the character name below its sprite. */ + sprite = et->ch->sprites[CHARACTER_SPRITE_NORMAL]; + + et->name.text = et->ch->name; + et->name.flags = LABEL_FLAGS_SHADOW; + label_query(&et->name, &lw, NULL); + et->name.y = et->y + sprite->cellh + BATTLE_THEME(bt)->padding; + et->name.x = et->x + (sprite->cellw / 2) - (lw / 2); +} + +static void +positionate_names(struct battle *bt) +{ + struct battle_entity *et; + + BATTLE_TEAM_FOREACH(bt, et) + if (character_ok(et->ch)) + positionate_name(et, bt); + BATTLE_ENEMY_FOREACH(bt, et) + if (character_ok(et->ch)) + positionate_name(et, bt); +} + +static void +positionate_team(struct battle *bt) +{ + struct battle_entity *et; + unsigned int requirement = 0, nmemb = 0, spacing; + int x, y; + + BATTLE_TEAM_FOREACH(bt, et) { + /* Stop in case any member of the team has been positionated. */ + if (et->x != 0 || et->y != 0) + return; + + if (battle_entity_ok(bt->team[i])) { + nmemb++; + requirement += et->ch->sprites[CHARACTER_SPRITE_NORMAL]->cellh; + } + } + + /* TODO: compute a correct x placement. */ + spacing = (window.h - requirement) / (nmemb + 1); + x = window.w - 200; + y = spacing; + + BATTLE_TEAM_FOREACH(bt, et) { + if (battle_entity_ok(et)) { + et->x = x; + et->y = y; + y += et->ch->sprites[CHARACTER_SPRITE_NORMAL]->cellh + spacing; + } + } +} + +static void +draw_entities(const struct battle *bt, struct battle_entity **entities, size_t entitiesz) +{ + for (size_t i = 0; i < entitiesz; ++i) { + if (battle_entity_ok(entities[i])) + battle_entity_draw(entities[i], bt); + } +} + +static void +update_entities(struct battle_entity **entities, size_t entitiesz, unsigned int ticks) +{ + for (size_t i = 0; i < entitiesz; ++i) { + if (battle_entity_ok(entities[i])) + battle_entity_update(entities[i], ticks); + } +} + +void +battle_init(struct battle *bt) +{ + assert(bt); + + memset(bt, 0, sizeof (*bt)); +} + +int +battle_ok(const struct battle *bt) +{ + return bt && bt->state && bt->bar && bt->enemiesz && bt->team; +} + +void +battle_start(struct battle *bt) +{ + assert(bt); + + struct battle_entity *et; + + BATTLE_TEAM_FOREACH(bt, et) + if (battle_entity_ok(et)) + battle_entity_init(et); + BATTLE_ENEMY_FOREACH(bt, et) + if (battle_entity_ok(et)) + battle_entity_init(et); + + positionate_team(bt); + positionate_names(bt); + + /* Start the state "opening" animation. */ + battle_state_opening(bt); + + /* Play music if present. */ + if (bt->music[0]) + music_play(bt->music[0], MUSIC_LOOP); + + battle_order(bt); +} + +void +battle_switch(struct battle *bt, struct battle_state *st) +{ + assert(bt); + assert(st); + + if (bt->state) + battle_state_finish(bt->state, bt); + + bt->state = st; +} + +void +battle_order(struct battle *bt) +{ + struct battle_entity **porder; + + /* Create a pointer list to every entity. */ + bt->order = alloc_rearray0(bt->order, bt->ordersz, + bt->teamsz + bt->enemiesz, sizeof (*bt->order)); + bt->ordersz = bt->teamsz + bt->enemiesz; + bt->ordercur = porder = bt->order; + + for (size_t i = 0; i < bt->teamsz; ++i) + if (bt->team[i] && character_ok(bt->team[i]->ch)) + *porder++ = bt->team[i]; + for (size_t i = 0; i < bt->enemiesz; ++i) + if (bt->enemies[i] && character_ok(bt->enemies[i]->ch)) + *porder++ = bt->enemies[i]; + + /* Now sort. */ + qsort(bt->order, bt->ordersz, sizeof (*bt->order), cmp_order); +} + +struct battle_entity * +battle_current(const struct battle *bt) +{ + assert(bt); + + return *bt->ordercur; +} + +size_t +battle_index(const struct battle *bt) +{ + assert(bt); + + return bt->ordercur - bt->order; +} + +void +battle_attack(struct battle *bt, + struct character *source, + struct character *target) +{ + assert(bt); + assert(character_ok(source)); + + /* Target is empty? select randomly. */ + if (!target) { + if (is_team(bt, source)) + target = random_select(bt->enemies, bt->enemiesz)->ch; + else + target = random_select(bt->team, bt->teamsz)->ch; + } + + battle_state_attacking(battle_find(bt, source), battle_find(bt, target), bt); +} + +void +battle_cast(struct battle *bt, + struct character *source, + const struct spell *spell, + const struct selection *selection) +{ + assert(bt); + assert(source); + assert(spell); + assert((unsigned int)source->mp >= spell->mp); + + /* TODO: animate. */ + source->mp -= spell->mp; + spell_action(spell, bt, source, selection); +} + +void +battle_use(struct battle *bt, const struct item *item, struct character *owner, struct character *target) +{ + assert(bt); + assert(item); + assert(owner); + assert(target); + + /* + * Change the state to check prior to execute the item so it can change to something else + * if needed. + */ + battle_state_check(bt); + + inventory_consume(bt->inventory, item, 1); + item_exec_battle(item, bt, owner, target); +} + +void +battle_next(struct battle *bt) +{ + assert(bt); + + if (!bt->ordercur) + battle_order(bt); + else { + if (bt->ordercur - bt->order + (size_t)1U >= bt->ordersz) + battle_order(bt); + else + bt->ordercur++; + } + + if (is_team(bt, battle_current(bt)->ch)) { + battle_bar_start(bt->bar, bt); + battle_state_menu(bt); + } else + battle_state_ai(bt); +} + +struct battle_entity * +battle_find(struct battle *bt, const struct character *ch) +{ + assert(bt); + + return find(bt, ch); +} + +void +battle_indicator_hp(struct battle *bt, const struct character *target, long amount) +{ + assert(bt); + assert(target); + + const struct battle_entity *et = find(bt, target); + struct indicator *id; + + if (!(bt->effects)) { + tracef("unable to add id without a drawable_stack"); + return; + } + + id = alloc_new0(sizeof (*id)); + id->bti.color = BATTLE_INDICATOR_HP_COLOR; + id->bti.amount = labs(amount); + + /* TODO: positionate better. */ + id->dw.x = et->x + target->sprites[CHARACTER_SPRITE_NORMAL]->cellw; + id->dw.y = et->y + target->sprites[CHARACTER_SPRITE_NORMAL]->cellh; + id->dw.data = id; + id->dw.update = indicator_update; + id->dw.draw = indicator_draw; + id->dw.finish = indicator_free; + + battle_indicator_start(&id->bti); + + if (drawable_stack_add(bt->effects, &id->dw) < 0) + drawable_finish(&id->dw); +} + +void +battle_handle_component(struct battle *bt, const union event *ev, enum battle_component comp) +{ + assert(bt); + assert(ev); + + if (comp & BATTLE_COMPONENT_BAR) + battle_bar_handle(bt->bar, bt, ev); + if ((comp & BATTLE_COMPONENT_ACTIONS) && bt->actions) + action_stack_handle(bt->actions, ev); +} + +void +battle_handle(struct battle *bt, const union event *ev) +{ + assert(bt); + assert(ev); + + battle_state_handle(bt->state, bt, ev); +} + +void +battle_update_component(struct battle *bt, unsigned int ticks, enum battle_component comp) +{ + assert(bt); + + if (comp & BATTLE_COMPONENT_ENTITIES) { + update_entities(bt->team, bt->teamsz, ticks); + update_entities(bt->enemies, bt->enemiesz, ticks); + } + if (comp & BATTLE_COMPONENT_BAR) + battle_bar_update(bt->bar, bt, ticks); + if ((comp & BATTLE_COMPONENT_ACTIONS) && bt->actions) + action_stack_update(bt->actions, ticks); + if ((comp & BATTLE_COMPONENT_DRAWABLES) && bt->effects) + drawable_stack_update(bt->effects, ticks); +} + +int +battle_update(struct battle *bt, unsigned int ticks) +{ + assert(bt && bt->state); + + return battle_state_update(bt->state, bt, ticks); +} + +void +battle_draw_component(const struct battle *bt, enum battle_component comp) +{ + assert(bt); + + if ((comp & BATTLE_COMPONENT_BACKGROUND) && texture_ok(bt->background)) + texture_scale(bt->background, + 0, 0, bt->background->w, bt->background->h, + 0, 0, window.w, window.h, + 0.f); + if (comp & BATTLE_COMPONENT_ENTITIES) { + draw_entities(bt, bt->team, bt->teamsz); + draw_entities(bt, bt->enemies, bt->enemiesz); + } + if (comp & BATTLE_COMPONENT_BAR) + battle_bar_draw(bt->bar, bt); + if ((comp & BATTLE_COMPONENT_ACTIONS) && bt->actions) + action_stack_draw(bt->actions); + if ((comp & BATTLE_COMPONENT_DRAWABLES) && bt->effects) + drawable_stack_draw(bt->effects); +} + +void +battle_draw(const struct battle *bt) +{ + assert(battle_ok(bt)); + + battle_state_draw(bt->state, bt); +} + +void +battle_finish(struct battle *bt) +{ + assert(bt); + + if (bt->state) + battle_state_finish(bt->state, bt); + + free(bt->order); + memset(bt, 0, sizeof (*bt)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/battle.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,153 @@ +/* + * battle.h -- battles + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_BATTLE_H +#define MLK_RPG_BATTLE_H + +#include <mlk/core/action.h> +#include <mlk/core/action-stack.h> +#include <mlk/core/core.h> +#include <mlk/core/drawable.h> +#include <mlk/core/drawable-stack.h> + +#include <mlk/ui/frame.h> +#include <mlk/ui/gridmenu.h> + +#include "battle-entity.h" +#include "battle-state.h" +#include "selection.h" +#include "spell.h" + +union event; + +struct battle_bar; +struct character; +struct inventory; +struct item; +struct music; +struct selection; +struct spell; +struct theme; + +#define BATTLE_TEAM_FOREACH(bt, iter) \ + for (size_t i = 0; i < (bt)->teamsz && ((iter) = (bt)->team[i]); ++i) +#define BATTLE_ENEMY_FOREACH(bt, iter) \ + for (size_t i = 0; i < (bt)->enemiesz && ((iter) = (bt)->enemies[i]); ++i) + +#define BATTLE_THEME(bt) ((bt)->theme ? (bt)->theme : theme_default()) + +enum battle_status { + BATTLE_STATUS_NONE, + BATTLE_STATUS_RUNNING, + BATTLE_STATUS_WON, + BATTLE_STATUS_LOST, +}; + +enum battle_component { + BATTLE_COMPONENT_BACKGROUND = (1 << 0), + BATTLE_COMPONENT_ENTITIES = (1 << 1), + BATTLE_COMPONENT_BAR = (1 << 2), + BATTLE_COMPONENT_ACTIONS = (1 << 3), + BATTLE_COMPONENT_DRAWABLES = (1 << 4), + BATTLE_COMPONENT_ALL = 0xff +}; + +struct battle { + struct battle_state *state; + enum battle_status status; + struct battle_entity **team; + size_t teamsz; + struct battle_entity **enemies; + size_t enemiesz; + struct battle_entity **order; + struct battle_entity **ordercur; + size_t ordersz; + struct texture *background; + struct music *music[3]; + struct theme *theme; + struct drawable_stack *effects; + struct action_stack *actions; + struct inventory *inventory; + struct battle_bar *bar; +}; + +CORE_BEGIN_DECLS + +void +battle_init(struct battle *); + +int +battle_ok(const struct battle *); + +void +battle_start(struct battle *); + +void +battle_next(struct battle *); + +struct battle_entity * +battle_find(struct battle *, const struct character *); + +void +battle_switch(struct battle *, struct battle_state *); + +void +battle_order(struct battle *); + +struct battle_entity * +battle_current(const struct battle *); + +size_t +battle_index(const struct battle *); + +void +battle_attack(struct battle *, struct character *, struct character *); + +void +battle_cast(struct battle *, struct character *, const struct spell *, const struct selection *); + +void +battle_use(struct battle *, const struct item *, struct character *, struct character *); + +void +battle_indicator_hp(struct battle *, const struct character *, long); + +void +battle_handle_component(struct battle *, const union event *, enum battle_component); + +void +battle_handle(struct battle *, const union event *); + +void +battle_update_component(struct battle *, unsigned int, enum battle_component); + +int +battle_update(struct battle *, unsigned int); + +void +battle_draw_component(const struct battle *, enum battle_component); + +void +battle_draw(const struct battle *); + +void +battle_finish(struct battle *); + +CORE_END_DECLS + +#endif /* MLK_RPG_BATTLE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/character.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,122 @@ +/* + * character.c -- character definition + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include <mlk/core/sprite.h> + +#include <assets/sql/character-save.h> +#include <assets/sql/character-load.h> + +#include "character.h" +#include "equipment.h" +#include "save.h" + +int +character_ok(const struct character *ch) +{ + return ch && ch->name && ch->reset && sprite_ok(ch->sprites[CHARACTER_SPRITE_NORMAL]); +} + +const char * +character_status_string(enum character_status status) +{ + /* + * We expect the user to only specify one status as character_status + * is a bitmask. + */ + switch (status) { + case CHARACTER_STATUS_POISON: + return "poison"; + default: + return "normal"; + } +} + +void +character_reset(struct character *ch) +{ + assert(character_ok(ch)); + + ch->reset(ch); + + /* For all equipments, apply its equip function. */ + for (int i = 0; i < CHARACTER_EQUIPMENT_NUM; ++i) + if (ch->equipments[i]) + equipment_equip(ch->equipments[i], ch); +} + +void +character_exec(struct character *ch, struct battle *bt) +{ + assert(character_ok(ch)); + + if (ch->exec) + ch->exec(ch, bt); +} + +int +character_save(const struct character *ch, struct save *s) +{ + assert(ch); + assert(save_ok(s)); + + return save_exec(s, (const char *)assets_character_save, "s iii i iiiiii", + ch->name, + ch->hp, + ch->mp, + ch->level, + ch->team_order, + ch->hpbonus, + ch->mpbonus, + ch->atkbonus, + ch->defbonus, + ch->agtbonus, + ch->luckbonus + ); +} + +int +character_load(struct character *ch, struct save *s) +{ + assert(ch); + assert(save_ok(s)); + + struct save_stmt stmt; + enum save_stmt_errno ret; + + if (save_stmt_init(&stmt, s, (const char *)assets_character_load, "s", ch->name) < 0) + return -1; + + ret = save_stmt_next(&stmt, "iii i iiiiii", + &ch->hp, + &ch->mp, + &ch->level, + &ch->team_order, + &ch->hpbonus, + &ch->mpbonus, + &ch->atkbonus, + &ch->defbonus, + &ch->agtbonus, + &ch->luckbonus + ) == SAVE_STMT_ROW; + + save_stmt_finish(&stmt); + + return ret ? 0 : -1; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/character.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,109 @@ +/* + * character.h -- character definition + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_CHARACTER_H +#define MLK_RPG_CHARACTER_H + +#include <mlk/core/core.h> + +#define CHARACTER_SPELL_MAX (64) + +struct battle; +struct save; +struct sprite; +struct spell; + +enum character_status { + CHARACTER_STATUS_NORMAL, + CHARACTER_STATUS_POISON = (1 << 0) +}; + +enum character_sprite { + CHARACTER_SPRITE_AXE, + CHARACTER_SPRITE_BOW, + CHARACTER_SPRITE_CROSSBOW, + CHARACTER_SPRITE_DAGGER, + CHARACTER_SPRITE_HAMMER, + CHARACTER_SPRITE_NORMAL, + CHARACTER_SPRITE_SPIKE, + CHARACTER_SPRITE_SWORD, + CHARACTER_SPRITE_WAND, + CHARACTER_SPRITE_NUM +}; + +enum character_equipment { + CHARACTER_EQUIPMENT_GLOVES, + CHARACTER_EQUIPMENT_HELMET, + CHARACTER_EQUIPMENT_SHIELD, + CHARACTER_EQUIPMENT_TOP, + CHARACTER_EQUIPMENT_TROUSERS, + CHARACTER_EQUIPMENT_WEAPON, + CHARACTER_EQUIPMENT_NUM +}; + +struct character { + const char *name; + enum character_status status; + unsigned int level; + int hp; + unsigned int hpmax; + unsigned int hpbonus; + int mp; + unsigned int mpmax; + unsigned int mpbonus; + int atk; + unsigned int atkbonus; + int def; + unsigned int defbonus; + int agt; + unsigned int agtbonus; + int luck; + unsigned int luckbonus; + unsigned int team_order; + + struct sprite *sprites[CHARACTER_SPRITE_NUM]; + const struct equipment *equipments[CHARACTER_EQUIPMENT_NUM]; + const struct spell *spells[CHARACTER_SPELL_MAX]; + + void (*reset)(struct character *owner); + void (*exec)(struct character *owner, struct battle *bt); +}; + +CORE_BEGIN_DECLS + +int +character_ok(const struct character *ch); + +const char * +character_status_string(enum character_status status); + +void +character_reset(struct character *ch); + +void +character_exec(struct character *ch, struct battle *bt); + +int +character_save(const struct character *ch, struct save *s); + +int +character_load(struct character *, struct save *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_CHARACTER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/equipment.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,38 @@ +/* + * equipment.h -- character equipment + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include "character.h" +#include "equipment.h" + +int +equipment_ok(const struct equipment *eq) +{ + return eq && eq->name && eq->description; +} + +void +equipment_equip(const struct equipment *eq, struct character *ch) +{ + assert(equipment_ok(eq)); + assert(character_ok(ch)); + + if (eq->equip) + eq->equip(eq, ch); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/equipment.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,66 @@ +/* + * equipment.h -- character equipment + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_EQUIPMENT_H +#define MLK_RPG_EQUIPMENT_H + +#include <mlk/core/core.h> + +struct character; +struct texture; + +enum equipment_type { + /* Attack weapons. */ + EQUIPMENT_TYPE_AXE, + EQUIPMENT_TYPE_BOW, + EQUIPMENT_TYPE_CROSSBOW, + EQUIPMENT_TYPE_DAGGER, + EQUIPMENT_TYPE_HAMMER, + EQUIPMENT_TYPE_SPIKE, + EQUIPMENT_TYPE_SWORD, + EQUIPMENT_TYPE_WAND, + + /* Defense equipment. */ + EQUIPMENT_TYPE_GLOVES, + EQUIPMENT_TYPE_HELMET, + EQUIPMENT_TYPE_SHIELD, + EQUIPMENT_TYPE_TOP, + EQUIPMENT_TYPE_TROUSERS, +}; + +struct equipment { + const char *name; + const char *description; + unsigned int price; + enum equipment_type type; + struct texture *icon; + + void (*equip)(const struct equipment *, struct character *); +}; + +CORE_BEGIN_DECLS + +int +equipment_ok(const struct equipment *); + +void +equipment_equip(const struct equipment *, struct character *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_EQUIPMENT_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/inventory.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,69 @@ +/* + * inventory.c -- item inventory + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stddef.h> + +#include "inventory.h" + +static struct inventory_slot * +find(struct inventory *iv, const struct item *item) +{ + for (size_t i = 0; i < INVENTORY_ITEM_MAX; ++i) + if (iv->items[i].item == item) + return &iv->items[i]; + + return NULL; +} + +int +inventory_add(struct inventory *iv, const struct item *item, unsigned int amount) +{ + assert(iv); + assert(item); + + struct inventory_slot *slot; + + /* Find one existing, otherwise find one empty. */ + if (!(slot = find(iv, item))) + slot = find(iv, NULL); + + if (!slot) + return 0; + + slot->item = item; + slot->amount += amount; + + return -1; +} + +void +inventory_consume(struct inventory *iv, const struct item *item, unsigned int amount) +{ + assert(iv); + assert(item); + + struct inventory_slot *slot; + + if ((slot = find(iv, item))) { + slot->amount -= amount; + + if (slot->amount == 0) + slot->item = NULL; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/inventory.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,47 @@ +/* + * inventory.h -- item inventory + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_INVENTORY_H +#define MLK_RPG_INVENTORY_H + +#include <mlk/core/core.h> + +#define INVENTORY_ITEM_MAX (512) + +struct item; + +struct inventory_slot { + unsigned int amount; + const struct item *item; +}; + +struct inventory { + struct inventory_slot items[INVENTORY_ITEM_MAX]; +}; + +CORE_BEGIN_DECLS + +int +inventory_add(struct inventory *, const struct item *, unsigned int); + +void +inventory_consume(struct inventory *, const struct item *, unsigned int); + +CORE_END_DECLS + +#endif /* !MLK_RPG_INVENTORY_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/item.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,44 @@ +/* + * item.c -- inventory items + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include "item.h" + +void +item_exec_menu(const struct item *item, struct character *ch) +{ + assert(item); + assert(ch); + + item->exec_menu(item, ch); +} + +void +item_exec_battle(const struct item *item, + struct battle *bt, + struct character *src, + struct character *tgt) +{ + assert(item); + assert(bt); + assert(src); + assert(tgt); + + item->exec_battle(item, bt, src, tgt); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/item.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,54 @@ +/* + * item.h -- inventory items + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_ITEM_H +#define MLK_RPG_ITEM_H + +#include <mlk/core/core.h> + +struct battle; +struct character; +struct texture; + +struct item { + const char *name; + const char *description; + struct texture *icon; + + void (*exec_menu)(const struct item *, struct character *); + + void (*exec_battle)(const struct item *, + struct battle *, + struct character *, + struct character *); +}; + +CORE_BEGIN_DECLS + +void +item_exec_menu(const struct item *, struct character *); + +void +item_exec_battle(const struct item *, + struct battle *, + struct character *, + struct character *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_ITEM_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/map-file.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,312 @@ +/* + * map-file.c -- map file loader + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <mlk/util/util.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/error.h> +#include <mlk/core/image.h> +#include <mlk/core/trace.h> +#include <mlk/core/util.h> + +#include "map-file.h" + +#define MAX_F(v) MAX_F_(v) +#define MAX_F_(v) "%" #v "[^\n|]" + +struct context { + struct map_file *mf; /* Map loader. */ + struct map *map; /* Map object to fill. */ + FILE *fp; /* Map file pointer. */ + char basedir[PATH_MAX]; /* Parent map directory */ +}; + +static int +parse_layer_tiles(struct context *ctx, const char *layer_name) +{ + enum map_layer_type layer_type; + size_t amount, current; + + if (strcmp(layer_name, "background") == 0) + layer_type = MAP_LAYER_TYPE_BACKGROUND; + else if (strcmp(layer_name, "foreground") == 0) + layer_type = MAP_LAYER_TYPE_FOREGROUND; + else if (strcmp(layer_name, "above") == 0) + layer_type = MAP_LAYER_TYPE_ABOVE; + else + return errorf("invalid layer type: %s", layer_name); + + amount = ctx->map->columns * ctx->map->rows; + current = 0; + + /* + * The next line after a layer declaration is a list of plain integer + * that fill the layer tiles. + */ + if (!(ctx->mf->layers[layer_type].tiles = alloc_array0(amount, sizeof (unsigned short)))) + return -1; + + for (int tile; fscanf(ctx->fp, "%d\n", &tile) && current < amount; ++current) + ctx->mf->layers[layer_type].tiles[current] = tile; + + ctx->map->layers[layer_type].tiles = ctx->mf->layers[layer_type].tiles; + + return 0; +} + +static int +parse_actions(struct context *ctx) +{ + char exec[128 + 1]; + int x = 0, y = 0, block = 0; + unsigned int w = 0, h = 0; + + while (fscanf(ctx->fp, "%d|%d|%u|%u|%d|%128[^\n]\n", &x, &y, &w, &h, &block, exec) >= 5) { + struct map_block *reg; + + if (!ctx->mf->load_action) { + tracef("ignoring action %d,%d,%u,%u,%d,%s", x, y, w, h, block, exec); + continue; + } + + ctx->mf->load_action(ctx->map, x, y, w, h, exec); + + /* + * Actions do not have concept of collisions because they are + * not only used on maps. The map structure has its very own + * object to manage collisions but the .map file use the same + * directive for simplicity. So create a block region if the + * directive has one. + */ + if (block) { + if (!(reg = alloc_pool_new(&ctx->mf->blocks))) + return -1; + + reg->x = x; + reg->y = y; + reg->w = w; + reg->h = h; + } + } + + /* Reference the blocks array from map_file. */ + ctx->map->blocks = ctx->mf->blocks.data; + ctx->map->blocksz = ctx->mf->blocks.size; + + return 0; +} + +static int +parse_layer(struct context *ctx, const char *line) +{ + char layer_name[32 + 1] = {0}; + + /* Check if weight/height has been specified. */ + if (ctx->map->columns == 0 || ctx->map->rows == 0) + return errorf("missing map dimensions before layer"); + + /* Determine layer type. */ + if (sscanf(line, "layer|%32s", layer_name) <= 0) + return errorf("missing layer type definition"); + + if (strcmp(layer_name, "actions") == 0) + return parse_actions(ctx); + + return parse_layer_tiles(ctx, layer_name); +} + +static int +parse_tileset(struct context *ctx, const char *line) +{ + char path[PATH_MAX] = {0}, *p; + struct map_file *mf = ctx->mf; + struct tileset_file *tf = &mf->tileset_file; + + if (!(p = strchr(line, '|'))) + return errorf("could not parse tileset"); + + snprintf(path, sizeof (path), "%s/%s", ctx->basedir, p + 1); + + if (tileset_file_open(tf, &mf->tileset, path) < 0) + return -1; + + ctx->map->tileset = &mf->tileset; + + return 0; +} + +static int +parse_title(struct context *ctx, const char *line) +{ + if (sscanf(line, "title|" MAX_F(MAP_FILE_TITLE_MAX), ctx->mf->title) != 1 || strlen(ctx->mf->title) == 0) + return errorf("null map title"); + + ctx->map->title = ctx->mf->title; + + return 0; +} + +static int +parse_columns(struct context *ctx, const char *line) +{ + if (sscanf(line, "columns|%u", &ctx->map->columns) != 1 || ctx->map->columns == 0) + return errorf("null map columns"); + + return 0; +} + +static int +parse_rows(struct context *ctx, const char *line) +{ + if (sscanf(line, "rows|%u", &ctx->map->rows) != 1 || ctx->map->rows == 0) + return errorf("null map rows"); + + return 0; +} + +static int +parse_origin(struct context *ctx, const char *line) +{ + if (sscanf(line, "origin|%d|%d", &ctx->map->player_x, &ctx->map->player_y) != 2) + return errorf("invalid origin"); + + return 0; +} + +static int +parse_line(struct context *ctx, const char *line) +{ + static const struct { + const char *property; + int (*read)(struct context *, const char *); + } props[] = { + { "title", parse_title }, + { "columns", parse_columns }, + { "rows", parse_rows }, + { "tileset", parse_tileset }, + { "origin", parse_origin }, + { "layer", parse_layer }, + }; + + for (size_t i = 0; i < UTIL_SIZE(props); ++i) + if (strncmp(line, props[i].property, strlen(props[i].property)) == 0) + return props[i].read(ctx, line); + + return 0; +} + +static int +parse(struct context *ctx, const char *path) +{ + char line[1024]; + char basedir[PATH_MAX]; + + util_strlcpy(basedir, path, sizeof (basedir)); + util_strlcpy(ctx->basedir, util_dirname(basedir), sizeof (ctx->basedir)); + + while (fgets(line, sizeof (line), ctx->fp)) { + /* Remove \n if any */ + line[strcspn(line, "\r\n")] = '\0'; + + if (parse_line(ctx, line) < 0) + return -1; + } + + return 0; +} + +static int +check(struct map *map) +{ + /* + * Check that we have parsed every required components. + */ + if (!map->title) + return errorf("missing title"); + + /* + * We don't need to check width/height because parsing layers and + * tilesets already check for their presence, so only check layers. + */ + if (!map->layers[0].tiles) + return errorf("missing background layer"); + if (!map->layers[1].tiles) + return errorf("missing foreground layer"); + if (!tileset_ok(map->tileset)) + return errorf("missing tileset"); + + return 0; +} + +int +map_file_open(struct map_file *file, struct map *map, const char *path) +{ + assert(file); + assert(path); + assert(map); + + struct context ctx = { + .mf = file, + .map = map, + }; + int ret = 0; + + memset(map, 0, sizeof (*map)); + alloc_pool_init(&file->blocks, sizeof (*map->blocks), NULL); + + if (!(ctx.fp = fopen(path, "r"))) + goto fail; + if ((ret = parse(&ctx, path)) < 0 || (ret = check(map)) < 0) + goto fail; + + fclose(ctx.fp); + + return 0; + +fail: + map_finish(map); + map_file_finish(file); + + if (ctx.fp) + fclose(ctx.fp); + + return -1; +} + +void +map_file_finish(struct map_file *file) +{ + assert(file); + + free(file->layers[0].tiles); + free(file->layers[1].tiles); + free(file->layers[2].tiles); + + tileset_file_finish(&file->tileset_file); + alloc_pool_finish(&file->blocks); + + memset(file, 0, sizeof (*file)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/map-file.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,53 @@ +/* + * map-file.h -- map file loader + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_MAP_FILE_H +#define MLK_RPG_MAP_FILE_H + +#include <mlk/core/alloc.h> +#include <mlk/core/core.h> +#include <mlk/core/sprite.h> +#include <mlk/core/texture.h> + +#include "map.h" +#include "tileset.h" +#include "tileset-file.h" + +#define MAP_FILE_TITLE_MAX 64 + +struct map_file { + void (*load_action)(struct map *, int, int, int, int, const char *); + + char title[MAP_FILE_TITLE_MAX]; + struct map_layer layers[MAP_LAYER_TYPE_NUM]; + struct tileset_file tileset_file; + struct tileset tileset; + struct alloc_pool blocks; +}; + +CORE_BEGIN_DECLS + +int +map_file_open(struct map_file *file, struct map *map, const char *path); + +void +map_file_finish(struct map_file *file); + +CORE_END_DECLS + +#endif /* !MLK_RPG_MAP_FILE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/map.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,672 @@ +/* + * map.c -- game map + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <mlk/core/error.h> +#include <mlk/core/event.h> +#include <mlk/core/image.h> +#include <mlk/core/maths.h> +#include <mlk/core/painter.h> +#include <mlk/core/sprite.h> +#include <mlk/core/sys.h> +#include <mlk/core/texture.h> +#include <mlk/core/window.h> + +#include <mlk/ui/debug.h> + +#include "map.h" +#include "tileset.h" + +/* + * This is the speed the player moves on the map. + * + * SPEED represents the number of pixels it must move per SEC. + * SEC simply represends the number of milliseconds in one second. + */ +#define SPEED 100 +#define SEC 1000 + +/* + * Those are margins within the edge of the screen. The camera always try to + * keep those padding between the player and the screen. + */ +#define MARGIN_WIDTH 160 +#define MARGIN_HEIGHT 90 + +#define WIDTH(map) ((map)->columns * (map)->tileset->sprite->cellw) +#define HEIGHT(map) ((map)->rows * (map)->tileset->sprite->cellh) + +/* + * This structure defines the possible movement of the player as flags since + * it's possible to make diagonal movements. + */ +enum movement { + MOVING_UP = 1 << 0, + MOVING_RIGHT = 1 << 1, + MOVING_DOWN = 1 << 2, + MOVING_LEFT = 1 << 3 +}; + +/* + * A bit of explanation within this array. The structure walksprite requires + * an orientation between 0-7 depending on the user direction. + * + * Since keys for moving the character may be pressed at the same time, we need + * a conversion table from "key pressed" to "orientation". + * + * When an orientation is impossible, it is set to -1. Example, when both left + * and right are pressed. + * + * MOVING_UP = 0001 = 0x1 + * MOVING_RIGHT = 0010 = 0x2 + * MOVING_DOWN = 0100 = 0x3 + * MOVING_LEFT = 1000 = 0x4 + */ +static unsigned int orientations[16] = { + [0x1] = 0, + [0x2] = 2, + [0x3] = 1, + [0x4] = 4, + [0x6] = 3, + [0x8] = 6, + [0x9] = 7, + [0xC] = 5 +}; + +/* + * Check if this block is usable for collision detection. For example if the + * player is moving upwards but the collision shape is below it is unnecessary + * to check. + */ +static int +is_block_relevant(const struct map *map, + const struct map_block *block, + int drow, + int dcol) +{ + if (drow) { + /* Object outside of left-right bounds. */ + if (block->x + (int)block->w <= map->player_x || + block->x >= map->player_x + (int)map->player_sprite->cellw) + return 0; + + if ((drow < 0 && block->y >= map->player_y + (int)map->player_sprite->cellh) || + (drow > 0 && block->y + block->h <= map->player_y + map->player_sprite->cellh)) + return 0; + } else if (dcol) { + /* Object outside of up-down bounds. */ + if (block->y + (int)block->h <= map->player_y || + block->y >= map->player_y + (int)map->player_sprite->cellh) + return 0; + + if ((dcol < 0 && block->x >= map->player_x + (int)map->player_sprite->cellw) || + (dcol > 0 && block->x + block->w <= map->player_x + map->player_sprite->cellw)) + return 0; + } + + return 1; +} + +/* + * Determine if this collision shape is "closer" to the player by checking the + * new block coordinates with the previous one. + */ +static int +is_block_better(const struct map_block *now, + const struct map_block *new, + int drow, + int dcol) +{ + return ((drow < 0 && new->y + new->h > now->y + now->h) || + (drow > 0 && new->y < now->y) || + (dcol < 0 && new->x + new->w > now->x + now->w) || + (dcol > 0 && new->x < now->x)); + +} + +static void +center(struct map *map) +{ + map->view_x = map->player_x - (int)(map->view_w / 2); + map->view_y = map->player_y - (int)(map->view_h / 2); + + if (map->view_x < 0) + map->view_x = 0; + else if ((unsigned int)map->view_x > WIDTH(map) - map->view_w) + map->view_x = WIDTH(map) - map->view_w; + + if (map->view_y < 0) + map->view_y = 0; + else if ((unsigned int)map->view_y > HEIGHT(map) - map->view_h) + map->view_y = HEIGHT(map) - map->view_h; +} + +static void +init(struct map *map) +{ + /* Adjust view. */ + map->view_w = window.w; + map->view_h = window.h; + + /* Adjust margin. */ + map->margin_w = map->view_w - (MARGIN_WIDTH * 2) - map->player_sprite->cellw; + map->margin_h = map->view_h - (MARGIN_HEIGHT * 2) - map->player_sprite->cellh; + + /* Center the view by default. */ + center(map); + + /* Final bits. */ + walksprite_init(&map->player_ws, map->player_sprite, 150); +} + +static void +handle_keydown(struct map *map, const union event *event) +{ + switch (event->key.key) { + case KEY_UP: + map->player_movement |= MOVING_UP; + break; + case KEY_RIGHT: + map->player_movement |= MOVING_RIGHT; + break; + case KEY_DOWN: + map->player_movement |= MOVING_DOWN; + break; + case KEY_LEFT: + map->player_movement |= MOVING_LEFT; + break; + default: + break; + } + + map->player_angle = orientations[map->player_movement]; +} + +static void +handle_keyup(struct map *map, const union event *event) +{ + switch (event->key.key) { + case KEY_TAB: + map->flags ^= MAP_FLAGS_SHOW_GRID | MAP_FLAGS_SHOW_COLLIDE; + break; + case KEY_UP: + map->player_movement &= ~(MOVING_UP); + break; + case KEY_RIGHT: + map->player_movement &= ~(MOVING_RIGHT); + break; + case KEY_DOWN: + map->player_movement &= ~(MOVING_DOWN); + break; + case KEY_LEFT: + map->player_movement &= ~(MOVING_LEFT); + break; + default: + break; + } +} + +static int +cmp_tile(const struct tileset_tiledef *td1, const struct tileset_tiledef *td2) +{ + if (td1->id < td2->id) + return -1; + if (td1->id > td2->id) + return 1; + + return 0; +} + +static struct tileset_tiledef * +find_tiledef_by_id(const struct map *map, unsigned short id) +{ + typedef int (*cmp)(const void *, const void *); + + const struct tileset_tiledef key = { + .id = id + }; + + return bsearch(&key, map->tileset->tiledefs, map->tileset->tiledefsz, + sizeof (key), (cmp)cmp_tile); +} + +static struct tileset_tiledef * +find_tiledef_by_row_column_in_layer(const struct map *map, + const struct map_layer *layer, + int row, + int col) +{ + unsigned short id; + + if (row < 0 || (unsigned int)row >= map->rows || + col < 0 || (unsigned int)col >= map->columns) + return 0; + + if ((id = layer->tiles[col + row * map->columns]) == 0) + return NULL; + + return find_tiledef_by_id(map, id - 1); +} + +static struct tileset_tiledef * +find_tiledef_by_row_column(const struct map *map, int row, int col) +{ + struct tileset_tiledef *tile; + + /* TODO: probably a for loop when we have indefinite layers. */ + if (!(tile = find_tiledef_by_row_column_in_layer(map, &map->layers[1], row, col))) + tile = find_tiledef_by_row_column_in_layer(map, &map->layers[0], row, col); + + return tile; +} + +static void +find_block_iterate(const struct map *map, + struct map_block *block, + int rowstart, + int rowend, + int colstart, + int colend, + int drow, + int dcol) +{ + assert(map); + assert(block); + + /* First, check with tiledefs. */ + for (int r = rowstart; r <= rowend; ++r) { + for (int c = colstart; c <= colend; ++c) { + struct tileset_tiledef *td; + struct map_block tmp; + + if (!(td = find_tiledef_by_row_column(map, r, c))) + continue; + + /* Convert to absolute values. */ + tmp.x = td->x + c * map->tileset->sprite->cellw; + tmp.y = td->y + r * map->tileset->sprite->cellh; + tmp.w = td->w; + tmp.h = td->h; + + /* This tiledef is out of context. */ + if (!is_block_relevant(map, &tmp, drow, dcol)) + continue; + + if (is_block_better(block, &tmp, drow, dcol)) { + block->x = tmp.x; + block->y = tmp.y; + block->w = tmp.w; + block->h = tmp.h; + } + } + } + + /* Now check if there are objects closer than tiledefs. */ + for (size_t i = 0; i < map->blocksz; ++i) { + const struct map_block *new = &map->blocks[i]; + + if (is_block_relevant(map, new, drow, dcol) && + is_block_better(block, new, drow, dcol)) { + block->x = new->x; + block->y = new->y; + block->w = new->w; + block->h = new->h; + } + } +} + +static void +find_collision(const struct map *map, struct map_block *block, int drow, int dcolumn) +{ + assert((drow && !dcolumn) || (dcolumn && !drow)); + + const int playercol = map->player_x / map->tileset->sprite->cellw; + const int playerrow = map->player_y / map->tileset->sprite->cellh; + const int ncols = (map->player_sprite->cellw / map->tileset->sprite->cellw) + 1; + const int nrows = (map->player_sprite->cellh / map->tileset->sprite->cellh) + 1; + int rowstart, rowend, colstart, colend; + + if (drow) { + colstart = playercol; + colend = playercol + ncols; + + if (drow < 0) { + /* Moving UP. */ + rowstart = 0; + rowend = playerrow; + block->x = block->y = block->h = 0; + block->w = WIDTH(map); + } else { + /* Moving DOWN. */ + rowstart = playerrow; + rowend = HEIGHT(map); + block->x = block->h = 0; + block->y = HEIGHT(map); + block->w = WIDTH(map); + } + } else { + rowstart = playerrow; + rowend = playerrow + nrows; + + if (dcolumn < 0) { + /* Moving LEFT. */ + colstart = 0; + colend = playercol; + block->x = block->y = block->w = 0; + block->h = HEIGHT(map); + } else { + /* Moving RIGHT. */ + colstart = playercol; + colend = WIDTH(map); + block->x = WIDTH(map); + block->y = block->w = 0; + block->h = block->h; + } + } + + find_block_iterate(map, block, rowstart, rowend, colstart, colend, drow, dcolumn); +} + +static void +move_x(struct map *map, int delta) +{ + struct map_block block; + + find_collision(map, &block, 0, delta < 0 ? -1 : +1); + + if (delta < 0 && map->player_x + delta < (int)(block.x + block.w)) + delta = map->player_x - block.x - block.w; + else if (delta > 0 && (int)(map->player_x + map->player_sprite->cellw + delta) >= block.x) + delta = block.x - map->player_x - (int)(map->player_sprite->cellw); + + map->player_x += delta; + + if ((delta < 0 && map->player_x < map->margin_x) || + (delta > 0 && map->player_x >= (int)(map->margin_x + map->margin_w))) + map->view_x += delta; + + if (map->view_x < 0) + map->view_x = 0; + else if (map->view_x >= (int)(WIDTH(map) - map->view_w)) + map->view_x = WIDTH(map) - map->view_w; +} + +static void +move_y(struct map *map, int delta) +{ + struct map_block block; + + find_collision(map, &block, delta < 0 ? -1 : +1, 0); + + if (delta < 0 && map->player_y + delta < (int)(block.y + block.h)) + delta = map->player_y - block.y - block.h; + else if (delta > 0 && (int)(map->player_y + map->player_sprite->cellh + delta) >= block.y) + delta = block.y - map->player_y - (int)(map->player_sprite->cellh); + + map->player_y += delta; + + if ((delta < 0 && map->player_y < map->margin_y) || + (delta > 0 && map->player_y >= (int)(map->margin_y + map->margin_h))) + map->view_y += delta; + + if (map->view_y < 0) + map->view_y = 0; + else if (map->view_y >= (int)(HEIGHT(map) - map->view_h)) + map->view_y = HEIGHT(map) - map->view_h; +} + +static void +move(struct map *map, unsigned int ticks) +{ + /* This is the amount of pixels the player must move. */ + const int delta = SPEED * ticks / SEC; + + /* This is the rectangle within the view where users must be. */ + map->margin_x = map->view_x + MARGIN_WIDTH; + map->margin_y = map->view_y + MARGIN_HEIGHT; + + int dx = 0; + int dy = 0; + + if (map->player_movement == 0) + return; + + if (map->player_movement & MOVING_UP) + dy = -1; + if (map->player_movement & MOVING_DOWN) + dy = 1; + if (map->player_movement & MOVING_LEFT) + dx = -1; + if (map->player_movement & MOVING_RIGHT) + dx = 1; + + /* Move the player and adjust view if needed. */ + if (dx) + move_x(map, dx * delta); + if (dy) + move_y(map, dy * delta); + + walksprite_update(&map->player_ws, ticks); +} + +static inline void +draw_layer_tile(const struct map *map, + const struct map_layer *layer, + struct texture *colbox, + int start_col, + int start_row, + int start_x, + int start_y, + unsigned int r, + unsigned int c) +{ + const struct tileset_tiledef *td; + int index, id, sc, sr, mx, my; + + index = (start_col + c) + ((start_row + r) * map->columns); + + if ((id = layer->tiles[index]) == 0) + return; + + id -= 1; + + /* Sprite row/column. */ + sc = (id) % map->tileset->sprite->ncols; + sr = (id) / map->tileset->sprite->ncols; + + /* On screen coordinates. */ + mx = start_x + (int)c * (int)map->tileset->sprite->cellw; + my = start_y + (int)r * (int)map->tileset->sprite->cellh; + + tileset_draw(map->tileset, sr, sc, mx, my); + + if ((td = find_tiledef_by_id(map, id)) && texture_ok(colbox)) + texture_scale(colbox, 0, 0, 5, 5, mx + td->x, my + td->y, td->w, td->h, 0); + + if (map->flags & MAP_FLAGS_SHOW_GRID) { + painter_set_color(0x202e37ff); + painter_draw_line(mx, my, mx + (int)map->tileset->sprite->cellw, my); + painter_draw_line( + mx + (int)map->tileset->sprite->cellw - 1, my, + mx + (int)map->tileset->sprite->cellw - 1, my + (int)map->tileset->sprite->cellh); + } +} + +static void +draw_layer(const struct map *map, const struct map_layer *layer) +{ + assert(map); + assert(layer); + + /* Beginning of view in row/column. */ + const unsigned int start_col = map->view_x / map->tileset->sprite->cellw; + const unsigned int start_row = map->view_y / map->tileset->sprite->cellh; + + /* Convert into x/y coordinate. */ + const int start_x = 0 - (map->view_x % (int)map->tileset->sprite->cellw); + const int start_y = 0 - (map->view_y % (int)map->tileset->sprite->cellh); + + /* Number of row/columns to draw starting from there. */ + const unsigned int ncols = (map->view_w / map->tileset->sprite->cellw) + 2; + const unsigned int nrows = (map->view_h / map->tileset->sprite->cellh) + 2; + + struct texture colbox = {0}; + + if (!layer->tiles) + return; + + /* Show collision box if requested. */ + if (map->flags & MAP_FLAGS_SHOW_COLLIDE && texture_new(&colbox, 16, 16) == 0) { + texture_set_blend_mode(&colbox, TEXTURE_BLEND_BLEND); + texture_set_alpha_mod(&colbox, 100); + PAINTER_BEGIN(&colbox); + painter_set_color(0xa53030ff); + painter_clear(); + PAINTER_END(); + } + + for (unsigned int r = 0; r < nrows; ++r) { + for (unsigned int c = 0; c < ncols; ++c) { + if (start_col + c >= map->columns || + start_row + r >= map->rows) + continue; + + draw_layer_tile(map, layer, &colbox, start_col, start_row, start_x, start_y, r, c); + } + } + + texture_finish(&colbox); +} + +static void +draw_collide(const struct map *map) +{ + struct texture box = {0}; + + if (map->flags & MAP_FLAGS_SHOW_COLLIDE && texture_new(&box, 64, 64) == 0) { + /* Draw collide box around player if requested. */ + texture_set_alpha_mod(&box, 100); + texture_set_blend_mode(&box, TEXTURE_BLEND_BLEND); + PAINTER_BEGIN(&box); + painter_set_color(0x4f8fbaff); + painter_clear(); + PAINTER_END(); + texture_scale(&box, 0, 0, 64, 64, + map->player_x - map->view_x, map->player_y - map->view_y, + map->player_sprite->cellw, map->player_sprite->cellh, 0.f); + + /* Do the same for every objects. */ + PAINTER_BEGIN(&box); + painter_set_color(0xa8ca58ff); + painter_clear(); + PAINTER_END(); + + for (size_t i = 0; i < map->blocksz; ++i) { + texture_scale(&box, 0, 0, 64, 64, + map->blocks[i].x - map->view_x, map->blocks[i].y - map->view_y, + map->blocks[i].w, map->blocks[i].h, + 0.f); + } + + texture_finish(&box); + } +} + +int +map_init(struct map *map) +{ + assert(map); + + init(map); + tileset_start(map->tileset); + + return 0; +} + +void +map_handle(struct map *map, const union event *ev) +{ + assert(map); + assert(ev); + + switch (ev->type) { + case EVENT_KEYDOWN: + handle_keydown(map, ev); + break; + case EVENT_KEYUP: + handle_keyup(map, ev); + break; + default: + break; + } + + action_stack_handle(&map->astack_par, ev); + action_stack_handle(&map->astack_seq, ev); +} + +void +map_update(struct map *map, unsigned int ticks) +{ + assert(map); + + action_stack_update(&map->astack_par, ticks); + action_stack_update(&map->astack_seq, ticks); + + tileset_update(map->tileset, ticks); + + /* No movements if the sequential actions are running. */ + if (action_stack_completed(&map->astack_seq)) + move(map, ticks); +} + +void +map_draw(const struct map *map) +{ + assert(map); + + /* Draw the texture about background/foreground. */ + draw_layer(map, &map->layers[MAP_LAYER_TYPE_BACKGROUND]); + draw_layer(map, &map->layers[MAP_LAYER_TYPE_FOREGROUND]); + + walksprite_draw( + &map->player_ws, + map->player_angle, + map->player_x - map->view_x, + map->player_y - map->view_y); + + draw_layer(map, &map->layers[MAP_LAYER_TYPE_ABOVE]); + draw_collide(map); + + action_stack_draw(&map->astack_par); + action_stack_draw(&map->astack_seq); +} + +void +map_finish(struct map *map) +{ + assert(map); + + action_stack_finish(&map->astack_par); + action_stack_finish(&map->astack_seq); + + memset(map, 0, sizeof (*map)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/map.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,120 @@ +/* + * map.h -- game map + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_MAP_H +#define MLK_RPG_MAP_H + +#include <stddef.h> + +#include <mlk/core/action.h> +#include <mlk/core/action-stack.h> +#include <mlk/core/core.h> + +#include "walksprite.h" + +struct tileset; + +union event; + +enum map_layer_type { + MAP_LAYER_TYPE_BACKGROUND, + MAP_LAYER_TYPE_FOREGROUND, + MAP_LAYER_TYPE_ABOVE, + MAP_LAYER_TYPE_NUM +}; + +struct map_layer { + unsigned short *tiles; +}; + +enum map_flags { + MAP_FLAGS_NONE = 0, + MAP_FLAGS_SHOW_GRID = (1 << 0), + MAP_FLAGS_SHOW_COLLIDE = (1 << 2) +}; + +struct map_block { + int x; + int y; + unsigned int w; + unsigned int h; +}; + +struct map { + const char *title; /*!< (+) Map title name. */ + unsigned int columns; /*!< (-) Number of columns. */ + unsigned int rows; /*!< (-) Number of rows. */ + + /* Tileset. */ + struct tileset *tileset; /*!< (+&?) Tileset to use. */ + + /* View options. */ + enum map_flags flags; /*!< (+) View options. */ + + /* Extra collisions blocks. */ + struct map_block *blocks; /*!< (+&?) Extra collisions. */ + size_t blocksz; /*!< (+) Number of collisions. */ + + /* List of actions. */ + struct action_stack astack_par; /*!< (+) Parallel actions. */ + struct action_stack astack_seq; /*!< (+) Blocking actions. */ + + /* Player. */ + struct sprite *player_sprite; /*!< (+) The sprite to use */ + struct walksprite player_ws; /*!< (-) Walking sprite for moving the player. */ + int player_x; /*!< (+) Player position in x */ + int player_y; /*!< (+) Player position in y */ + int player_angle; /*!< (+) Player angle (see walksprite) */ + unsigned int player_movement; /*!< (*) Current player movements. */ + + /* View to zoom/locate. */ + int view_x; /*!< (+) Position in x */ + int view_y; /*!< (+) Position in y */ + unsigned int view_w; /*!< (+) View width */ + unsigned int view_h; /*!< (+) View height */ + + /* View margin. */ + int margin_x; /*!< (+) View margin in x. */ + int margin_y; /*!< (+) View margin in y. */ + unsigned int margin_w; /*!< (+) Margin width. */ + unsigned int margin_h; /*!< (+) Margin height. */ + + /* Different tile layers. */ + struct map_layer layers[MAP_LAYER_TYPE_NUM]; +}; + +CORE_BEGIN_DECLS + +int +map_init(struct map *map); + +void +map_handle(struct map *map, const union event *ev); + +void +map_update(struct map *map, unsigned int ticks); + +void +map_draw(const struct map *map); + +void +map_finish(struct map *map); + +CORE_END_DECLS + +#endif /* !MLK_RPG_MAP_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/message.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,316 @@ +/* + * message.c -- message dialog + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <mlk/core/action.h> +#include <mlk/core/event.h> +#include <mlk/core/font.h> +#include <mlk/core/maths.h> +#include <mlk/core/painter.h> +#include <mlk/core/panic.h> +#include <mlk/core/sprite.h> +#include <mlk/core/trace.h> +#include <mlk/core/util.h> + +#include <mlk/ui/align.h> +#include <mlk/ui/frame.h> +#include <mlk/ui/label.h> +#include <mlk/ui/theme.h> + +#include "message.h" + +#define THEME(msg) (msg->theme ? msg->theme : theme_default()) + +static void +handle(struct action *action, const union event *ev) +{ + assert(action); + assert(ev); + + message_handle(action->data, ev); +} + +static int +update(struct action *action, unsigned int ticks) +{ + assert(action); + + return message_update(action->data, ticks); +} + +static void +draw(struct action *action) +{ + assert(action); + + message_draw(action->data); +} + +static void +draw_frame(const struct message *msg) +{ + assert(msg); + + struct frame frame = { + .w = msg->w, + .h = msg->h, + .theme = msg->theme + }; + + frame_draw(&frame); +} + +static inline unsigned int +min_width(const struct message *msg) +{ + assert(msg); + + unsigned int maxw = 0, w = 0; + + for (size_t i = 0; i < msg->linesz; ++i) { + if (!msg->lines[i]) + continue; + if (font_query(THEME(msg)->fonts[THEME_FONT_INTERFACE], msg->lines[i], &w, NULL) < 0) + panic(); + if (w > maxw) + maxw = w; + } + + return (THEME(msg)->padding * 2) + maxw; +} + +static inline unsigned int +min_height(const struct message *msg) +{ + assert(msg); + + const struct theme *th = THEME(msg); + const unsigned int lh = font_height(th->fonts[THEME_FONT_INTERFACE]); + + return (th->padding * 2) + (msg->linesz * lh) + ((msg->linesz - 1) * msg->spacing); +} + +static void +draw_lines(const struct message *msg) +{ + const struct theme *theme = THEME(msg); + struct label label; + unsigned int lw, lh; + + for (size_t i = 0; i < msg->linesz; ++i) { + if (!msg->lines[i]) + continue; + if (font_query(theme->fonts[THEME_FONT_INTERFACE], msg->lines[i], &lw, &lh) < 0) + panic(); + + label.theme = theme; + label.x = theme->padding; + label.y = theme->padding + (i * (lh + msg->spacing)); + label.text = msg->lines[i]; + label.flags = LABEL_FLAGS_SHADOW; + + if (label.x + lw > msg->w) + tracef("message width too small: %u < %u", msg->w, min_width(msg)); + if (label.y + lh > msg->h) + tracef("message height too small: %u < %u", msg->h, min_height(msg)); + + /* + * The function label_draw will use THEME_COLOR_NORMAL to draw + * text and THEME_COLOR_SHADOW so if we have selected a line + * we need to cheat the normal color. + */ + if (msg->flags & MESSAGE_FLAGS_QUESTION && msg->index == (unsigned int)i) + label.flags |= LABEL_FLAGS_SELECTED; + else + label.flags &= ~(LABEL_FLAGS_SELECTED); + + label_draw(&label); + } +} + +void +message_start(struct message *msg) +{ + assert(msg); + + if (msg->flags & (MESSAGE_FLAGS_FADEIN|MESSAGE_FLAGS_FADEOUT)) + assert(msg->delay > 0); + + msg->elapsed = 0; + msg->scale = msg->flags & MESSAGE_FLAGS_FADEIN ? 0.0 : 1.0; + msg->state = msg->flags & MESSAGE_FLAGS_FADEIN + ? MESSAGE_STATE_OPENING + : MESSAGE_STATE_SHOWING; + + if (msg->flags & MESSAGE_FLAGS_AUTOMATIC && msg->timeout == 0) + tracef("message is automatic but has zero timeout"); +} + +void +message_query(const struct message *msg, unsigned int *w, unsigned int *h) +{ + assert(msg); + + if (w) + *w = min_width(msg); + if (h) + *h = min_height(msg); +} + +void +message_handle(struct message *msg, const union event *ev) +{ + assert(msg); + assert(ev); + + /* Skip if the message animation hasn't complete. */ + if (msg->state != MESSAGE_STATE_SHOWING) + return; + + /* Only keyboard event are valid. */ + if (ev->type != EVENT_KEYDOWN || msg->state == MESSAGE_STATE_NONE) + return; + + switch (ev->key.key) { + case KEY_UP: + if (msg->index > 0) + msg->index--; + break; + case KEY_DOWN: + if (msg->index + 1 < msg->linesz && msg->lines[msg->index + 1]) + msg->index++; + break; + case KEY_ENTER: + msg->state = msg->flags & MESSAGE_FLAGS_FADEOUT + ? MESSAGE_STATE_HIDING + : MESSAGE_STATE_NONE; + msg->elapsed = 0; + break; + default: + break; + } +} + +int +message_update(struct message *msg, unsigned int ticks) +{ + assert(msg); + + msg->elapsed += ticks; + + switch (msg->state) { + case MESSAGE_STATE_OPENING: + msg->scale = (double)msg->elapsed / (double)msg->delay; + + if (msg->scale > 1) + msg->scale = 1; + + if (msg->elapsed >= msg->delay) { + msg->state = MESSAGE_STATE_SHOWING; + msg->elapsed = 0; + } + + break; + case MESSAGE_STATE_SHOWING: + /* Do automatically switch state if requested by the user. */ + if (msg->flags & MESSAGE_FLAGS_AUTOMATIC && msg->elapsed >= msg->timeout) { + msg->state = msg->flags & MESSAGE_FLAGS_FADEOUT + ? MESSAGE_STATE_HIDING + : MESSAGE_STATE_NONE; + msg->elapsed = 0; + } + + break; + case MESSAGE_STATE_HIDING: + msg->scale = 1 - (double)msg->elapsed / (double)msg->delay; + + if (msg->scale < 0) + msg->scale = 0; + if (msg->elapsed >= msg->delay) { + msg->state = MESSAGE_STATE_NONE; + msg->elapsed = 0; + } + + break; + default: + break; + } + + return msg->state == MESSAGE_STATE_NONE; +} + +void +message_draw(const struct message *msg) +{ + assert(msg); + + struct texture tex; + int x, y; + unsigned int w, h; + + if (msg->w == 0 || msg->h == 0) { + tracef("message has null dimensions"); + return; + } + + if (texture_new(&tex, msg->w, msg->h) < 0) + panic(); + + PAINTER_BEGIN(&tex); + draw_frame(msg); + draw_lines(msg); + PAINTER_END(); + + /* Compute scaling. */ + w = msg->w * msg->scale; + h = msg->h * msg->scale; + + /* Centerize within its drawing area. */ + align(ALIGN_CENTER, &x, &y, w, h, msg->x, msg->y, msg->w, msg->h); + + /* Draw and clear. */ + texture_scale(&tex, 0, 0, msg->w, msg->h, x, y, w, h, 0); + texture_finish(&tex); +} + +void +message_hide(struct message *msg) +{ + assert(msg); + + msg->state = MESSAGE_STATE_HIDING; + msg->elapsed = 0; +} + +void +message_action(struct message *msg, struct action *action) +{ + assert(msg); + assert(action); + + memset(action, 0, sizeof (struct action)); + action->data = msg; + action->handle = handle; + action->update = update; + action->draw = draw; + + message_start(msg); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/message.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,91 @@ +/* + * message.h -- message dialog + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_MESSAGE_H +#define MLK_RPG_MESSAGE_H + +#include <mlk/core/core.h> +#include <mlk/core/texture.h> + +struct action; +struct font; +struct theme; + +union event; + +#define MESSAGE_DELAY_DEFAULT (150) +#define MESSAGE_TIMEOUT_DEFAULT (5000) + +enum message_flags { + MESSAGE_FLAGS_AUTOMATIC = (1 << 0), + MESSAGE_FLAGS_QUESTION = (1 << 1), + MESSAGE_FLAGS_FADEIN = (1 << 2), + MESSAGE_FLAGS_FADEOUT = (1 << 3) +}; + +enum message_state { + MESSAGE_STATE_NONE, + MESSAGE_STATE_OPENING, + MESSAGE_STATE_SHOWING, + MESSAGE_STATE_HIDING +}; + +struct message { + int x; + int y; + unsigned int w; + unsigned int h; + unsigned int spacing; + unsigned int delay; + unsigned int timeout; + const char * const *lines; + size_t linesz; + unsigned int index; + enum message_flags flags; + enum message_state state; + const struct theme *theme; + unsigned int elapsed; + double scale; +}; + +CORE_BEGIN_DECLS + +void +message_start(struct message *msg); + +void +message_query(const struct message *msg, unsigned int *w, unsigned int *h); + +void +message_handle(struct message *msg, const union event *ev); + +int +message_update(struct message *msg, unsigned int ticks); + +void +message_draw(const struct message *msg); + +void +message_hide(struct message *msg); + +void +message_action(struct message *msg, struct action *act); + +CORE_END_DECLS + +#endif /* !MLK_RPG_MESSAGE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/property.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,63 @@ +/* + * property.c -- manage game properties + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include <assets/sql/property-save.h> +#include <assets/sql/property-remove.h> +#include <assets/sql/property-load.h> + +#include "property.h" +#include "save.h" + +int +property_save(const struct property *p, struct save *s) +{ + assert(p); + assert(save_ok(s)); + + return save_exec(s, (const char *)assets_property_save, "ss", p->key, p->value); +} + +int +property_load(struct property *p, struct save *s) +{ + assert(p); + assert(save_ok(s)); + + struct save_stmt stmt; + enum save_stmt_errno ret; + + if (save_stmt_init(&stmt, s, (const char *)assets_property_load, "s", p->key) < 0) + return -1; + + ret = save_stmt_next(&stmt, "s", p->value, sizeof (p->value)) == SAVE_STMT_ROW; + save_stmt_finish(&stmt); + + return ret ? 0 : -1; +} + +int +property_remove(struct property *p, struct save *s) +{ + assert(p); + assert(save_ok(s)); + + return save_exec(s, (const char *)assets_property_remove, "s", p->key); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/property.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,47 @@ +/* + * property.h -- manage game properties + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_PROPERTY_H +#define MLK_RPG_PROPERTY_H + +#include <mlk/core/core.h> + +#define PROPERTY_KEY_MAX (64) +#define PROPERTY_VALUE_MAX (1024) + +struct save; + +struct property { + char key[PROPERTY_KEY_MAX + 1]; + char value[PROPERTY_VALUE_MAX + 1]; +}; + +CORE_BEGIN_DECLS + +int +property_save(const struct property *, struct save *); + +int +property_load(struct property *, struct save *); + +int +property_remove(struct property *, struct save *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_PROPERTY_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/quest.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,83 @@ +/* + * quest.c -- in game quests + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include <assets/sql/quest-remove.h> +#include <assets/sql/quest-save.h> +#include <assets/sql/quest-step-load.h> +#include <assets/sql/quest-step-save.h> + +#include "quest.h" +#include "save.h" + +int +quest_save(struct quest *q, struct save *s) +{ + assert(q); + assert(s); + + const struct quest_step *step; + + if (save_tx_begin(s) < 0) + return -1; + + if (save_exec(s, (const char *)assets_quest_save, "s", q->name) < 0) { + save_tx_rollback(s); + return -1; + } + + for (size_t i = 0; i < q->stepsz; ++i) { + step = &q->steps[i]; + + if (save_exec(s, (const char *)assets_quest_step_save, "ssi", q->name, step->name, step->percent) < 0) { + save_tx_rollback(s); + return -1; + } + } + + save_tx_commit(s); + + return 0; +} + +int +quest_load(struct quest *q, struct save *s) +{ + assert(q); + assert(s); + + struct save_stmt stmt; + struct quest_step *step; + + for (size_t i = 0; i < q->stepsz; ++i) { + step = &q->steps[i]; + + if (save_stmt_init(&stmt, s, (const char *)assets_quest_step_load, "s", step->name)) + return -1; + + if (save_stmt_next(&stmt, "i", &step->percent) < 0) { + save_stmt_finish(&stmt); + return -1; + } + + save_stmt_finish(&stmt); + } + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/quest.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,51 @@ +/* + * quest.h -- in game quests + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_QUEST_H +#define MLK_RPG_QUEST_H + +#include <stddef.h> + +#include <mlk/core/core.h> + +struct save; + +struct quest_step { + const char *name; + const char *description; + int percent; +}; + +struct quest { + const char *name; + const char *description; + struct quest_step *steps; + size_t stepsz; +}; + +CORE_BEGIN_DECLS + +int +quest_save(struct quest *, struct save *); + +int +quest_load(struct quest *, struct save *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_QUEST_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/rpg.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,30 @@ +/* + * rpg.c -- librpg convenient header + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "rpg.h" + +int +rpg_init(void) +{ + return 0; +} + +void +rpg_finish(void) +{ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/rpg.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,34 @@ +/* + * rpg.h -- librpg convenient header + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_RPG_H +#define MLK_RPG_RPG_H + +#include <mlk/core/core.h> + +CORE_BEGIN_DECLS + +int +rpg_init(void); + +void +rpg_finish(void); + +CORE_END_DECLS + +#endif /* !MLK_RPG_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/save.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,318 @@ +/* + * save.c -- save functions + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sqlite3.h> + +#include <mlk/util/util.h> + +#include <mlk/core/error.h> +#include <mlk/core/sys.h> +#include <mlk/core/util.h> + +#include <assets/sql/init.h> + +#include "property.h" +#include "save.h" + +#define SQL_BEGIN "BEGIN EXCLUSIVE TRANSACTION" +#define SQL_COMMIT "COMMIT" +#define SQL_ROLLBACK "ROLLBACK" + +static int +exec(struct save *db, const char *sql) +{ + if (sqlite3_exec(db->handle, sql, NULL, NULL, NULL) != SQLITE_OK) + return errorf("%s", sqlite3_errmsg(db->handle)); + + return 0; +} + +static const char * +path(unsigned int idx) +{ + return util_pathf("%s%u.db", sys_dir(SYS_DIR_SAVE), idx); +} + +static int +execu(struct save *db, const unsigned char *sql) +{ + return exec(db, (const char *)sql); +} + +static int +verify(struct save *db) +{ + struct { + time_t *date; + struct property prop; + } table[] = { + { .date = &db->created, { .key = "molko.create-date" } }, + { .date = &db->updated, { .key = "molko.update-date" } }, + }; + + /* Ensure create and update dates are present. */ + for (size_t i = 0; i < UTIL_SIZE(table); ++i) { + if (property_load(&table[i].prop, db) < 0) { + sqlite3_close(db->handle); + return errorf("database not initialized correctly"); + } + + *table[i].date = strtoull(table[i].prop.value, NULL, 10); + } + + return 0; +} + +static int +prepare(struct save *s, struct save_stmt *stmt, const char *sql, const char *args, va_list ap) +{ + stmt->parent = s; + stmt->handle = NULL; + + if (sqlite3_prepare(s->handle, sql, -1, (sqlite3_stmt **)&stmt->handle, NULL) != SQLITE_OK) + goto sqlite3_err; + + for (int i = 1; args && *args; ++args) { + switch (*args) { + case 'i': + case 'u': + if (sqlite3_bind_int(stmt->handle, i++, va_arg(ap, int)) != SQLITE_OK) + return -1; + break; + case 's': + if (sqlite3_bind_text(stmt->handle, i++, va_arg(ap, const char *), -1, NULL) != SQLITE_OK) + return -1; + break; + case 't': + if (sqlite3_bind_int64(stmt->handle, i++, va_arg(ap, time_t)) != SQLITE_OK) + return -1; + break; + case ' ': + break; + default: + return errorf("invalid format: %c", *args); + } + } + + return 0; + +sqlite3_err: + return errorf("%s", sqlite3_errmsg(s->handle)); +} + +static int +extract(struct save_stmt *stmt, const char *args, va_list ap) +{ + const int ncols = sqlite3_column_count(stmt->handle); + + for (int c = 0; args && *args; ++args) { + if (c >= ncols) + return errorf("too many arguments"); + + /* TODO: type check. */ + switch (*args) { + case 'i': + case 'u': + *va_arg(ap, int *) = sqlite3_column_int(stmt->handle, c++); + break; + case 's': { + char *str = va_arg(ap, char *); + size_t max = va_arg(ap, size_t); + + util_strlcpy(str, (const char *)sqlite3_column_text(stmt->handle, c++), max); + break; + } + case 't': + *va_arg(ap, time_t *) = sqlite3_column_int64(stmt->handle, c++); + break; + case ' ': + break; + default: + return errorf("invalid format: %c", *args); + } + } + + return 0; +} + +int +save_open(struct save *db, unsigned int idx, enum save_mode mode) +{ + assert(db); + + return save_open_path(db, path(idx), mode); +} + +int +save_open_path(struct save *db, const char *path, enum save_mode mode) +{ + assert(db); + assert(path); + + int flags = 0; + + switch (mode) { + case SAVE_MODE_WRITE: + flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + break; + default: + flags = SQLITE_OPEN_READONLY; + break; + } + + if (sqlite3_open_v2(path, (sqlite3**)&db->handle, flags, NULL) != SQLITE_OK) + goto sqlite3_err; + + if (mode == SAVE_MODE_WRITE && execu(db, assets_init) < 0) + goto sqlite3_err; + + return verify(db); + +sqlite3_err: + errorf("%s", sqlite3_errmsg(db->handle)); + sqlite3_close(db->handle); + + memset(db, 0, sizeof (*db)); + + return -1; +} + +int +save_ok(const struct save *db) +{ + assert(db); + + return db && db->handle; +} + +int +save_exec(struct save *db, const char *sql, const char *args, ...) +{ + assert(save_ok(db)); + assert(sql); + + struct save_stmt stmt; + enum save_stmt_errno ret; + va_list ap; + + va_start(ap, args); + ret = prepare(db, &stmt, sql, args, ap); + va_end(ap); + + if (ret < 0) + return -1; + + ret = save_stmt_next(&stmt, NULL); + save_stmt_finish(&stmt); + + return ret == SAVE_STMT_ERROR ? -1 : 0; +} + +void +save_finish(struct save *db) +{ + assert(db); + + if (db->handle) + sqlite3_close(db->handle); + + memset(db, 0, sizeof (*db)); +} + +int +save_stmt_init(struct save_stmt *stmt, struct save *db, const char *sql, const char *args, ...) +{ + assert(stmt); + assert(save_ok(db)); + assert(args); + + va_list ap; + int ret; + + va_start(ap, args); + ret = prepare(db, stmt, sql, args, ap); + va_end(ap); + + return ret; +} + +enum save_stmt_errno +save_stmt_next(struct save_stmt *stmt, const char *args, ...) +{ + assert(stmt); + + va_list ap; + enum save_stmt_errno ret = SAVE_STMT_ERROR; + + switch (sqlite3_step(stmt->handle)) { + case SQLITE_ROW: + va_start(ap, args); + + if (extract(stmt, args, ap) == 0) + ret = SAVE_STMT_ROW; + + va_end(ap); + break; + case SQLITE_DONE: + ret = SAVE_STMT_DONE; + break; + default: + errorf("%s", sqlite3_errmsg(stmt->parent->handle)); + break; + } + + return ret; +} + +void +save_stmt_finish(struct save_stmt *stmt) +{ + assert(stmt); + + sqlite3_finalize(stmt->handle); + memset(stmt, 0, sizeof (*stmt)); +} + +int +save_tx_begin(struct save *s) +{ + assert(save_ok(s)); + + return save_exec(s, "BEGIN EXCLUSIVE TRANSACTION", NULL); +} + +void +save_tx_rollback(struct save *s) +{ + assert(save_ok(s)); + + (void)save_exec(s, "ROLLBACK", NULL); +} + +void +save_tx_commit(struct save *s) +{ + assert(save_ok(s)); + + (void)save_exec(s, "COMMIT", NULL); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/save.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,87 @@ +/* + * save.h -- save functions + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_SAVE_H +#define MLK_RPG_SAVE_H + +#include <time.h> + +#include <mlk/core/core.h> + +struct save { + time_t created; + time_t updated; + void *handle; +}; + +enum save_mode { + SAVE_MODE_READ, + SAVE_MODE_WRITE +}; + +struct save_stmt { + struct save *parent; + void *handle; +}; + +enum save_stmt_errno { + SAVE_STMT_DONE, + SAVE_STMT_ROW, + SAVE_STMT_ERROR +}; + +CORE_BEGIN_DECLS + +int +save_open(struct save *, unsigned int, enum save_mode); + +int +save_open_path(struct save *, const char *, enum save_mode); + +int +save_ok(const struct save *); + +int +save_exec(struct save *, const char *, const char *, ...); + +void +save_finish(struct save *); + +/* Prepared statements. */ +int +save_stmt_init(struct save_stmt *, struct save *, const char *, const char *, ...); + +enum save_stmt_errno +save_stmt_next(struct save_stmt *, const char *, ...); + +void +save_stmt_finish(struct save_stmt *); + +/* Explicit transactions. */ +int +save_tx_begin(struct save *); + +void +save_tx_rollback(struct save *); + +void +save_tx_commit(struct save *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_SAVE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/selection.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,68 @@ +/* + * selection.c -- kind of selection + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include <mlk/core/util.h> + +#include "battle.h" +#include "character.h" +#include "selection.h" + +static void +random(struct selection *slt, struct battle_entity **entities, size_t entitiesz) +{ + do { + slt->index_character = util_nrand(0, entitiesz); + } while (!battle_entity_ok(entities[slt->index_character])); +} + +static void +first(struct selection *slt, struct battle_entity **entities, size_t entitiesz) +{ + for (size_t i = 0; i < entitiesz; ++i) { + if (battle_entity_ok(entities[i])) { + slt->index_character = i; + break; + } + } +} + +void +selection_first(struct selection *slt, const struct battle *bt) +{ + assert(slt); + assert(bt); + + if (slt->index_side == 0) + first(slt, bt->enemies, bt->enemiesz); + else + first(slt, bt->team, bt->teamsz); +} + +void +selection_random(struct selection *slt, const struct battle *bt) +{ + assert(slt); + assert(bt); + + if (slt->index_side == 0) + random(slt, bt->enemies, bt->enemiesz); + else + random(slt, bt->team, bt->teamsz); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/selection.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,60 @@ +/* + * selection.h -- kind of selection + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_SELECTION_H +#define MLK_RPG_SELECTION_H + +#include <mlk/core/core.h> + +struct battle; + +enum selection_kind { + SELECTION_KIND_SELF, + SELECTION_KIND_ONE, + SELECTION_KIND_ALL, + SELECTION_KIND_BOTH +}; + +enum selection_side { + /* Which side allowed (can be both). */ + SELECTION_SIDE_TEAM = (1 << 0), + SELECTION_SIDE_ENEMY = (1 << 1) +}; + +struct selection { + enum selection_kind allowed_kinds; + enum selection_side allowed_sides; + + /* Character index in battle entity array. */ + unsigned int index_character; + + /* Side index (0 = enemy, 1 = team). */ + unsigned int index_side; +}; + +CORE_BEGIN_DECLS + +void +selection_first(struct selection *, const struct battle *); + +void +selection_random(struct selection *, const struct battle *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_SELECTION_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/spell.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,52 @@ +/* + * spell.c -- magic spells + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include "spell.h" + +void +spell_select(const struct spell *s, const struct battle *bt, struct selection *slt) +{ + assert(s && s->select); + assert(bt); + assert(slt); + + s->select(bt, slt); +} + +void +spell_action(const struct spell *s, struct battle *bt, struct character *owner, const struct selection *slt) +{ + assert(s && s->action); + assert(bt); + assert(owner); + assert(slt); + + s->action(bt, owner, slt); +} + +void +spell_use(struct spell *s, struct character *owner, const struct selection *slt) +{ + assert(s && s->use); + assert(owner); + assert(slt); + + s->use(owner, slt); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/spell.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,67 @@ +/* + * spell.h -- magic spells + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_SPELL_H +#define MLK_RPG_SPELL_H + +#include <mlk/core/core.h> + +#include "selection.h" + +struct character; +struct battle; +struct selection; + +enum spell_type { + SPELL_TYPE_NEUTRAL, + SPELL_TYPE_FIRE, + SPELL_TYPE_WIND, + SPELL_TYPE_WATER, + SPELL_TYPE_EARTH, + SPELL_TYPE_CHAOS, + SPELL_TYPE_HOLY, + SPELL_TYPE_TIME +}; + +struct spell { + const char *name; + const char *description; + unsigned int mp; + enum spell_type type; + enum selection_kind select_kind; + enum selection_side select_side; + + void (*select)(const struct battle *, struct selection *); + void (*action)(struct battle *, struct character *, const struct selection *); + void (*use)(struct character *, const struct selection *); +}; + +CORE_BEGIN_DECLS + +void +spell_select(const struct spell *, const struct battle *, struct selection *); + +void +spell_action(const struct spell *, struct battle *, struct character *, const struct selection *); + +void +spell_use(struct spell *, struct character *, const struct selection *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_SPELL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/team.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,20 @@ +/* + * team.c -- team storage + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Nothing yet. */ +enum { some_compiler_needs_more_than_nothing = 1 };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/team.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,30 @@ +/* + * team.h -- team storage + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_TEAM_H +#define MLK_RPG_TEAM_H + +#define TEAM_MEMBER_MAX (4) + +struct character; + +struct team { + struct character *members[TEAM_MEMBER_MAX]; +}; + +#endif /* MLK_RPG_TEAM_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/tileset-file.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,334 @@ +/* + * tileset-file.c -- tileset file loader + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <mlk/util/util.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/animation.h> +#include <mlk/core/error.h> +#include <mlk/core/image.h> +#include <mlk/core/util.h> + +#include "tileset-file.h" +#include "tileset.h" + +#define MAX_F(v) MAX_F_(v) +#define MAX_F_(v) "%" #v "[^\n|]" + +/* + * This is how memory for animations is allocated in the tileset_file + * structure. + * + * As animations require a texture and a sprite to be present, we need to store + * them locally in the tileset_file structure. + * + * tileset_file->anims[0] array (struct tileset_animation_block): + * + * [0] [1] [N] + * | texture | texture | texture + * | sprite | sprite | sprite + * | animation | animation | animation + * + * tileset_file->anims[1] array (struct tileset_animation): + * + * [0] [1] [N] + * | id | id | id + * | animation ^ | animation ^ | animation ^ + * + * The second array is the exposed array through the tileset->anims pointer, + * animations are referenced from the first array. This is because user may need + * or replace the tileset by itself and as such we need to keep track of the + * resource the tileset_file has allocated itself. + */ + +struct tileset_animation_block { + struct texture texture; + struct sprite sprite; + struct animation animation; +}; + +struct context { + struct tileset_file *tf; + struct tileset *tileset; + FILE *fp; + + char basedir[PATH_MAX]; + + /* + * The following properties aren't stored in the tileset because they + * are not needed after loading. + */ + unsigned int tilewidth; + unsigned int tileheight; + + /* Number of rows/columns in the image. */ + unsigned int nrows; + unsigned int ncolumns; +}; + +static void +tileset_animation_block_finish(void *data) +{ + struct tileset_animation_block *anim = data; + + texture_finish(&anim->texture); +} + +static int +tileset_tiledef_cmp(const void *d1, const void *d2) +{ + const struct tileset_tiledef *mtd1 = d1; + const struct tileset_tiledef *mtd2 = d2; + + if (mtd1->id < mtd2->id) + return -1; + if (mtd1->id > mtd2->id) + return 1; + + return 0; +} + +static int +tileset_animation_cmp(const void *d1, const void *d2) +{ + const struct tileset_animation *mtd1 = d1; + const struct tileset_animation *mtd2 = d2; + + if (mtd1->id < mtd2->id) + return -1; + if (mtd1->id > mtd2->id) + return 1; + + return 0; +} + +static int +parse_tilewidth(struct context *ctx, const char *line) +{ + if (sscanf(line, "tilewidth|%u", &ctx->tilewidth) != 1 || ctx->tilewidth == 0) + return errorf("tilewidth is null"); + + return 0; +} + +static int +parse_tileheight(struct context *ctx, const char *line) +{ + if (sscanf(line, "tileheight|%u", &ctx->tileheight) != 1 || ctx->tileheight == 0) + return errorf("tileheight is null"); + + return 0; +} + +static int +parse_tiledefs(struct context *ctx, const char *line) +{ + (void)line; + + short x, y; + unsigned short id, w, h; + struct tileset_tiledef *td; + + alloc_pool_init(&ctx->tf->tiledefs, sizeof (*td), NULL); + + while (fscanf(ctx->fp, "%hu|%hd|%hd|%hu|%hu\n", &id, &x, &y, &w, &h) == 5) { + td = alloc_pool_new(&ctx->tf->tiledefs); + td->id = id; + td->x = x; + td->y = y; + td->w = w; + td->h = h; + } + + /* Sort the array and expose it through the tileset->tiledefs pointer. */ + qsort(ctx->tf->tiledefs.data, ctx->tf->tiledefs.size, ctx->tf->tiledefs.elemsize, tileset_tiledef_cmp); + ctx->tileset->tiledefs = ctx->tf->tiledefs.data; + ctx->tileset->tiledefsz = ctx->tf->tiledefs.size; + + return 0; +} + +static int +parse_animations(struct context *ctx, const char *line) +{ + (void)line; + + unsigned short id; + unsigned int delay; + char filename[FILENAME_MAX + 1]; + struct tileset_animation_block *anim; + + alloc_pool_init(&ctx->tf->anims[0], sizeof (struct tileset_animation_block), tileset_animation_block_finish); + alloc_pool_init(&ctx->tf->anims[1], sizeof (struct tileset_animation), NULL); + + /* + * 1. Create the first array of animation, sprite and texture that are + * owned by the tileset_file structure. + */ + while (fscanf(ctx->fp, "%hu|" MAX_F(FILENAME_MAX) "|%u", &id, filename, &delay) == 3) { + anim = alloc_pool_new(&ctx->tf->anims[0]); + + if (image_open(&anim->texture, util_pathf("%s/%s", ctx->basedir, filename)) < 0) + return -1; + + sprite_init(&anim->sprite, &anim->texture, ctx->tilewidth, ctx->tileheight); + animation_init(&anim->animation, &anim->sprite, delay); + } + + /* + * 2. Create the second array that only consist of pointers to + * animations referencing the first array. + */ + for (size_t i = 0; i < ctx->tf->anims[0].size; ++i) { + struct tileset_animation_block *anim = alloc_pool_get(&ctx->tf->anims[0], i); + struct tileset_animation *ta; + + if (!(ta = alloc_pool_new(&ctx->tf->anims[1]))) + return -1; + + ta->id = id; + ta->animation = &anim->animation; + } + + /* + * 3. Finally expose the second array through the tileset->anims pointer + * and sort it. + */ + qsort(ctx->tf->anims[1].data, ctx->tf->anims[1].size, ctx->tf->anims[1].elemsize, tileset_animation_cmp); + ctx->tileset->anims = ctx->tf->anims[1].data; + ctx->tileset->animsz = ctx->tf->anims[1].size; + + return 0; +} + +static int +parse_image(struct context *ctx, const char *line) +{ + char *p; + + if (ctx->tilewidth == 0 || ctx->tileheight == 0) + return errorf("missing tile dimensions before image"); + if (!(p = strchr(line, '|'))) + return errorf("could not parse image"); + + if (image_open(&ctx->tf->image, util_pathf("%s/%s", ctx->basedir, p + 1)) < 0) + return -1; + + sprite_init(&ctx->tf->sprite, &ctx->tf->image, ctx->tilewidth, ctx->tileheight); + ctx->tileset->sprite = &ctx->tf->sprite; + + return 0; +} + +static int +parse_line(struct context *ctx, const char *line) +{ + static const struct { + const char *property; + int (*read)(struct context *, const char *); + } props[] = { + { "tilewidth", parse_tilewidth }, + { "tileheight", parse_tileheight }, + { "tiledefs", parse_tiledefs }, + { "animations", parse_animations }, + { "image", parse_image } + }; + + for (size_t i = 0; i < UTIL_SIZE(props); ++i) { + if (strncmp(line, props[i].property, strlen(props[i].property)) == 0) + return props[i].read(ctx, line); + } + + return 0; +} + +static int +parse(struct context *ctx, const char *path) +{ + char line[1024]; + char basedir[PATH_MAX]; + + util_strlcpy(basedir, path, sizeof (basedir)); + util_strlcpy(ctx->basedir, util_dirname(basedir), sizeof (ctx->basedir)); + + while (fgets(line, sizeof (line), ctx->fp)) { + /* Remove \n if any */ + line[strcspn(line, "\r\n")] = '\0'; + + if (parse_line(ctx, line) < 0) + return -1; + } + + return 0; +} + +static int +check(const struct tileset *tileset) +{ + if (!tileset->sprite) + return errorf("missing tileset image"); + + return 0; +} + +int +tileset_file_open(struct tileset_file *tf, struct tileset *tileset, const char *path) +{ + assert(tf); + assert(tileset); + assert(path); + + struct context ctx = { + .tf = tf, + .tileset = tileset + }; + int ret = 0; + + memset(tileset, 0, sizeof (*tileset)); + + if (!(ctx.fp = fopen(path, "r"))) + return -1; + if ((ret = parse(&ctx, path)) < 0 || (ret = check(tileset)) < 0) + tileset_file_finish(tf); + + fclose(ctx.fp); + + return ret; +} + +void +tileset_file_finish(struct tileset_file *tf) +{ + assert(tf); + + alloc_pool_finish(&tf->tiledefs); + alloc_pool_finish(&tf->anims[0]); + alloc_pool_finish(&tf->anims[1]); + + texture_finish(&tf->image); + + memset(tf, 0, sizeof (*tf)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/tileset-file.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,49 @@ +/* + * tileset-file.h -- tileset file loader + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_TILESET_FILE_H +#define MLK_RPG_TILESET_FILE_H + +#include <stddef.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/core.h> +#include <mlk/core/sprite.h> +#include <mlk/core/texture.h> + +struct tileset; +struct tileset_tiledef; + +struct tileset_file { + struct alloc_pool tiledefs; + struct alloc_pool anims[2]; + struct texture image; + struct sprite sprite; +}; + +CORE_BEGIN_DECLS + +int +tileset_file_open(struct tileset_file *, struct tileset *, const char *); + +void +tileset_file_finish(struct tileset_file *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_TILESET_FILE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/tileset.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,93 @@ +/* + * tileset.c -- map tileset definition + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> + +#include <mlk/core/animation.h> +#include <mlk/core/sprite.h> + +#include "tileset.h" + +static inline int +anim_cmp(const void *d1, const void *d2) +{ + const struct tileset_animation *mtd1 = d1; + const struct tileset_animation *mtd2 = d2; + + if (mtd1->id < mtd2->id) + return -1; + if (mtd1->id > mtd2->id) + return 1; + + return 0; +} + +static inline const struct tileset_animation * +find(const struct tileset *ts, unsigned int r, unsigned int c) +{ + const struct tileset_animation key = { + .id = c + (r * ts->sprite->ncols) + }; + + return bsearch(&key, ts->anims, ts->animsz, sizeof (key), anim_cmp); +} + +int +tileset_ok(const struct tileset *ts) +{ + return ts && sprite_ok(ts->sprite); +} + +void +tileset_start(struct tileset *ts) +{ + for (size_t i = 0; i < ts->animsz; ++i) { + struct tileset_animation *ta = &ts->anims[i]; + + if (ta->animation) + animation_start(ta->animation); + } +} + +void +tileset_update(struct tileset *ts, unsigned int ticks) +{ + for (size_t i = 0; i < ts->animsz; ++i) { + struct tileset_animation *ta = &ts->anims[i]; + + if (!ta->animation) + continue; + + if (animation_update(ta->animation, ticks)) + animation_start(ta->animation); + } +} + +void +tileset_draw(const struct tileset *ts, unsigned int r, unsigned int c, int x, int y) +{ + assert(ts); + + const struct tileset_animation *ta; + + if ((ta = find(ts, r, c))) + animation_draw(ta->animation, x, y); + else + sprite_draw(ts->sprite, r, c, x, y); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/tileset.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,65 @@ +/* + * tileset.h -- map tileset definition + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_TILESET_H +#define MLK_RPG_TILESET_H + +#include <stddef.h> + +#include <mlk/core/core.h> + +struct sprite; + +struct tileset_tiledef { + unsigned short id; + short x; + short y; + unsigned short w; + unsigned short h; +}; + +struct tileset_animation { + unsigned short id; + struct animation *animation; +}; + +struct tileset { + struct tileset_tiledef *tiledefs; + size_t tiledefsz; + struct tileset_animation *anims; + size_t animsz; + struct sprite *sprite; +}; + +CORE_BEGIN_DECLS + +int +tileset_ok(const struct tileset *); + +void +tileset_start(struct tileset *); + +void +tileset_update(struct tileset *, unsigned int); + +void +tileset_draw(const struct tileset *, unsigned int, unsigned int, int, int); + +CORE_END_DECLS + +#endif /* !MLK_RPG_TILESET_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/walksprite.c Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,69 @@ +/* + * walksprite.c -- sprite designed for walking entities + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <string.h> + +#include <mlk/core/sprite.h> + +#include "walksprite.h" + +void +walksprite_init(struct walksprite *ws, struct sprite *sprite, unsigned int delay) +{ + assert(ws); + assert(sprite); + + memset(ws, 0, sizeof (*ws)); + ws->sprite = sprite; + ws->delay = delay; +} + +void +walksprite_reset(struct walksprite *ws) +{ + assert(ws); + + ws->index = 0; +} + +void +walksprite_update(struct walksprite *ws, unsigned int ticks) +{ + assert(ws); + + ws->elapsed += ticks; + + if (ws->elapsed >= ws->delay) { + ws->index += 1; + + if (ws->index >= ws->sprite->ncols) + ws->index = 0; + + ws->elapsed = 0; + } +} + +void +walksprite_draw(const struct walksprite *ws, unsigned int orientation, int x, int y) +{ + assert(ws); + assert(orientation < 8); + + sprite_draw(ws->sprite, orientation, ws->index, x, y); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/walksprite.h Sat Oct 15 21:24:17 2022 +0200 @@ -0,0 +1,79 @@ +/* + * walksprite.h -- sprite designed for walking entities + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_WALKSPRITE_H +#define MLK_RPG_WALKSPRITE_H + +#include <mlk/core/core.h> + +struct sprite; + +/** + * \brief Sprite designed for walking entities. + * + * This structure works with sprite images that are defined as using the + * following conventions: + * + * ``` + * 7 0 1 + * ↖ ↑ ↗ + * 6 ← → 2 + * ↙ ↓ ↘ + * 5 4 3 + * ``` + * + * Where numbers define row in the sprite according to the character + * orientation. In other terms, your image sprite should look like this: + * + * ``` + * row columns in your image + * ---|--------------------- + * 0 | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ + * 1 | ↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗ + * 2 | →→→→→→→→→→→→→→→→→→→→ + * 3 | ↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘ + * 4 | ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ + * 5 | ↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙ + * 6 | ←←←←←←←←←←←←←←←←←←←← + * 7 | ↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖ + * ``` + */ +struct walksprite { + struct sprite *sprite; + unsigned int delay; + unsigned int index; + unsigned int elapsed; +}; + +CORE_BEGIN_DECLS + +void +walksprite_init(struct walksprite *, struct sprite *, unsigned int); + +void +walksprite_reset(struct walksprite *); + +void +walksprite_update(struct walksprite *, unsigned int); + +void +walksprite_draw(const struct walksprite *, unsigned int, int, int); + +CORE_END_DECLS + +#endif /* !MLK_RPG_WALKSPRITE_H */
--- a/src/libmlk-rpg/assets/sql/character-load.sql Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ --- --- character-load.sql -- load a character data --- --- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -SELECT hp - , mp - , level - , team_order - , bonus_hp - , bonus_mp - , bonus_atk - , bonus_def - , bonus_agt - , bonus_luck - FROM character - WHERE name = ?
--- a/src/libmlk-rpg/assets/sql/character-save.sql Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ --- --- character-save.sql -- save or replace character --- --- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -INSERT OR REPLACE INTO character( - name, - hp, - mp, - level, - team_order, - bonus_hp, - bonus_mp, - bonus_atk, - bonus_def, - bonus_agt, - bonus_luck -) -VALUES( - ?, - ?, - ?, - ?, - ?, - ?, - ?, - ?, - ?, - ?, - ? -)
--- a/src/libmlk-rpg/assets/sql/init.sql Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ --- --- init.sql -- initialize database --- --- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -BEGIN EXCLUSIVE TRANSACTION; - -CREATE TABLE IF NOT EXISTS property( - id INTEGER PRIMARY KEY AUTOINCREMENT, - key TEXT NOT NULL UNIQUE, - value TEXT NOT NULL -); - -CREATE TABLE IF NOT EXISTS character( - name TEXT PRIMARY KEY, - hp INTEGER NOT NULL, - mp INTEGER NOT NULL, - level INTEGER NOT NULL, - team_order INTEGER DEFAULT -1, - bonus_hp INTEGER DEFAULT 0, - bonus_mp INTEGER DEFAULT 0, - bonus_atk INTEGER DEFAULT 0, - bonus_def INTEGER DEFAULT 0, - bonus_agt INTEGER DEFAULT 0, - bonus_luck INTEGER DEFAULT 0 -); - -CREATE TABLE IF NOT EXISTS quest( - name TEXT PRIMARY KEY -); - -CREATE TABLE IF NOT EXISTS quest_step( - name TEXT PRIMARY KEY, - percent INTEGER DEFAULT 0, - quest_name TEXT NOT NULL, - FOREIGN KEY(quest_name) REFERENCES quest(name) -); - -INSERT OR IGNORE INTO property(key, value) VALUES ('molko.create-date', strftime('%s','now')); -INSERT OR IGNORE INTO property(key, value) VALUES ('molko.update-date', strftime('%s','now')); - -COMMIT;
--- a/src/libmlk-rpg/assets/sql/property-load.sql Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ --- --- property-load.sql -- get a property --- --- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -SELECT value - FROM property - WHERE key = ?
--- a/src/libmlk-rpg/assets/sql/property-remove.sql Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ --- --- property-remove.sql -- remove a property --- --- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -DELETE - FROM property - WHERE key = ?
--- a/src/libmlk-rpg/assets/sql/property-save.sql Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ --- --- property-save.sql -- set a property --- --- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -INSERT OR REPLACE INTO property( - key, - value -) -VALUES( - ?, - ? -)
--- a/src/libmlk-rpg/assets/sql/quest-remove.sql Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ --- --- quest-remove.sql -- remove a quest entirely --- --- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -DELETE - FROM quest - WHERE name = ?
--- a/src/libmlk-rpg/assets/sql/quest-save.sql Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ --- --- quest-save.sql -- create parent quest entry --- --- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -INSERT INTO quest( - name -) -VALUES( - ? -)
--- a/src/libmlk-rpg/assets/sql/quest-step-load.sql Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ --- --- quest-step-load.sql -- remove a quest entirely --- --- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -SELECT percent - FROM quest_step - WHERE name = ?
--- a/src/libmlk-rpg/assets/sql/quest-step-save.sql Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ --- --- quest-step-save.sql -- save a quest step --- --- Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -INSERT INTO quest_step( - quest_name, - name, - percent -) VALUES( - ?, - ?, - ? -)
--- a/src/libmlk-rpg/rpg/battle-bar-default.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,693 +0,0 @@ -/* - * battle-bar-default.c -- default battle status bar and menu implementation - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/event.h> -#include <mlk/core/font.h> -#include <mlk/core/sprite.h> -#include <mlk/core/trace.h> -#include <mlk/core/util.h> -#include <mlk/core/window.h> - -#include <mlk/ui/align.h> -#include <mlk/ui/theme.h> - -#include "battle-bar-default.h" -#include "battle-bar.h" -#include "battle-state-item.h" -#include "battle-state-selection.h" -#include "battle.h" -#include "character.h" -#include "inventory.h" -#include "item.h" -#include "spell.h" - -#define THEME(bar) ((bar)->theme ? (bar)->theme : theme_default()) - -struct geo { - int x, y; - unsigned int w, h; -}; - -static inline void -dimensions(struct geo geo[2], const struct battle_bar_default *bar) -{ - /* 0 == main menu */ - geo[0].w = bar->w * 0.2; - geo[0].h = bar->h; - geo[0].x = bar->x + (bar->w / 2) - (geo[0].w / 2); - geo[0].y = window.h - bar->h; - - /* 1 == status frame */ - geo[1].x = geo[0].x + geo[0].w; - geo[1].y = geo[0].y; - geo[1].w = (bar->w - geo[0].w) / 2; - geo[1].h = bar->h; -} - -/* - * The following validate_* functions are called when the user has validated a - * selection depending on the current menu (e.g. Magic, Items). - * - * They change the battle state to the appropriate one. - */ - -static void -validate_attack(struct battle_bar_default *bar, struct battle *bt, const struct selection *sel) -{ - (void)bar; - - struct character *target; - - if (sel->index_side == 0) - target = bt->enemies[sel->index_character]->ch; - else - target = bt->team[sel->index_character]->ch; - - battle_attack(bt, battle_current(bt)->ch, target); -} - -static void -validate_magic(struct battle_bar_default *bar, struct battle *bt, const struct selection *sel) -{ - struct character *source = battle_current(bt)->ch; - const struct spell *spell = source->spells[bar->grid.selected]; - - battle_cast(bt, source, spell, sel); -} - -static void -validate_item(struct battle_bar_default *bar, struct battle *bt, const struct selection *sel) -{ - struct inventory_slot *slot; - struct battle_entity *source, *target; - - if (bar->grid.selected >= INVENTORY_ITEM_MAX) - return; - if (!(slot = &bt->inventory->items[bar->grid.selected])) - return; - - source = battle_current(bt); - target = sel->index_side == 0 - ? bt->enemies[sel->index_character] - : bt->team[sel->index_character]; - - /* TODO: battle_use? */ - battle_state_item(bt, source, target, slot); -} - -/* - * The following functions are used to switch to the battle selection state - * using the appropriate selector algorithm. For example, an item can only be - * used on a unique target while a spell can have multiple choices. - */ - -static void -switch_selection_attack(struct battle_bar_default *bar, struct battle *bt) -{ - struct selection sel = { - .allowed_kinds = SELECTION_KIND_ONE, - .allowed_sides = SELECTION_SIDE_ENEMY, - .index_side = 0 - }; - - /* Disable handling anymore. */ - bar->state = BATTLE_BAR_DEFAULT_STATE_NONE; - - selection_first(&sel, bt); - battle_state_selection(bt, &sel); -} - -static void -switch_selection_spell(struct battle_bar_default *bar, struct battle *bt) -{ - const struct character *ch = battle_current(bt)->ch; - const struct spell *sp = ch->spells[bar->grid.selected]; - struct selection sel = {0}; - - if (bar->grid.selected > CHARACTER_SPELL_MAX) - return; - if (!(sp = ch->spells[bar->grid.selected]) || sp->mp > (unsigned int)ch->mp) - return; - - /* Use the spell selection algorithm to fill default values. */ - spell_select(sp, bt, &sel); - battle_state_selection(bt, &sel); - - /* A cursor should be present. */ - if (!sprite_ok(BATTLE_THEME(bt)->sprites[THEME_SPRITE_CURSOR])) - tracef("battle: no cursor sprite in theme"); -} - -static void -switch_selection_item(struct battle *bt) -{ - const struct selection slt = { - .allowed_kinds = SELECTION_KIND_ONE, - .allowed_sides = SELECTION_SIDE_TEAM | SELECTION_SIDE_ENEMY, - .index_side = 1, - .index_character = battle_index(bt) - }; - - battle_state_selection(bt, &slt); -} - -/* - * The following functions actually draw the bar and their components depending - * on the current selected menu. - */ - -static void -draw_help(const struct battle_bar_default *bar, const char *what) -{ - struct label label = {0}; - unsigned int lw = 0, lh = 0; - - label.flags = LABEL_FLAGS_SHADOW; - label.text = what; - label_query(&label, &lw, &lh); - label.x = bar->grid.x + (bar->grid.w / 2) - (lw / 2); - label.y = bar->grid.y - lh - THEME(bar)->padding; - label_draw(&label); -} - -static void -draw_spell_help(const struct battle_bar_default *bar, const struct battle *bt) -{ - const struct character *ch = battle_current(bt)->ch; - const struct spell *sp; - - if (bar->grid.selected >= CHARACTER_SPELL_MAX) - return; - if (!(sp = ch->spells[bar->grid.selected])) - return; - - draw_help(bar, sp->description); -} - -static void -draw_item_help(const struct battle_bar_default *bar, const struct battle *bt) -{ - const struct inventory_slot *slot; - - if (bar->grid.selected >= INVENTORY_ITEM_MAX) - return; - - slot = &bt->inventory->items[bar->grid.selected]; - - if (!slot->item) - return; - - draw_help(bar, slot->item->description); -} - -static void -draw_status_character_stats(const struct battle_bar_default *bar, - const struct character *ch, - int x, - int y, - unsigned int h) -{ - const struct theme *theme = THEME(bar); - struct label label; - unsigned int spacing, lw, lh; - char line[64]; - - /* Compute spacing between elements. */ - spacing = h - (font_height(theme->fonts[THEME_FONT_INTERFACE]) * 3); - spacing /= 4; - - /* Reuse the same label. */ - label.theme = theme; - label.text = line; - label.flags = LABEL_FLAGS_SHADOW; - - /* Name. */ - snprintf(line, sizeof (line), "%s", ch->name); - label_query(&label, &lw, &lh); - label.x = x + theme->padding; - label.y = y + spacing; - label_draw(&label); - - /* HP. */ - snprintf(line, sizeof (line), "%d/%u", ch->hp, ch->hpmax); - label_query(&label, &lw, &lh); - label.x = x + theme->padding; - label.y = label.y + lh + spacing; - label_draw(&label); - - /* MP. */ - snprintf(line, sizeof (line), "%d/%u", ch->mp, ch->mpmax); - label_query(&label, &lw, &lh); - label.x = x + theme->padding; - label.y = label.y + lh + spacing; - label_draw(&label); - - /* Status. */ - /* TODO: list all status. */ -} - -static void -draw_status_character(const struct battle_bar_default *bar, - const struct battle *bt, - const struct character *ch, - const struct geo *geo, - unsigned int index) -{ - int x, y; - unsigned int w, h; - - /* Compute bounding box for rendering. */ - w = geo->w / bt->teamsz; - h = geo->h; - x = geo->x + (index * w); - y = geo->y; - - draw_status_character_stats(bar, ch, x, y, h); -} - -static void -draw_status_characters(const struct battle_bar_default *bar, - const struct battle *bt, - const struct geo *geo) -{ - const struct battle_entity *et; - unsigned int index = 0; - - BATTLE_TEAM_FOREACH(bt, et) { - if (character_ok(et->ch)) - draw_status_character(bar, bt, et->ch, geo, index); - - ++index; - } -} - -static void -draw_status(const struct battle_bar_default *bar, const struct battle *bt, const struct geo *geo) -{ - frame_draw(&(const struct frame) { - .x = geo->x, - .y = geo->y, - .w = geo->w, - .h = geo->h - }); - - draw_status_characters(bar, bt, geo); -} - -static void -draw_menu(const struct battle_bar_default *bar, const struct geo *geo) -{ - struct { - unsigned int w, h; - enum align align; - struct label label; - } buttons[] = { - { - .align = ALIGN_TOP, - .label = { - .text = "Attack", - .flags = LABEL_FLAGS_SHADOW - } - }, - { - .align = ALIGN_RIGHT, - .label = { - .text = "Magic", - .flags = LABEL_FLAGS_SHADOW - } - }, - { - .align = ALIGN_BOTTOM, - .label = { - .text = "Objects", - .flags = LABEL_FLAGS_SHADOW - } - }, - { - .align = ALIGN_LEFT, - .label = { - .text = "Special", - .flags = LABEL_FLAGS_SHADOW - } - } - }; - - const struct theme *theme = THEME(bar); - int bx, by; - unsigned int bw, bh; - - /* Compute bounding box with margins removed. */ - bx = geo->x + theme->padding; - by = geo->y + theme->padding; - bw = geo->w - theme->padding * 2; - bh = geo->h - theme->padding * 2; - - /* Draw menu frame. */ - frame_draw(&(const struct frame) { - .x = geo->x, - .y = geo->y, - .w = geo->w, - .h = geo->h - }); - - for (size_t i = 0; i < UTIL_SIZE(buttons); ++i) { - buttons[i].label.theme = theme; - - label_query(&buttons[i].label, &buttons[i].w, &buttons[i].h); - - /* Change theme if it's selected. */ - if ((size_t)bar->menu == i) - buttons[i].label.flags |= LABEL_FLAGS_SELECTED; - else - buttons[i].label.flags &= ~LABEL_FLAGS_SELECTED; - - align(buttons[i].align, - &buttons[i].label.x, &buttons[i].label.y, buttons[i].w, buttons[i].h, - bx, by, bw, bh); - label_draw(&buttons[i].label); - } -} - -/* - * This function is called only in the first level of the bar menu: selecting - * one of the Attack, Magic, Item and Special items. - */ -static void -handle_keydown_menu(struct battle_bar_default *bar, struct battle *bt, const union event *ev) -{ - (void)bt; - - switch (ev->key.key) { - case KEY_UP: - bar->menu = BATTLE_BAR_DEFAULT_MENU_ATTACK; - break; - case KEY_RIGHT: - bar->menu = BATTLE_BAR_DEFAULT_MENU_MAGIC; - break; - case KEY_DOWN: - bar->menu = BATTLE_BAR_DEFAULT_MENU_ITEM; - break; - case KEY_LEFT: - bar->menu = BATTLE_BAR_DEFAULT_MENU_SPECIAL; - break; - case KEY_ENTER: - /* - * At this step, attack does not require opening the sub menu so - * we change selection state immediately if needed. - */ - switch (bar->menu) { - case BATTLE_BAR_DEFAULT_MENU_ATTACK: - switch_selection_attack(bar, bt); - break; - case BATTLE_BAR_DEFAULT_MENU_ITEM: - battle_bar_default_open_item(bar, bt); - break; - case BATTLE_BAR_DEFAULT_MENU_MAGIC: - battle_bar_default_open_magic(bar, bt, battle_current(bt)->ch); - break; - default: - break; - } - break; - default: - break; - } -} - -/* - * This function is called when we're selecting a submenu entry from Items - * and Magic. - */ -static void -handle_keydown_grid(struct battle_bar_default *bar, struct battle *bt, const union event *ev) -{ - /* Go back to main menu if I press escape. */ - if (ev->key.key == KEY_ESCAPE) - bar->state = BATTLE_BAR_DEFAULT_STATE_MENU; - else if (gridmenu_handle(&bar->grid, ev)) { - switch (bar->menu) { - case BATTLE_BAR_DEFAULT_MENU_MAGIC: - switch_selection_spell(bar, bt); - break; - case BATTLE_BAR_DEFAULT_MENU_ITEM: - switch_selection_item(bt); - break; - default: - break; - } - } -} - -static void -handle_keydown(struct battle_bar_default *bar, struct battle *bt, const union event *ev) -{ - assert(ev->type == EVENT_KEYDOWN); - - static void (*handlers[])(struct battle_bar_default *, struct battle *, const union event *) = { - [BATTLE_BAR_DEFAULT_STATE_MENU] = handle_keydown_menu, - [BATTLE_BAR_DEFAULT_STATE_GRID] = handle_keydown_grid - }; - - if (handlers[bar->state]) - handlers[bar->state](bar, bt, ev); -} - -#if 0 - -static void -handle_clickdown(struct battle_bar_default *bar, struct battle *bt, const union event *ev) -{ - assert(ev->type == EVENT_CLICKDOWN); - - (void)bar; - (void)bt; - - switch (bar->state) { - case BATTLE_BAR_DEFAULT_STATE_MENU: - /* We are selecting a main menu entry. */ - /* TODO: implement click here too. */ - break; - case BATTLE_BAR_DEFAULT_STATE_SUB: - /* We are in the sub menu (objects/spells). */ - if (bar->sub_grid.state == GRIDMENU_STATE_ACTIVATED) - default: - break; - } - - return 0; -} - -#endif - -static void -self_start(struct battle_bar *bar, struct battle *bt) -{ - (void)bt; - - battle_bar_default_start(bar->data); -} - -static void -self_select(struct battle_bar *bar, struct battle *bt, const struct selection *sel) -{ - battle_bar_default_select(bar->data, bt, sel); -} - -static void -self_handle(struct battle_bar *bar, struct battle *bt, const union event *ev) -{ - battle_bar_default_handle(bar->data, bt, ev); -} - -static void -self_draw(const struct battle_bar *bar, const struct battle *bt) -{ - battle_bar_default_draw(bar->data, bt); -} - -void -battle_bar_default_init(struct battle_bar_default *bar) -{ - assert(bar); - - struct geo geo[2]; - - memset(bar, 0, sizeof (*bar)); - - bar->w = window.w; - bar->h = window.h * 0.12; - bar->x = 0; - bar->y = window.h - bar->h; - - dimensions(geo, bar); - - gridmenu_init(&bar->grid, 2, 2, NULL, 0); - gridmenu_resize(&bar->grid, bar->x, geo[0].y, geo[1].w, bar->h); - bar->grid.theme = bar->theme; -} - -void -battle_bar_default_open_magic(struct battle_bar_default *bar, const struct battle *bt, struct character *ch) -{ - assert(bar); - assert(bt); - assert(ch); - - (void)bt; - - bar->items = alloc_rearray0(bar->items, bar->itemsz, - CHARACTER_SPELL_MAX, sizeof (*bar->items)); - bar->itemsz = CHARACTER_SPELL_MAX; - bar->state = BATTLE_BAR_DEFAULT_STATE_GRID; - - for (size_t i = 0; i < CHARACTER_SPELL_MAX; ++i) - if (ch->spells[i]) - bar->items[i] = ch->spells[i]->name; - - bar->grid.items = bar->items; - bar->grid.itemsz = bar->itemsz; -} - -void -battle_bar_default_open_item(struct battle_bar_default *bar, const struct battle *bt) -{ - assert(bar); - assert(bt); - - /* TODO: not implemented yet. */ - (void)bar; - (void)bt; -#if 0 - for (size_t i = 0; i < INVENTORY_ITEM_MAX; ++i) { - if (bt->inventory->items[i].item) { - snprintf(bar->sub_items[i], sizeof (bar->sub_items[i]), "%-16s %u", - bt->inventory->items[i].item->name, bt->inventory->items[i].amount); - bar->sub_grid.menu[i] = bar->sub_items[i]; - } - } - - bar->state = BATTLE_BAR_DEFAULT_STATE_GRID; -#endif -} - -void -battle_bar_default_start(struct battle_bar_default *bar) -{ - assert(bar); - - bar->menu = BATTLE_BAR_DEFAULT_MENU_ATTACK; - bar->state = BATTLE_BAR_DEFAULT_STATE_MENU; -} - -/* - * Apply the battle selection for the current menu item. This function is called - * from the battle-state-selection state when the user validated the selection. - */ -void -battle_bar_default_select(struct battle_bar_default *bar, struct battle *bt, const struct selection *sel) -{ - assert(bar); - assert(bt); - assert(sel); - - static void (*validate[])(struct battle_bar_default *, struct battle *, const struct selection *) = { - [BATTLE_BAR_DEFAULT_MENU_ATTACK] = validate_attack, - [BATTLE_BAR_DEFAULT_MENU_ITEM] = validate_item, - [BATTLE_BAR_DEFAULT_MENU_MAGIC] = validate_magic, - [BATTLE_BAR_DEFAULT_MENU_SPECIAL] = NULL - }; - - if (validate[bar->menu]) - validate[bar->menu](bar, bt, sel); -} - -void -battle_bar_default_handle(struct battle_bar_default *bar, struct battle *bt, const union event *ev) -{ - assert(bar); - assert(bt); - assert(ev); - - static void (*handlers[])(struct battle_bar_default *, struct battle *, const union event *) = { - [EVENT_KEYDOWN] = handle_keydown, - [EVENT_NUM] = NULL - }; - - if (handlers[ev->type]) - handlers[ev->type](bar, bt, ev); -} - -void -battle_bar_default_draw(const struct battle_bar_default *bar, const struct battle *bt) -{ - assert(bar); - assert(bt); - - struct geo geo[2]; - - dimensions(geo, bar); - draw_menu(bar, &geo[0]); - draw_status(bar, bt, &geo[1]); - - if (bar->state == BATTLE_BAR_DEFAULT_STATE_GRID) { - switch (bar->menu) { - case BATTLE_BAR_DEFAULT_MENU_MAGIC: - draw_spell_help(bar, bt); - break; - case BATTLE_BAR_DEFAULT_MENU_ITEM: - draw_item_help(bar, bt); - break; - default: - break; - } - } - - /* Sub menu is only shown if state is set to it. */ - if (bar->state == BATTLE_BAR_DEFAULT_STATE_GRID) - gridmenu_draw(&bar->grid); -} - -void -battle_bar_default_finish(struct battle_bar_default *bar) -{ - assert(bar); - - free(bar->items); - memset(bar, 0, sizeof (*bar)); -} - -void -battle_bar_default(struct battle_bar_default *self, struct battle_bar *bar) -{ - assert(self); - assert(bar); - - memset(bar, 0, sizeof (*bar)); - - bar->data = self; - bar->start = self_start; - bar->select = self_select; - bar->handle = self_handle; - bar->draw = self_draw; -}
--- a/src/libmlk-rpg/rpg/battle-bar-default.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * battle-bar-default.h -- default battle status bar and menu implementation - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_BAR_DEFAULT_H -#define MLK_RPG_BATTLE_BAR_DEFAULT_H - -#include <mlk/core/core.h> - -#include <mlk/ui/gridmenu.h> - -struct battle; -struct battle_bar; -struct character; -struct selection; -struct theme; - -union event; - -enum battle_bar_default_menu { - BATTLE_BAR_DEFAULT_MENU_ATTACK, - BATTLE_BAR_DEFAULT_MENU_MAGIC, - BATTLE_BAR_DEFAULT_MENU_ITEM, - BATTLE_BAR_DEFAULT_MENU_SPECIAL -}; - -enum battle_bar_default_state { - BATTLE_BAR_DEFAULT_STATE_NONE, - BATTLE_BAR_DEFAULT_STATE_MENU, - BATTLE_BAR_DEFAULT_STATE_GRID -}; - -struct battle_bar_default { - int x; - int y; - unsigned int w; - unsigned int h; - struct theme *theme; - enum battle_bar_default_state state; - enum battle_bar_default_menu menu; - - /* Private fields. */ - const char **items; - size_t itemsz; - struct gridmenu grid; -}; - -CORE_BEGIN_DECLS - -void -battle_bar_default_init(struct battle_bar_default *); - -void -battle_bar_default_open_magic(struct battle_bar_default *, const struct battle *, struct character *); - -void -battle_bar_default_open_item(struct battle_bar_default *, const struct battle *); - -void -battle_bar_default_start(struct battle_bar_default *); - -void -battle_bar_default_select(struct battle_bar_default *, struct battle *, const struct selection *); - -void -battle_bar_default_handle(struct battle_bar_default *, struct battle *, const union event *); - -void -battle_bar_default_draw(const struct battle_bar_default *, const struct battle *); - -void -battle_bar_default_finish(struct battle_bar_default *); - -void -battle_bar_default(struct battle_bar_default *, struct battle_bar *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_BATTLE_BAR_DEFAULT_H */
--- a/src/libmlk-rpg/rpg/battle-bar.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * battle-bar.c -- abstract battle bar - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include "battle-bar.h" - -void -battle_bar_start(struct battle_bar *bar, struct battle *bt) -{ - assert(bar); - assert(bt); - - if (bar->start) - bar->start(bar, bt); -} - -void -battle_bar_select(struct battle_bar *bar, struct battle *bt, const struct selection *sel) -{ - assert(bar); - assert(bt); - assert(sel); - - if (bar->select) - bar->select(bar, bt, sel); - -} - -void -battle_bar_handle(struct battle_bar *bar, struct battle *bt, const union event *ev) -{ - assert(bar); - assert(bt); - assert(ev); - - if (bar->handle) - bar->handle(bar, bt, ev); -} - -void -battle_bar_update(struct battle_bar *bar, struct battle *bt, unsigned int ticks) -{ - assert(bar); - assert(bt); - - if (bar->update) - bar->update(bar, bt, ticks); -} - -void -battle_bar_draw(const struct battle_bar *bar, const struct battle *bt) -{ - assert(bar); - assert(bt); - - if (bar->draw) - bar->draw(bar, bt); -} - -void -battle_bar_finish(struct battle_bar *bar, struct battle *bt) -{ - assert(bar); - assert(bt); - - if (bar->finish) - bar->finish(bar, bt); -}
--- a/src/libmlk-rpg/rpg/battle-bar.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * battle-bar.h -- abstract battle bar - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_BAR_H -#define MLK_RPG_BATTLE_BAR_H - -#include <mlk/core/core.h> - -struct battle; -struct selection; - -union event; - -struct battle_bar { - void *data; - void (*start)(struct battle_bar *, struct battle *); - void (*select)(struct battle_bar *, struct battle *, const struct selection *); - void (*handle)(struct battle_bar *, struct battle *, const union event *); - void (*update)(struct battle_bar *, struct battle *, unsigned int); - void (*draw)(const struct battle_bar *, const struct battle *); - void (*finish)(struct battle_bar *, struct battle *); -}; - -CORE_BEGIN_DECLS - -void -battle_bar_start(struct battle_bar *, struct battle *); - -void -battle_bar_select(struct battle_bar *, struct battle *, const struct selection *); - -void -battle_bar_handle(struct battle_bar *, struct battle *, const union event *); - -void -battle_bar_update(struct battle_bar *, struct battle *, unsigned int); - -void -battle_bar_draw(const struct battle_bar *, const struct battle *); - -void -battle_bar_finish(struct battle_bar *, struct battle *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_BATTLE_BAR_H */
--- a/src/libmlk-rpg/rpg/battle-entity-state-attacking.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * battle-entity-state-attacking.h -- the entity is attacking - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/animation.h> -#include <mlk/core/panic.h> -#include <mlk/core/sprite.h> - -#include "battle-entity-state-attacking.h" -#include "battle-entity-state.h" -#include "battle-entity.h" - -struct self { - struct battle_entity_state_attacking data; - struct battle_entity_state state; -}; - -static int -update(struct battle_entity_state *st, struct battle_entity *et, unsigned int ticks) -{ - (void)et; - - return battle_entity_state_attacking_update(st->data, ticks); -} - -static void -draw(const struct battle_entity_state *st, const struct battle_entity *et) -{ - battle_entity_state_attacking_draw(st->data, et); -} - -static void -finish(struct battle_entity_state *st, struct battle_entity *et) -{ - (void)et; - - free(st->data); -} - -void -battle_entity_state_attacking_init(struct battle_entity_state_attacking *atk, const struct sprite *which) -{ - assert(atk); - assert(sprite_ok(which)); - - animation_init(&atk->anim, which, 100); - animation_start(&atk->anim); -} - -int -battle_entity_state_attacking_update(struct battle_entity_state_attacking *atk, unsigned int ticks) -{ - assert(atk); - - return animation_update(&atk->anim, ticks); -} - -void -battle_entity_state_attacking_draw(const struct battle_entity_state_attacking *atk, const struct battle_entity *et) -{ - assert(atk); - assert(battle_entity_ok(et)); - - animation_draw(&atk->anim, et->x, et->y); -} - -void -battle_entity_state_attacking(struct battle_entity *et, const struct sprite *which) -{ - assert(battle_entity_ok(et)); - assert(sprite_ok(which)); - - struct self *self; - - self = alloc_new0(sizeof (*self)); - self->state.data = self; - self->state.update = update; - self->state.draw = draw; - self->state.finish = finish; - - battle_entity_state_attacking_init(&self->data, which); - battle_entity_switch(et, &self->state); -}
--- a/src/libmlk-rpg/rpg/battle-entity-state-attacking.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * battle-entity-state-attacking.c -- the entity is attacking - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_ENTITY_STATE_ATTACKING_H -#define MLK_RPG_BATTLE_ENTITY_STATE_ATTACKING_H - -#include <mlk/core/animation.h> - -struct battle_entity; -struct sprite; - -struct battle_entity_state_attacking { - struct animation anim; -}; - -void -battle_entity_state_attacking_init(struct battle_entity_state_attacking *, const struct sprite *); - -int -battle_entity_state_attacking_update(struct battle_entity_state_attacking *, unsigned int); - -void -battle_entity_state_attacking_draw(const struct battle_entity_state_attacking *, const struct battle_entity *); - -void -battle_entity_state_attacking(struct battle_entity *, const struct sprite *); - -#endif /* !MLK_RPG_BATTLE_ENTITY_STATE_ATTACKING_H */
--- a/src/libmlk-rpg/rpg/battle-entity-state-blinking.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * battle-entity-state-blinking.c -- the entity is blinking - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/panic.h> -#include <mlk/core/sprite.h> -#include <mlk/core/texture.h> - -#include "battle-entity-state-blinking.h" -#include "battle-entity-state.h" -#include "battle-entity.h" -#include "character.h" - -#define TRANSPARENT (150) -#define OPAQUE (255) - -struct self { - struct battle_entity_state_blinking data; - struct battle_entity_state state; -}; - -static int -update(struct battle_entity_state *st, struct battle_entity *et, unsigned int ticks) -{ - (void)et; - - return battle_entity_state_blinking_update(st->data, ticks); -} - -static void -finish(struct battle_entity_state *st, struct battle_entity *et) -{ - (void)et; - - free(st->data); -} - -void -battle_entity_state_blinking_init(struct battle_entity_state_blinking *blk, struct battle_entity *et) -{ - assert(blk); - assert(battle_entity_ok(et)); - - blk->tex = et->ch->sprites[CHARACTER_SPRITE_NORMAL]->texture; - texture_set_alpha_mod(blk->tex, TRANSPARENT); -} - -int -battle_entity_state_blinking_update(struct battle_entity_state_blinking *blk, unsigned int ticks) -{ - assert(blk); - - blk->elapsed += ticks; - - if (blk->elapsed >= 80) { - blk->count += 1; - blk->elapsed = 0; - } - - texture_set_alpha_mod(blk->tex, blk->count % 2 == 0 ? TRANSPARENT : OPAQUE); - - return blk->count >= 3; -} - -void -battle_entity_state_blinking(struct battle_entity *et) -{ - assert(battle_entity_ok(et)); - - struct self *self; - - self = alloc_new0(sizeof (*self)); - self->state.data = self; - self->state.update = update; - self->state.finish = finish; - - battle_entity_state_blinking_init(&self->data, et); - battle_entity_switch(et, &self->state); -}
--- a/src/libmlk-rpg/rpg/battle-entity-state-blinking.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * battle-entity-state-blinking.h -- the entity is blinking - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_ENTITY_STATE_BLINKING_H -#define MLK_RPG_BATTLE_ENTITY_STATE_BLINKING_H - -struct battle_entity; -struct texture; - -struct battle_entity_state_blinking { - struct texture *tex; - unsigned int elapsed; - unsigned int count; -}; - -void -battle_entity_state_blinking_init(struct battle_entity_state_blinking *, struct battle_entity *et); - -int -battle_entity_state_blinking_update(struct battle_entity_state_blinking *, unsigned int); - -void -battle_entity_state_blinking(struct battle_entity *); - -#endif /* !MLK_RPG_BATTLE_ENTITY_STATE_BLINKING_H */
--- a/src/libmlk-rpg/rpg/battle-entity-state-moving.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/* - * battle-entity-state-moving.c -- the entity is moving - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <math.h> -#include <stdlib.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/panic.h> - -#include "battle-entity-state-moving.h" -#include "battle-entity-state.h" -#include "battle-entity.h" -#include "character.h" -#include "walksprite.h" - -#define SPEED 800 -#define SEC 1000 -#define WALK 40 - -struct self { - struct battle_entity_state_moving data; - struct battle_entity_state state; -}; - -static inline unsigned int -orientation(const struct battle_entity_state_moving *mv, const struct battle_entity *et) -{ - /* TODO: support diagonal. */ - /* See: walksprite definitions. */ - return mv->x < et->x ? 6 : 2; -} - -static int -update(struct battle_entity_state *st, struct battle_entity *et, unsigned int ticks) -{ - return battle_entity_state_moving_update(st->data, et, ticks); -} - -static void -draw(const struct battle_entity_state *st, const struct battle_entity *et) -{ - battle_entity_state_moving_draw(st->data, et); -} - -static void -finish(struct battle_entity_state *st, struct battle_entity *et) -{ - (void)et; - - free(st->data); -} - -void -battle_entity_state_moving_init(struct battle_entity_state_moving *mv, struct battle_entity *et, int dstx, int dsty) -{ - assert(mv); - assert(battle_entity_ok(et)); - - walksprite_init(&mv->ws, et->ch->sprites[CHARACTER_SPRITE_NORMAL], 40); - mv->x = dstx; - mv->y = dsty; -} - -int -battle_entity_state_moving_update(struct battle_entity_state_moving *mv, struct battle_entity *et, unsigned int ticks) -{ - assert(mv); - assert(battle_entity_ok(et)); - - int step_x, step_y, delta_x, delta_y; - - delta_x = mv->x < et->x ? -1 : +1; - delta_y = mv->y < et->y ? -1 : +1; - step_x = fmin(SPEED * ticks / SEC, abs(et->x - mv->x)); - step_y = fmin(SPEED * ticks / SEC, abs(et->y - mv->y)); - - et->x += delta_x * step_x; - et->y += delta_y * step_y; - - if (et->x != mv->x || et->y != mv->y) - walksprite_update(&mv->ws, ticks); - else - walksprite_reset(&mv->ws); - - return et->x == mv->x && et->y == mv->y; -} - -void -battle_entity_state_moving_draw(const struct battle_entity_state_moving *mv, const struct battle_entity *et) -{ - assert(mv); - assert(battle_entity_ok(et)); - - /* TODO: compute orientation. */ - walksprite_draw(&mv->ws, orientation(mv, et), et->x, et->y); -} - -void -battle_entity_state_moving(struct battle_entity *et, int dstx, int dsty) -{ - assert(battle_entity_ok(et)); - - struct self *self; - - self = alloc_new0(sizeof (*self)); - self->state.data = self; - self->state.update = update; - self->state.draw = draw; - self->state.finish = finish; - - battle_entity_state_moving_init(&self->data, et, dstx, dsty); - battle_entity_switch(et, &self->state); -}
--- a/src/libmlk-rpg/rpg/battle-entity-state-moving.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * battle-entity-state-moving.h -- the entity is moving - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_ENTITY_STATE_MOVING_H -#define MLK_RPG_BATTLE_ENTITY_STATE_MOVING_H - -#include <rpg/walksprite.h> - -struct battle_entity; - -struct battle_entity_state_moving { - struct walksprite ws; - int x; - int y; -}; - -void -battle_entity_state_moving_init(struct battle_entity_state_moving *, struct battle_entity *, int, int); - -int -battle_entity_state_moving_update(struct battle_entity_state_moving *, struct battle_entity *, unsigned int); - -void -battle_entity_state_moving_draw(const struct battle_entity_state_moving *, const struct battle_entity *); - -void -battle_entity_state_moving(struct battle_entity *, int, int); - -#endif /* !MLK_RPG_BATTLE_ENTITY_STATE_MOVING_H */
--- a/src/libmlk-rpg/rpg/battle-entity-state-normal.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * battle-entity-state-normal.c -- the entity is normal - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include "battle-entity-state-normal.h" -#include "battle-entity-state.h" -#include "battle-entity.h" - -/* TODO: animate characters when they are inactive. */ - -void -battle_entity_state_normal(struct battle_entity *et) -{ - assert(battle_entity_ok(et)); - - /* Not needed yet. */ - static struct battle_entity_state st; - - battle_entity_switch(et, &st); -}
--- a/src/libmlk-rpg/rpg/battle-entity-state-normal.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * battle-entity-state-normal.h -- the entity is normal - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_ENTITY_STATE_NORMAL_H -#define MLK_RPG_BATTLE_ENTITY_STATE_NORMAL_H - -struct battle_entity; - -void -battle_entity_state_normal(struct battle_entity *); - -#endif /* !MLK_RPG_BATTLE_ENTITY_STATE_NORMAL_H */ -
--- a/src/libmlk-rpg/rpg/battle-entity-state.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * battle-entity-state.c -- abstract battle entity state - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include "battle-entity.h" -#include "battle-entity-state.h" - -int -battle_entity_state_update(struct battle_entity_state *st, struct battle_entity *et, unsigned int ticks) -{ - assert(st); - assert(battle_entity_ok(et)); - - if (st->update) - return st->update(st, et, ticks); - - return 1; -} - -void -battle_entity_state_draw(const struct battle_entity_state *st, const struct battle_entity *et) -{ - assert(st); - assert(battle_entity_ok(et)); - - if (st->draw) - st->draw(st, et); - else - battle_entity_draw_sprite(et); -} - -void -battle_entity_state_finish(struct battle_entity_state *st, struct battle_entity *et) -{ - assert(battle_entity_ok(et)); - - if (st->finish) - st->finish(st, et); -}
--- a/src/libmlk-rpg/rpg/battle-entity-state.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * battle-entity-state.h -- abstract battle entity state - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_ENTITY_STATE_H -#define MLK_RPG_BATTLE_ENTITY_STATE_H - -#include <mlk/core/core.h> - -struct battle_entity; -struct sprite; - -struct battle_entity_state { - void *data; - int (*update)(struct battle_entity_state *, struct battle_entity *, unsigned int); - void (*draw)(const struct battle_entity_state *, const struct battle_entity *); - void (*finish)(struct battle_entity_state *, struct battle_entity *); -}; - -CORE_BEGIN_DECLS - -int -battle_entity_state_update(struct battle_entity_state *, struct battle_entity *, unsigned int); - -void -battle_entity_state_draw(const struct battle_entity_state *, const struct battle_entity *); - -void -battle_entity_state_finish(struct battle_entity_state *, struct battle_entity *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_BATTLE_ENTITY_STATE_H */
--- a/src/libmlk-rpg/rpg/battle-entity.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * battle-entity.c -- in game battle entity - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include <mlk/core/sprite.h> -#include <mlk/core/texture.h> - -#include <mlk/ui/theme.h> - -#include "battle.h" -#include "battle-entity.h" -#include "battle-entity-state.h" -#include "battle-entity-state-normal.h" -#include "character.h" - -static void -draw_name(const struct battle_entity *et, const struct battle *bt) -{ - struct label label = et->name; - - label.theme = BATTLE_THEME(bt); - - if (et == battle_current(bt)) - label.flags |= LABEL_FLAGS_SELECTED; - else - label.flags &= ~LABEL_FLAGS_SELECTED; - - label_draw(&label); -} - -void -battle_entity_init(struct battle_entity *et) -{ - assert(et); - - character_reset(et->ch); - texture_set_alpha_mod(et->ch->sprites[CHARACTER_SPRITE_NORMAL]->texture, 255); - - battle_entity_state_normal(et); -} - -int -battle_entity_ok(const struct battle_entity *et) -{ - return et && character_ok(et->ch); -} - -void -battle_entity_switch(struct battle_entity *et, struct battle_entity_state *st) -{ - assert(et); - assert(st); - - if (et->state) - battle_entity_state_finish(et->state, et); - - et->state = st; -} - -int -battle_entity_update(struct battle_entity *et, unsigned int ticks) -{ - assert(et); - - return battle_entity_state_update(et->state, et, ticks); -} - -void -battle_entity_draw_sprite(const struct battle_entity *et) -{ - struct sprite *sprite = et->ch->sprites[CHARACTER_SPRITE_NORMAL]; - int row; - - /* - * Ennemies are usually defined with a single image as such the - * sprite may contain only one cell/row. Otherwise if the user - * have provided a structured sprite, use appropriate row. - */ - if (sprite->nrows >= 6) - row = 6; - else - row = 0; - - sprite_draw(sprite, row, 0, et->x, et->y); -} - -void -battle_entity_draw(const struct battle_entity *et, const struct battle *bt) -{ - assert(et); - assert(bt); - - draw_name(et, bt); - battle_entity_state_draw(et->state, et); -} - -void -battle_entity_finish(struct battle_entity *et) -{ - assert(et); - - battle_entity_state_finish(et->state, et); -}
--- a/src/libmlk-rpg/rpg/battle-entity.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * battle-entity.h -- in game battle entity - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_ENTITY_H -#define MLK_RPG_BATTLE_ENTITY_H - -#include <mlk/core/core.h> - -#include <mlk/ui/label.h> - -struct battle; -struct battle_entity_state; -struct character; - -struct battle_entity { - struct character *ch; - int x; - int y; - struct label name; - struct battle_entity_state *state; -}; - -CORE_BEGIN_DECLS - -void -battle_entity_init(struct battle_entity *); - -int -battle_entity_ok(const struct battle_entity *); - -void -battle_entity_switch(struct battle_entity *, struct battle_entity_state *); - -int -battle_entity_update(struct battle_entity *, unsigned int); - -void -battle_entity_draw(const struct battle_entity *, const struct battle *); - -void -battle_entity_draw_sprite(const struct battle_entity *); - -void -battle_entity_finish(struct battle_entity *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_BATTLE_ENTITY_H */
--- a/src/libmlk-rpg/rpg/battle-indicator.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/* - * battle-indicator.c -- drawable for rendering a hp/mp count usage - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <math.h> -#include <stdio.h> -#include <string.h> - -#include <mlk/core/color.h> -#include <mlk/core/font.h> -#include <mlk/core/panic.h> - -#include <mlk/ui/theme.h> - -#include "battle-indicator.h" - -#define THEME(bti) ((bti)->theme ? (bti)->theme : theme_default()) -#define STEP (2) -#define DELAY (5) - -static inline unsigned int -inc(int cmp, int tgt) -{ - return tgt > cmp ? fmin(cmp + STEP, tgt) : fmax(cmp - STEP, tgt); -} - -static inline int -colored(const struct battle_indicator *bti) -{ - /* Only check r, g, b and ignore alpha. */ - return COLOR_R(bti->cur) == COLOR_R(bti->color) && - COLOR_G(bti->cur) == COLOR_G(bti->color) && - COLOR_B(bti->cur) == COLOR_B(bti->color); -} - -void -battle_indicator_start(struct battle_indicator *bti) -{ - assert(bti); - - char buf[128]; - const struct theme *theme = THEME(bti); - - snprintf(buf, sizeof (buf), "%u", bti->amount); - - bti->cur = 0xffffffff; - bti->elapsed = 0; - bti->alpha = 250; - - if (font_render(theme->fonts[THEME_FONT_INTERFACE], &bti->tex[0], buf, bti->cur) < 0|| - font_render(theme->fonts[THEME_FONT_INTERFACE], &bti->tex[1], buf, 0x000000ff) < 0) - panic(); -} - -int -battle_indicator_completed(const struct battle_indicator *bti) -{ - assert(battle_indicator_ok(bti)); - - return colored(bti) && bti->alpha == 0; -} - -int -battle_indicator_ok(const struct battle_indicator *bti) -{ - return bti && texture_ok(&bti->tex[0]) && texture_ok(&bti->tex[1]); -} - -int -battle_indicator_update(struct battle_indicator *bti, unsigned int ticks) -{ - assert(battle_indicator_ok(bti)); - - bti->elapsed += ticks; - - if (bti->elapsed > DELAY) { - bti->elapsed = 0; - - if (!colored(bti)) { - /* Update colors first. */ - bti->cur = COLOR_HEX( - inc(COLOR_R(bti->cur), COLOR_R(bti->color)), - inc(COLOR_G(bti->cur), COLOR_G(bti->color)), - inc(COLOR_B(bti->cur), COLOR_B(bti->color)), - 255 - ); - - texture_set_color_mod(&bti->tex[0], bti->cur); - } else { - /* Update alpha next. */ - bti->alpha -= 10; - - texture_set_alpha_mod(&bti->tex[0], bti->alpha); - texture_set_alpha_mod(&bti->tex[1], bti->alpha); - } - } - - return battle_indicator_completed(bti); -} - -void -battle_indicator_draw(const struct battle_indicator *bti, int x, int y) -{ - assert(battle_indicator_ok(bti)); - - texture_draw(&bti->tex[1], x + 1, y + 1); - texture_draw(&bti->tex[0], x, y); -} - -void -battle_indicator_finish(struct battle_indicator *bti) -{ - assert(bti); - - texture_finish(&bti->tex[0]); - texture_finish(&bti->tex[1]); - - memset(bti, 0, sizeof (*bti)); -}
--- a/src/libmlk-rpg/rpg/battle-indicator.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * battle-indicator.h -- drawable for rendering a hp/mp count usage - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_INDICATOR_H -#define MLK_RPG_BATTLE_INDICATOR_H - -#include <mlk/core/core.h> -#include <mlk/core/texture.h> - -#define BATTLE_INDICATOR_HP_COLOR (0xa5303000) -#define BATTLE_INDICATOR_MP_COLOR (0xa23e8c00) - -struct theme; - -struct battle_indicator { - unsigned int color; - unsigned int amount; - const struct theme *theme; - unsigned int cur; - unsigned int elapsed; - unsigned int alpha; - struct texture tex[2]; -}; - -CORE_BEGIN_DECLS - -void -battle_indicator_start(struct battle_indicator *); - -int -battle_indicator_completed(const struct battle_indicator *); - -int -battle_indicator_ok(const struct battle_indicator *); - -int -battle_indicator_update(struct battle_indicator *, unsigned int); - -void -battle_indicator_draw(const struct battle_indicator *, int, int); - -void -battle_indicator_finish(struct battle_indicator *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_BATTLE_INDICATOR_H */
--- a/src/libmlk-rpg/rpg/battle-message.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * battle-message.c -- automatic top center message in battle - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include <mlk/core/window.h> - -#include <mlk/ui/align.h> -#include <mlk/ui/frame.h> -#include <mlk/ui/label.h> - -#include "battle-message.h" - -#define DELAY 1500 - -int -battle_message_update(struct battle_message *msg, unsigned int ticks) -{ - assert(msg); - - msg->elapsed += ticks; - - return msg->elapsed >= DELAY; -} - -void -battle_message_draw(const struct battle_message *msg) -{ - assert(msg); - - struct frame f = {0}; - struct label l = {0}; - unsigned int lw = 0, lh = 0; - - /* Prepare message frame. */ - f.w = window.w / 3; - f.h = window.h / 15; - f.theme = msg->theme; - - /* Center on top. */ - align(ALIGN_TOP, &f.x, &f.y, f.w, f.h, 0, 20, window.w, window.h); - - /* Prepare message label box. */ - l.text = msg->text; - l.flags = LABEL_FLAGS_SHADOW; - l.theme = msg->theme; - label_query(&l, &lw, &lh); - - /* Align the text in the box. */ - align(ALIGN_CENTER, &l.x, &l.y, lw, lh, f.x, f.y, f.w, f.h); - - frame_draw(&f); - label_draw(&l); -}
--- a/src/libmlk-rpg/rpg/battle-message.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * battle-message.h -- automatic top center message in battle - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_MESSAGE_H -#define MLK_RPG_BATTLE_MESSAGE_H - -#include <mlk/core/core.h> - -struct theme; - -struct battle_message { - const char *text; - struct theme *theme; - unsigned int elapsed; -}; - -CORE_BEGIN_DECLS - -int -battle_message_update(struct battle_message *, unsigned int); - -void -battle_message_draw(const struct battle_message *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_BATTLE_MESSAGE_H */
--- a/src/libmlk-rpg/rpg/battle-state-ai.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* - * battle-state-ai.c -- battle state (enemy is playing) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> - -#include <mlk/core/alloc.h> - -#include "battle-state-ai.h" -#include "battle-state.h" -#include "battle.h" -#include "character.h" - -static int -update(struct battle_state *st, struct battle *bt, unsigned int ticks) -{ - (void)st; - (void)ticks; - - battle_state_ai_update(bt); - - return 0; -} - -static void -draw(const struct battle_state *st, const struct battle *bt) -{ - (void)st; - - battle_state_ai_draw(bt); -} - -static void -finish(struct battle_state *st, struct battle *bt) -{ - (void)bt; - - free(st); -} - -void -battle_state_ai_update(struct battle *bt) -{ - assert(battle_ok(bt)); - - struct character *ch = battle_current(bt)->ch; - - /* - * Immediately invoke the enemy exec strategy and put the battle state - * to check. - */ - character_exec(ch, bt); -} - -void -battle_state_ai_draw(const struct battle *bt) -{ - assert(battle_ok(bt)); - - battle_draw_component(bt, BATTLE_COMPONENT_ALL); -} - -void -battle_state_ai(struct battle *bt) -{ - assert(bt); - - struct battle_state *self; - - self = alloc_new0(sizeof (*self)); - self->data = bt; - self->update = update; - self->draw = draw; - self->finish = finish; - - battle_switch(bt, self); -}
--- a/src/libmlk-rpg/rpg/battle-state-ai.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * battle-state-ai.h -- battle state (enemy is playing) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_STATE_AI_H -#define MLK_RPG_BATTLE_STATE_AI_H - -struct battle; - -void -battle_state_ai_update(struct battle *); - -void -battle_state_ai_draw(const struct battle *); - -void -battle_state_ai(struct battle *); - -#endif /* !MLK_RPG_BATTLE_STATE_AI_H */
--- a/src/libmlk-rpg/rpg/battle-state-attacking.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -/* - * battle-state-attacking.c -- battle state (entity is moving for attacking) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/panic.h> -#include <mlk/core/sprite.h> - -#include "battle-entity-state-attacking.h" -#include "battle-entity-state-blinking.h" -#include "battle-entity-state-moving.h" -#include "battle-entity-state-normal.h" -#include "battle-entity-state.h" -#include "battle-state-attacking.h" -#include "battle-state-check.h" -#include "battle-state.h" -#include "battle.h" -#include "character.h" - -struct self { - struct battle_state_attacking data; - struct battle_state state; -}; - -static void -damage(const struct battle_entity *source, struct battle_entity *target, struct battle *bt) -{ - (void)source; - - /* TODO: math calculation here.*/ - target->ch->hp -= 50; - - if (target->ch->hp < 0) - target->ch->hp = 0; - - battle_indicator_hp(bt, target->ch, 50); -} - -static int -update(struct battle_state *st, struct battle *bt, unsigned int ticks) -{ - battle_state_attacking_update(st->data, bt, ticks); - - return 0; -} - -static void -draw(const struct battle_state *st, const struct battle *bt) -{ - battle_state_attacking_draw(st->data, bt); -} - -static void -finish(struct battle_state *st, struct battle *bt) -{ - (void)bt; - - free(st->data); -} - -void -battle_state_attacking_init(struct battle_state_attacking *atk, - struct battle_entity *source, - struct battle_entity *target) -{ - assert(atk); - assert(battle_entity_ok(source)); - assert(battle_entity_ok(target)); - - int x, y; - - /* Starts this state with advancing. */ - atk->source = source; - atk->target = target; - atk->origin_x = source->x; - atk->origin_y = source->y; - - /* We go to the enemy. */ - x = target->x + target->ch->sprites[CHARACTER_SPRITE_NORMAL]->cellw; - y = target->y; - - /* If it is an enemy we don't move it but blink instead. */ - if (source->ch->exec) { - atk->status = BATTLE_STATE_ATTACKING_BLINKING; - battle_entity_state_blinking(source); - } else - battle_entity_state_moving(source, x, y); -} - -void -battle_state_attacking_update(struct battle_state_attacking *atk, struct battle *bt, unsigned int ticks) -{ - assert(atk); - assert(bt); - - battle_update_component(bt, ticks, BATTLE_COMPONENT_ALL); - - if (!battle_entity_update(atk->source, 0)) - return; - - switch (atk->status) { - case BATTLE_STATE_ATTACKING_ADVANCING: - /* - * Current entity state is battle-entity-state-moving but it is - * already updated from the game itself so pass 0 just to check - * if it has finished moving. - */ - atk->status = BATTLE_STATE_ATTACKING_DAMAGING; - - /* TODO: determine sprite to use about equipment. */ - battle_entity_state_attacking(atk->source, atk->source->ch->sprites[CHARACTER_SPRITE_SWORD]); - break; - case BATTLE_STATE_ATTACKING_DAMAGING: - /* Move back to original position. */ - atk->status = BATTLE_STATE_ATTACKING_RETURNING; - damage(atk->source, atk->target, bt); - battle_entity_state_moving(atk->source, atk->origin_x, atk->origin_y); - break; - case BATTLE_STATE_ATTACKING_RETURNING: - case BATTLE_STATE_ATTACKING_BLINKING: - /* Just wait. */ - battle_entity_state_normal(atk->source); - damage(atk->source, atk->target, bt); - battle_state_check(bt); - break; - default: - break; - } -} - -void -battle_state_attacking_draw(const struct battle_state_attacking *atk, const struct battle *bt) -{ - assert(atk); - assert(battle_ok(bt)); - - (void)atk; - - battle_draw_component(bt, BATTLE_COMPONENT_ALL); -} - -void -battle_state_attacking(struct battle_entity *source, struct battle_entity *target, struct battle *bt) -{ - assert(battle_entity_ok(source)); - assert(battle_entity_ok(target)); - assert(bt); - - struct self *self; - - self = alloc_new0(sizeof (*self)); - self->state.data = self; - self->state.update = update; - self->state.draw = draw; - self->state.finish = finish; - - battle_state_attacking_init(&self->data, source, target); - battle_switch(bt, &self->state); -}
--- a/src/libmlk-rpg/rpg/battle-state-attacking.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * battle-state-attacking.h -- battle state (entity is moving for attacking) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_STATE_ATTACKING_H -#define MLK_RPG_BATTLE_STATE_ATTACKING_H - -struct battle; -struct battle_entity; - -enum battle_state_attacking_status { - /* For team. */ - BATTLE_STATE_ATTACKING_ADVANCING, - BATTLE_STATE_ATTACKING_DAMAGING, - BATTLE_STATE_ATTACKING_RETURNING, - - /* For enemies. */ - BATTLE_STATE_ATTACKING_BLINKING, -}; - -struct battle_state_attacking { - enum battle_state_attacking_status status; - struct battle_entity *source; - struct battle_entity *target; - int origin_x; - int origin_y; -}; - -void -battle_state_attacking_init(struct battle_state_attacking *, - struct battle_entity *, - struct battle_entity *); - -void -battle_state_attacking_update(struct battle_state_attacking *, struct battle *, unsigned int); - -void -battle_state_attacking_draw(const struct battle_state_attacking *, const struct battle *); - -void -battle_state_attacking(struct battle_entity *, struct battle_entity *, struct battle *); - -#endif /* !#define MLK_RPG_BATTLE_STATE_ATTACKING_H */
--- a/src/libmlk-rpg/rpg/battle-state-check.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,207 +0,0 @@ -/* - * battle-state-check.c -- battle state (check status) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> -#include <string.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/panic.h> -#include <mlk/core/sprite.h> -#include <mlk/core/texture.h> -#include <mlk/core/trace.h> - -#include "battle-state-check.h" -#include "battle-state-lost.h" -#include "battle-state-victory.h" -#include "battle-state.h" -#include "battle.h" -#include "character.h" - -struct fadeout { - struct character *ch; - int x; - int y; - struct drawable dw; - unsigned int alpha; - unsigned int elapsed; -}; - -static int -fadeout_update(struct drawable *dw, unsigned int ticks) -{ - struct fadeout *fade = dw->data; - - fade->elapsed += ticks; - - if (fade->elapsed >= 8) { - fade->elapsed = 0; - - if (fade->alpha == 0) - return 1; - - fade->alpha -= 10; - } - - return 0; -} - -static void -fadeout_draw(struct drawable *dw) -{ - const struct fadeout *fade = dw->data; - struct sprite *sprite = fade->ch->sprites[CHARACTER_SPRITE_NORMAL]; - - texture_set_alpha_mod(sprite->texture, fade->alpha); - sprite_draw(sprite, 0, 0, fade->x, fade->y); - texture_set_alpha_mod(sprite->texture, 255); -} - -static void -fadeout_finish(struct drawable *dw) -{ - free(dw->data); -} - -static void -fadeout(struct battle *bt, struct battle_entity *et) -{ - struct fadeout *fade; - - if (!bt->effects) { - tracef("can't create a fadeout effect without a drawable_stack"); - return; - } - - fade = alloc_new0(sizeof (*fade)); - fade->ch = et->ch; - fade->x = et->x; - fade->y = et->y; - fade->alpha = 250; - fade->dw.data = fade; - fade->dw.draw = fadeout_draw; - fade->dw.update = fadeout_update; - fade->dw.finish = fadeout_finish; - - if (drawable_stack_add(bt->effects, &fade->dw) < 0) - free(fade); -} - -static int -is_dead(const struct battle *bt) -{ - const struct battle_entity *et; - - BATTLE_TEAM_FOREACH(bt, et) { - if (!character_ok(et->ch)) - continue; - if (et->ch->hp > 0) - return 0; - } - - return 1; -} - -static int -is_won(const struct battle *bt) -{ - const struct battle_entity *et; - - BATTLE_ENEMY_FOREACH(bt, et) - if (character_ok(et->ch)) - return 0; - - return 1; -} - -static void -clean(struct battle *bt) -{ - for (size_t i = 0; i < bt->enemiesz; ++i) { - if (bt->enemies[i] && character_ok(bt->enemies[i]->ch) && bt->enemies[i]->ch->hp == 0) { - fadeout(bt, bt->enemies[i]); - bt->enemies[i] = NULL; - } - } -} - -static int -update(struct battle_state *st, struct battle *bt, unsigned int ticks) -{ - (void)st; - (void)ticks; - - battle_state_check_update(bt); - - return 0; -} - -static void -draw(const struct battle_state *st, const struct battle *bt) -{ - (void)st; - - battle_state_check_draw(bt); -} - -static void -finish(struct battle_state *st, struct battle *bt) -{ - (void)bt; - - free(st); -} - -void -battle_state_check_update(struct battle *bt) -{ - assert(battle_ok(bt)); - - clean(bt); - - if (is_dead(bt)) - battle_state_lost(bt); - else if (is_won(bt)) - battle_state_victory(bt); - else - battle_next(bt); -} - -void -battle_state_check_draw(const struct battle *bt) -{ - assert(battle_ok(bt)); - - battle_draw_component(bt, BATTLE_COMPONENT_ALL); -} - -void -battle_state_check(struct battle *bt) -{ - assert(battle_ok(bt)); - - struct battle_state *self; - - self = alloc_new0(sizeof (*self)); - self->data = bt; - self->update = update; - self->draw = draw; - self->finish = finish; - - battle_switch(bt, self); -}
--- a/src/libmlk-rpg/rpg/battle-state-check.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * battle-state-check.h -- battle state (check status) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_STATE_CHECK_H -#define MLK_RPG_BATTLE_STATE_CHECK_H - -struct battle; - -void -battle_state_check_update(struct battle *); - -void -battle_state_check_draw(const struct battle *); - -void -battle_state_check(struct battle *); - -#endif /* !MLK_RPG_BATTLE_STATE_CHECK_H */
--- a/src/libmlk-rpg/rpg/battle-state-closing.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/* - * battle-state-closing.c -- battle state (closing) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> -#include <string.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/music.h> -#include <mlk/core/painter.h> -#include <mlk/core/panic.h> -#include <mlk/core/texture.h> -#include <mlk/core/window.h> - -#include "battle-state-closing.h" -#include "battle.h" - -struct self { - struct battle_state_closing data; - struct battle_state state; -}; - -static int -update(struct battle_state *st, struct battle *bt, unsigned int ticks) -{ - (void)bt; - - return battle_state_closing_update(st->data, ticks); -} - -static void -draw(const struct battle_state *st, const struct battle *bt) -{ - (void)bt; - - battle_state_closing_draw(st->data, bt); -} - -static void -finish(struct battle_state *st, struct battle *bt) -{ - (void)bt; - - battle_state_closing_finish(st->data); - free(st->data); -} - -void -battle_state_closing_init(struct battle_state_closing *cls) -{ - assert(cls); - - if (texture_new(&cls->texture, window.w, window.h) < 0) - panic(); - - PAINTER_BEGIN(&cls->texture); - texture_set_blend_mode(&cls->texture, TEXTURE_BLEND_BLEND); - painter_set_color(0x000000ff); - painter_clear(); - painter_draw_rectangle(0, 0, window.w, window.h); - PAINTER_END(); - - texture_set_alpha_mod(&cls->texture, 0); -} - -int -battle_state_closing_update(struct battle_state_closing *cls, unsigned int ticks) -{ - assert(cls); - - cls->elapsed += ticks; - - /* TODO: ??? */ - if (cls->elapsed > 8) { - cls->elapsed = 0; - - if (cls->alpha == 255) { - /* TODO: since OpenAL, no notion of global music. */ -#if 0 - music_stop(0); -#endif - return 1; - } - - cls->alpha += 5; - texture_set_alpha_mod(&cls->texture, cls->alpha); - } - - return 0; -} - -void -battle_state_closing_draw(const struct battle_state_closing *cls, const struct battle *bt) -{ - assert(cls); - - battle_draw_component(bt, BATTLE_COMPONENT_ALL); - texture_draw(&cls->texture, 0, 0); -} - -void -battle_state_closing_finish(struct battle_state_closing *cls) -{ - assert(cls); - - texture_finish(&cls->texture); - memset(cls, 0, sizeof (*cls)); -} - -void -battle_state_closing(struct battle *bt) -{ - assert(bt); - - struct self *self; - - self = alloc_new0(sizeof (*self)); - self->state.data = self; - self->state.update = update; - self->state.draw = draw; - self->state.finish = finish; - - battle_state_closing_init(&self->data); - battle_switch(bt, &self->state); -}
--- a/src/libmlk-rpg/rpg/battle-state-closing.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * battle-state-closing.h -- battle state (closing) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_STATE_CLOSING_H -#define MLK_RPG_BATTLE_STATE_CLOSING_H - -#include <mlk/core/texture.h> - -struct battle; - -struct battle_state_closing { - struct texture texture; - unsigned int alpha; - unsigned int elapsed; -}; - -void -battle_state_closing_init(struct battle_state_closing *); - -int -battle_state_closing_update(struct battle_state_closing *, unsigned int); - -void -battle_state_closing_draw(const struct battle_state_closing *, const struct battle *); - -void -battle_state_closing_finish(struct battle_state_closing *); - -void -battle_state_closing(struct battle *); - -#endif /* !MLK_RPG_BATTLE_STATE_CLOSING_H */
--- a/src/libmlk-rpg/rpg/battle-state-item.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -/* - * battle-state-item.c -- battle state (using item) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/panic.h> - -#include <rpg/inventory.h> -#include <rpg/item.h> - -#include "battle-entity-state-moving.h" -#include "battle-entity-state-normal.h" -#include "battle-entity-state.h" -#include "battle-message.h" -#include "battle-state-item.h" -#include "battle-state.h" -#include "battle.h" - -struct self { - struct battle_state_item data; - struct battle_state state; -}; - -static int -update(struct battle_state *st, struct battle *bt, unsigned int ticks) -{ - return battle_state_item_update(st->data, bt, ticks); -} - -static void -draw(const struct battle_state *st, const struct battle *bt) -{ - (void)bt; - - battle_state_item_draw(st->data); -} - -static void -finish(struct battle_state *st, struct battle *bt) -{ - (void)bt; - - free(st->data); -} - -void -battle_state_item_init(struct battle_state_item *it, - struct battle *bt, - struct battle_entity *source, - struct battle_entity *target, - struct inventory_slot *slot) -{ - assert(it); - assert(bt); - assert(battle_entity_ok(source)); - assert(battle_entity_ok(target)); - assert(slot); - - it->source = source; - it->target = target; - it->slot = slot; - it->origin_x = it->source->x; - - it->msg.text = slot->item->name; - it->msg.theme = bt->theme; - - battle_entity_state_moving(it->source, it->origin_x - 100, it->source->y); -} - -int -battle_state_item_update(struct battle_state_item *it, struct battle *bt, unsigned int ticks) -{ - assert(it); - assert(bt); - - switch (it->status) { - case BATTLE_STATE_ITEM_ADVANCING: - /* Entity is updating from battle, so just inspect its status. */ - if (battle_entity_update(it->source, 0)) { - it->status = BATTLE_STATE_ITEM_MESSAGE; - battle_entity_state_normal(it->source); - } - break; - case BATTLE_STATE_ITEM_MESSAGE: - if (battle_message_update(&it->msg, ticks)) { - it->status = BATTLE_STATE_ITEM_RETURNING; - battle_entity_state_moving(it->source, it->origin_x, it->source->y); - } - break; - default: - if (battle_entity_update(it->source, 0)) { - battle_entity_state_normal(it->source); - battle_use(bt, it->slot->item, it->source->ch, it->target->ch); - } - break; - } - - return 0; -} - -void -battle_state_item_draw(struct battle_state_item *it) -{ - assert(it); - - if (it->status == BATTLE_STATE_ITEM_MESSAGE) - battle_message_draw(&it->msg); -} - -void -battle_state_item(struct battle *bt, - struct battle_entity *source, - struct battle_entity *target, - struct inventory_slot *slot) -{ - assert(battle_entity_ok(source)); - assert(battle_entity_ok(target)); - assert(slot); - assert(bt); - - struct self *self; - - self = alloc_new0(sizeof (*self)); - self->state.data = self; - self->state.update = update; - self->state.draw = draw; - self->state.finish = finish; - - battle_state_item_init(&self->data, bt, source, target, slot); - battle_switch(bt, &self->state); -}
--- a/src/libmlk-rpg/rpg/battle-state-item.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * battle-state-item.h -- battle state (using item) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_STATE_ITEM_H -#define MLK_RPG_BATTLE_STATE_ITEM_H - -#include <rpg/battle-message.h> - -struct battle; -struct battle_entity; -struct inventory_slot; - -enum battle_state_item_status { - BATTLE_STATE_ITEM_ADVANCING, - BATTLE_STATE_ITEM_MESSAGE, - BATTLE_STATE_ITEM_RETURNING -}; - -struct battle_state_item { - enum battle_state_item_status status; - struct battle_message msg; - struct battle_entity *source; - struct battle_entity *target; - struct inventory_slot *slot; - int origin_x; -}; - -void -battle_state_item_init(struct battle_state_item *, - struct battle *, - struct battle_entity *, - struct battle_entity *, - struct inventory_slot *); - -int -battle_state_item_update(struct battle_state_item *, struct battle *, unsigned int); - -void -battle_state_item_draw(struct battle_state_item *); - -void -battle_state_item(struct battle *, - struct battle_entity *, - struct battle_entity *, - struct inventory_slot *); - - -#endif /* !MLK_RPG_BATTLE_STATE_ITEM_H */
--- a/src/libmlk-rpg/rpg/battle-state-lost.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/* - * battle-state-lost.c -- battle state (lost) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/music.h> -#include <mlk/core/panic.h> -#include <mlk/core/window.h> - -#include "battle-state-closing.h" -#include "battle-state-lost.h" -#include "battle-state.h" -#include "battle.h" - -struct self { - struct battle_state_lost data; - struct battle_state state; -}; - -static void -handle(struct battle_state *st, struct battle *bt, const union event *ev) -{ - (void)bt; - - battle_state_lost_handle(st->data, ev); -} - -static int -update(struct battle_state *st, struct battle *bt, unsigned int ticks) -{ - return battle_state_lost_update(st->data, bt, ticks); -} - -static void -draw(const struct battle_state *st, const struct battle *bt) -{ - (void)bt; - - battle_state_lost_draw(st->data, bt); -} - -void -battle_state_lost_init(struct battle_state_lost *lost, struct battle *bt) -{ - assert(lost); - assert(bt); - - lost->text = "You have been defeated..."; - - lost->msg.lines = &lost->text; - lost->msg.linesz = 1; - lost->msg.theme = bt->theme; - lost->msg.flags = MESSAGE_FLAGS_AUTOMATIC | - MESSAGE_FLAGS_FADEIN | - MESSAGE_FLAGS_FADEOUT; - lost->msg.timeout = MESSAGE_TIMEOUT_DEFAULT; - lost->msg.delay = MESSAGE_DELAY_DEFAULT; - - message_start(&lost->msg); - message_query(&lost->msg, NULL, &lost->msg.h); - - lost->msg.w = window.w * 0.6; - lost->msg.y = window.h * 0.1; - lost->msg.x = (window.w - lost->msg.w) / 2; - - bt->status = BATTLE_STATUS_LOST; - - if (bt->music[2]) - music_play(bt->music[2], MUSIC_NONE); -} - -void -battle_state_lost_handle(struct battle_state_lost *lost, const union event *ev) -{ - assert(lost); - assert(ev); - - message_handle(&lost->msg, ev); -} - -int -battle_state_lost_update(struct battle_state_lost *lost, struct battle *bt, unsigned int ticks) -{ - assert(lost); - assert(bt); - - if (message_update(&lost->msg, ticks)) - battle_state_closing(bt); - - return 0; -} - -void -battle_state_lost_draw(struct battle_state_lost *lost, const struct battle *bt) -{ - assert(lost); - assert(battle_ok(bt)); - - battle_draw_component(bt, BATTLE_COMPONENT_ALL); - message_draw(&lost->msg); -} - -void -battle_state_lost(struct battle *bt) -{ - assert(bt); - - struct self *self; - - self = alloc_new0(sizeof (*self)); - self->state.data = self; - self->state.handle = handle; - self->state.update = update; - self->state.draw = draw; - - battle_state_lost_init(&self->data, bt); - battle_switch(bt, &self->state); -}
--- a/src/libmlk-rpg/rpg/battle-state-lost.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * battle-state-lost.h -- battle state (lost) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_STATE_LOST_H -#define MLK_RPG_BATTLE_STATE_LOST_H - -#include <rpg/message.h> - -union event; - -struct battle; - -struct battle_state_lost { - const char *text; - struct message msg; -}; - -void -battle_state_lost_init(struct battle_state_lost *, struct battle *); - -void -battle_state_lost_handle(struct battle_state_lost *, const union event *); - -int -battle_state_lost_update(struct battle_state_lost *, struct battle *, unsigned int); - -void -battle_state_lost_draw(struct battle_state_lost *, const struct battle *); - -void -battle_state_lost(struct battle *); - -#endif /* !MLK_RPG_BATTLE_STATE_LOST_H */
--- a/src/libmlk-rpg/rpg/battle-state-menu.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * battle-state-menu.h -- battle state (menu) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> - -#include <mlk/core/alloc.h> - -#include "battle-bar.h" -#include "battle-state-menu.h" -#include "battle-state.h" -#include "battle.h" - -static void -handle(struct battle_state *st, struct battle *bt, const union event *ev) -{ - (void)st; - - battle_state_menu_handle(bt, ev); -} - -static int -update(struct battle_state *st, struct battle *bt, unsigned int ticks) -{ - (void)st; - - battle_state_menu_update(bt, ticks); - - return 0; -} - -static void -draw(const struct battle_state *st, const struct battle *bt) -{ - (void)st; - - battle_state_menu_draw(bt); -} - -static void -finish(struct battle_state *st, struct battle *bt) -{ - (void)bt; - - free(st); -} - -void -battle_state_menu_handle(struct battle *bt, const union event *ev) -{ - assert(bt); - assert(ev); - - battle_bar_handle(bt->bar, bt, ev); -} - -void -battle_state_menu_update(struct battle *bt, unsigned int ticks) -{ - assert(battle_ok(bt)); - - battle_update_component(bt, ticks, BATTLE_COMPONENT_ALL); -} - -void -battle_state_menu_draw(const struct battle *bt) -{ - assert(battle_ok(bt)); - - battle_draw_component(bt, BATTLE_COMPONENT_ALL); -} - -void -battle_state_menu(struct battle *bt) -{ - assert(bt); - - struct battle_state *state; - - state = alloc_new0(sizeof (*state)); - state->data = bt; - state->handle = handle; - state->update = update; - state->draw = draw; - state->finish = finish; - - battle_bar_start(bt->bar, bt); - battle_switch(bt, state); -}
--- a/src/libmlk-rpg/rpg/battle-state-menu.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * battle-state-menu.c -- battle state (menu) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_STATE_MENU_H -#define MLK_RPG_BATTLE_STATE_MENU_H - -struct battle; - -union event; - -void -battle_state_menu_handle(struct battle *, const union event *); - -void -battle_state_menu_update(struct battle *, unsigned int); - -void -battle_state_menu_draw(const struct battle *); - -void -battle_state_menu(struct battle *); - -#endif /* !MLK_RPG_BATTLE_STATE_MENU_H */
--- a/src/libmlk-rpg/rpg/battle-state-opening.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -/* - * battle-state-opening.c -- battle state (opening) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/painter.h> -#include <mlk/core/panic.h> -#include <mlk/core/window.h> - -#include "battle-state-check.h" -#include "battle-state-opening.h" -#include "battle-state.h" -#include "battle.h" - -#define DELAY (1000U) - -struct self { - /* Always keep first. */ - struct battle_state_opening data; - struct battle_state state; -}; - -static int -update(struct battle_state *st, struct battle *bt, unsigned int ticks) -{ - (void)bt; - - return battle_state_opening_update(st->data, bt, ticks); -} - -static void -draw(const struct battle_state *st, const struct battle *bt) -{ - (void)bt; - - battle_state_opening_draw(st->data, bt); -} - -static void -finish(struct battle_state *st, struct battle *bt) -{ - (void)bt; - - free(st->data); -} - -int -battle_state_opening_update(struct battle_state_opening *op, struct battle *bt, unsigned int ticks) -{ - op->elapsed += ticks; - - /* - * Those function will effectively change state accordingly to the - * order of playing. - */ - if (op->elapsed >= DELAY) - battle_state_check(bt); - - return 0; -} - -void -battle_state_opening_draw(const struct battle_state_opening *op, const struct battle *bt) -{ - assert(op); - assert(bt); - - const unsigned int w = window.w; - const unsigned int h = window.h / 2; - const unsigned int ch = op->elapsed * h / DELAY; - - battle_draw_component(bt, BATTLE_COMPONENT_BACKGROUND | BATTLE_COMPONENT_ENTITIES); - - /* Draw some bezels opening. */ - painter_set_color(0x000000ff); - painter_draw_rectangle(0, 0, w, h - ch); - painter_draw_rectangle(0, h + ch, w, h - ch); -} - -void -battle_state_opening(struct battle *bt) -{ - assert(bt); - - struct self *self; - - self = alloc_new0(sizeof (*self)); - self->state.data = self; - self->state.update = update; - self->state.draw = draw; - self->state.finish = finish; - - battle_switch(bt, &self->state); -}
--- a/src/libmlk-rpg/rpg/battle-state-opening.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - * battle-state-opening.h -- battle state (opening) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_STATE_OPENING_H -#define MLK_RPG_BATTLE_STATE_OPENING_H - -struct battle; - -struct battle_state_opening { - unsigned int elapsed; -}; - -int -battle_state_opening_update(struct battle_state_opening *, struct battle *, unsigned int); - -void -battle_state_opening_draw(const struct battle_state_opening *, const struct battle *); - -void -battle_state_opening(struct battle *); - -#endif /* !MLK_RPG_BATTLE_STATE_OPENING_H */
--- a/src/libmlk-rpg/rpg/battle-state-rendering.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* - * battle-state-rendering.c -- battle state (rendering an action) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/drawable.h> - -#include "battle-state-rendering.h" -#include "battle.h" - -struct self { - struct battle_state_rendering data; - struct battle_state state; -}; - -static int -update(struct battle_state *st, struct battle *bt, unsigned int ticks) -{ - battle_state_rendering_update(st->data, bt, ticks); - - return 0; -} - -static void -draw(const struct battle_state *st, const struct battle *bt) -{ - battle_state_rendering_draw(st->data, bt); -} - -static void -finish(struct battle_state *st, struct battle *bt) -{ - (void)bt; - - battle_state_rendering_finish(st->data); - free(st->data); -} - -void -battle_state_rendering_init(struct battle_state_rendering *rdr, struct drawable *dw) -{ - assert(rdr); - assert(dw); - - rdr->drawable = dw; -} - -int -battle_state_rendering_update(struct battle_state_rendering *rdr, struct battle *bt, unsigned int ticks) -{ - assert(rdr); - assert(battle_ok(bt)); - - battle_update_component(bt, BATTLE_COMPONENT_ALL, ticks); - - if (drawable_update(rdr->drawable, ticks)) { - drawable_end(rdr->drawable); - return 1; - } - - return 0; -} - -void -battle_state_rendering_draw(const struct battle_state_rendering *rdr, const struct battle *bt) -{ - assert(rdr); - - battle_draw_component(bt, BATTLE_COMPONENT_ALL); - drawable_draw(rdr->drawable); -} - -void -battle_state_rendering_finish(struct battle_state_rendering *rdr) -{ - assert(rdr); - - drawable_finish(rdr->drawable); -} - -void -battle_state_rendering(struct battle *bt, struct drawable *dw) -{ - assert(bt); - assert(dw); - - struct self *self; - - self = alloc_new0(sizeof (*self)); - self->state.data = self; - self->state.update = update; - self->state.draw = draw; - self->state.finish = finish; - - battle_state_rendering_init(&self->data, dw); - battle_switch(bt, &self->state); -}
--- a/src/libmlk-rpg/rpg/battle-state-rendering.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * battle-state-rendering.h -- battle state (rendering an action) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_STATE_RENDERING_H -#define MLK_RPG_BATTLE_STATE_RENDERING_H - -struct battle; -struct drawable; - -struct battle_state_rendering { - struct drawable *drawable; -}; - -void -battle_state_rendering_init(struct battle_state_rendering *, struct drawable *); - -int -battle_state_rendering_update(struct battle_state_rendering *, struct battle *, unsigned int); - -void -battle_state_rendering_draw(const struct battle_state_rendering *, const struct battle *); - -void -battle_state_rendering_finish(struct battle_state_rendering *); - -void -battle_state_rendering(struct battle *, struct drawable *); - -#endif /* !MLK_RPG_BATTLE_STATE_RENDERING_H */
--- a/src/libmlk-rpg/rpg/battle-state-selection.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,231 +0,0 @@ -/* - * battle-state-selection.c -- battle state (selection) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> -#include <string.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/event.h> -#include <mlk/core/panic.h> -#include <mlk/core/sprite.h> -#include <mlk/core/util.h> - -#include <mlk/ui/theme.h> - -#include "battle-bar.h" -#include "battle-state-item.h" -#include "battle-state-menu.h" -#include "battle-state-selection.h" -#include "battle-state.h" -#include "battle.h" -#include "character.h" -#include "inventory.h" -#include "selection.h" -#include "spell.h" - -struct self { - struct battle_state_selection data; - struct battle_state state; -}; - -static void -select_adj_in(struct battle_state_selection *slt, struct battle_entity **entities, size_t entitiesz, int step) -{ - assert(slt->select.index_character != (unsigned int)-1); - - unsigned int newselection = slt->select.index_character; - - if (step < 0) { - while (newselection > 0) { - if (character_ok(entities[--newselection]->ch)) { - slt->select.index_character = newselection; - break; - } - } - } else { - while (newselection < entitiesz) { - if (character_ok(entities[++newselection]->ch)) { - slt->select.index_character = newselection; - break; - } - } - } -} - -static void -select_adj(struct battle_state_selection *slt, const struct battle *bt, int step) -{ - if (slt->select.index_side == 0) - select_adj_in(slt, bt->enemies, bt->enemiesz, step); - else - select_adj_in(slt, bt->team, bt->teamsz, step); -} - -static void -handle_keydown(struct battle_state_selection *stl, struct battle *bt, const union event *ev) -{ - assert(ev->type == EVENT_KEYDOWN); - - switch (ev->key.key) { - case KEY_ESCAPE: - battle_state_menu(bt); - break; - case KEY_ENTER: - battle_bar_select(bt->bar, bt, &stl->select); - break; - case KEY_LEFT: - if (stl->select.allowed_sides & SELECTION_SIDE_ENEMY) - stl->select.index_side = 0; - break; - case KEY_RIGHT: - if (stl->select.allowed_sides & SELECTION_SIDE_TEAM) - stl->select.index_side = 1; - break; - case KEY_UP: - select_adj(stl, bt, -1); - break; - case KEY_DOWN: - select_adj(stl, bt, +1); - break; - case KEY_TAB: - if (stl->select.allowed_kinds == SELECTION_KIND_BOTH) - stl->select.index_character = -1; - break; - default: - break; - } -} - -static void -draw_cursor(const struct battle *bt, const struct battle_entity *et) -{ - const struct theme *theme = BATTLE_THEME(bt); - const struct sprite *cursor = theme->sprites[THEME_SPRITE_CURSOR]; - int x, y; - unsigned int lh; - - if (!cursor) - return; - - label_query(&et->name, NULL, &lh); - - x = et->name.x - cursor->cellw - theme->padding; - y = et->name.y + (((int)(lh) - (int)(cursor->cellh)) / 2); - - sprite_draw(cursor, 1, 2, x, y); -} - -static void -draw_cursors(const struct battle *bt, - struct battle_entity * const *entities, - size_t entitiesz) -{ - for (size_t i = 0; i < entitiesz; ++i) { - const struct battle_entity *et = entities[i]; - - if (et && character_ok(et->ch)) - draw_cursor(bt, et); - } -} - -static void -handle(struct battle_state *st, struct battle *bt, const union event *ev) -{ - battle_state_selection_handle(st->data, bt, ev); -} - -static void -draw(const struct battle_state *st, const struct battle *bt) -{ - battle_state_selection_draw(st->data, bt); -} - -static void -finish(struct battle_state *st, struct battle *bt) -{ - (void)bt; - - free(st->data); -} - -void -battle_state_selection_init(struct battle_state_selection *stl, const struct selection *select) -{ - assert(stl); - assert(select); - - memcpy(&stl->select, select, sizeof (*select)); -} - -void -battle_state_selection_handle(struct battle_state_selection *stl, struct battle *bt, const union event *ev) -{ - assert(stl); - assert(bt); - assert(ev); - - switch (ev->type) { - case EVENT_KEYDOWN: - handle_keydown(stl, bt, ev); - break; - default: - break; - } -} - -void -battle_state_selection_draw(const struct battle_state_selection *stl, const struct battle *bt) -{ - assert(stl); - assert(bt); - - battle_draw_component(bt, BATTLE_COMPONENT_ALL); - - if (stl->select.index_character == -1U) { - /* All selected. */ - if (stl->select.index_side == 0) - draw_cursors(bt, bt->enemies, bt->enemiesz); - else - draw_cursors(bt, bt->team, bt->teamsz); - } else { - /* Select one. */ - if (stl->select.index_side == 0) - draw_cursor(bt, bt->enemies[stl->select.index_character]); - else - draw_cursor(bt, bt->team[stl->select.index_character]); - } -} - -void -battle_state_selection(struct battle *bt, const struct selection *select) -{ - assert(bt); - assert(select); - - struct self *self; - - self = alloc_new0(sizeof (*self)); - self->state.data = self; - self->state.handle = handle; - self->state.draw = draw; - self->state.finish = finish; - - battle_state_selection_init(&self->data, select); - battle_switch(bt, &self->state); -}
--- a/src/libmlk-rpg/rpg/battle-state-selection.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * battle-state-selection.h -- battle state (selection) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_STATE_SELECTION_H -#define MLK_RPG_BATTLE_STATE_SELECTION_H - -#include <rpg/selection.h> - -struct battle; - -union event; - -struct battle_state_selection { - struct selection select; -}; - -void -battle_state_selection_init(struct battle_state_selection *, const struct selection *); - -void -battle_state_selection_handle(struct battle_state_selection *, struct battle *, const union event *); - -void -battle_state_selection_draw(const struct battle_state_selection *, const struct battle *); - -void -battle_state_selection(struct battle *, const struct selection *); - -#endif /* !MLK_RPG_BATTLE_STATE_SELECTION_H */
--- a/src/libmlk-rpg/rpg/battle-state-victory.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -/* - * battle-state-victory.c -- battle state (victory) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/music.h> -#include <mlk/core/panic.h> -#include <mlk/core/window.h> - -#include "battle-state-closing.h" -#include "battle-state-victory.h" -#include "battle-state.h" -#include "battle.h" - -struct self { - struct battle_state_victory data; - struct battle_state state; -}; - -static void -handle(struct battle_state *st, struct battle *bt, const union event *ev) -{ - (void)bt; - - battle_state_victory_handle(st->data, ev); -} - -static int -update(struct battle_state *st, struct battle *bt, unsigned int ticks) -{ - (void)bt; - - return battle_state_victory_update(st->data, bt, ticks); -} - -static void -draw(const struct battle_state *st, const struct battle *bt) -{ - (void)bt; - - battle_state_victory_draw(st->data, bt); -} - -void -battle_state_victory_init(struct battle_state_victory *vic, struct battle *bt) -{ - assert(bt); - - vic->text = "Victory!"; - - vic->msg.lines = &vic->text; - vic->msg.linesz = 1; - vic->msg.theme = bt->theme; - vic->msg.flags = MESSAGE_FLAGS_AUTOMATIC | - MESSAGE_FLAGS_FADEIN | - MESSAGE_FLAGS_FADEOUT; - vic->msg.timeout = MESSAGE_TIMEOUT_DEFAULT; - vic->msg.delay = MESSAGE_DELAY_DEFAULT; - - message_start(&vic->msg); - message_query(&vic->msg, NULL, &vic->msg.h); - - vic->msg.w = window.w * 0.6; - vic->msg.y = window.h * 0.1; - vic->msg.x = (window.w - vic->msg.w) / 2; - - bt->status = BATTLE_STATUS_WON; - - if (bt->music[1]) - music_play(bt->music[1], MUSIC_NONE); -} - -void -battle_state_victory_handle(struct battle_state_victory *vic, const union event *ev) -{ - assert(vic); - - message_handle(&vic->msg, ev); -} - -int -battle_state_victory_update(struct battle_state_victory *vic, struct battle *bt, unsigned int ticks) -{ - assert(vic); - assert(bt); - - battle_update_component(bt, BATTLE_COMPONENT_ALL, ticks); - - if (message_update(&vic->msg, ticks)) - battle_state_closing(bt); - - return 0; -} - -void -battle_state_victory_draw(const struct battle_state_victory *vic, const struct battle *bt) -{ - assert(vic); - - battle_draw_component(bt, BATTLE_COMPONENT_ALL); - message_draw(&vic->msg); -} - -void -battle_state_victory(struct battle *bt) -{ - assert(bt); - - struct self *self; - - /* TODO: compute money, xp and drop. */ - self = alloc_new0(sizeof (*self)); - self->state.data = self; - self->state.handle = handle; - self->state.update = update; - self->state.draw = draw; - - battle_state_victory_init(&self->data, bt); - battle_switch(bt, &self->state); -}
--- a/src/libmlk-rpg/rpg/battle-state-victory.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * battle-state-victory.h -- battle state (victory) - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_STATE_VICTORY_H -#define MLK_RPG_BATTLE_STATE_VICTORY_H - -#include <rpg/message.h> - -struct battle; - -union event; - -struct battle_state_victory { - const char *text; - struct message msg; -}; - -void -battle_state_victory_init(struct battle_state_victory *, struct battle *); - -void -battle_state_victory_handle(struct battle_state_victory *, const union event *); - -int -battle_state_victory_update(struct battle_state_victory *, struct battle *, unsigned int); - -void -battle_state_victory_draw(const struct battle_state_victory *, const struct battle *); - -void -battle_state_victory(struct battle *); - -#endif /* !MLK_RPG_BATTLE_STATE_VICTORY_H */
--- a/src/libmlk-rpg/rpg/battle-state.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * battle-state.c -- battle abstract state - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include "battle-state.h" - -void -battle_state_handle(struct battle_state *st, struct battle *bt, const union event *ev) -{ - assert(st); - assert(bt); - assert(ev); - - if (st->handle) - st->handle(st, bt, ev); -} - -int -battle_state_update(struct battle_state *st, struct battle *bt, unsigned int ticks) -{ - assert(st); - assert(bt); - - if (st->update) - return st->update(st, bt, ticks); - - return 0; -} - -void -battle_state_draw(const struct battle_state *st, const struct battle *bt) -{ - assert(st); - assert(bt); - - if (st->draw) - st->draw(st, bt); -} - -void -battle_state_finish(struct battle_state *st, struct battle *bt) -{ - assert(st); - assert(bt); - - if (st->finish) - st->finish(st, bt); -}
--- a/src/libmlk-rpg/rpg/battle-state.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * battle-state.h -- battle abstract state - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_STATE_H -#define MLK_RPG_BATTLE_STATE_H - -#include <mlk/core/core.h> - -struct battle; -struct character; -struct inventory_slot; -struct selection; - -union event; - -struct battle_state { - void *data; - void (*handle)(struct battle_state *, struct battle *, const union event *); - int (*update)(struct battle_state *, struct battle *, unsigned int); - void (*draw)(const struct battle_state *, const struct battle *); - void (*finish)(struct battle_state *, struct battle *); -}; - -CORE_BEGIN_DECLS - -void -battle_state_handle(struct battle_state *, struct battle *, const union event *); - -int -battle_state_update(struct battle_state *, struct battle *, unsigned int); - -void -battle_state_draw(const struct battle_state *, const struct battle *); - -void -battle_state_finish(struct battle_state *, struct battle *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_BATTLE_STATE_H */
--- a/src/libmlk-rpg/rpg/battle.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,502 +0,0 @@ -/* - * battle.c -- battles - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/event.h> -#include <mlk/core/font.h> -#include <mlk/core/music.h> -#include <mlk/core/sprite.h> -#include <mlk/core/texture.h> -#include <mlk/core/trace.h> -#include <mlk/core/util.h> -#include <mlk/core/window.h> - -#include <mlk/ui/align.h> -#include <mlk/ui/frame.h> -#include <mlk/ui/label.h> -#include <mlk/ui/theme.h> - -#include "battle-bar.h" -#include "battle-indicator.h" -#include "battle-state-ai.h" -#include "battle-state-attacking.h" -#include "battle-state-check.h" -#include "battle-state-menu.h" -#include "battle-state-opening.h" -#include "battle-state.h" -#include "battle.h" -#include "character.h" -#include "inventory.h" -#include "item.h" -#include "spell.h" - -struct indicator { - struct drawable dw; - struct battle_indicator bti; -}; - -static int -indicator_update(struct drawable *dw, unsigned int ticks) -{ - struct indicator *id = dw->data; - - return battle_indicator_update(&id->bti, ticks); -} - -static void -indicator_draw(struct drawable *dw) -{ - const struct indicator *id = dw->data; - - battle_indicator_draw(&id->bti, dw->x, dw->y); -} - -static void -indicator_free(struct drawable *dw) -{ - struct indicator *id = dw->data; - - battle_indicator_finish(&id->bti); - free(id); -} - -static struct battle_entity * -find(struct battle *bt, const struct character *ch) -{ - struct battle_entity *et; - - BATTLE_TEAM_FOREACH(bt, et) - if (et->ch == ch) - return et; - BATTLE_ENEMY_FOREACH(bt, et) - if (et->ch == ch) - return et; - - return NULL; -} - -static struct battle_entity * -random_select(struct battle_entity **group, size_t groupsz) -{ - struct battle_entity *ret = NULL, *et = NULL; - - do { - et = group[util_nrand(0, groupsz - 1)]; - - if (et && et->ch) - ret = et; - } while (!ret); - - return ret; -} - -static int -cmp_order(const void *d1, const void *d2) -{ - const struct battle_entity *et1 = *(const struct battle_entity **)d1; - const struct battle_entity *et2 = *(const struct battle_entity **)d2; - - return et2->ch->agt < et1->ch->agt; -} - -static int -is_team(const struct battle *bt, const struct character *ch) -{ - for (size_t i = 0; i < bt->teamsz; ++i) - if (bt->team[i] && bt->team[i]->ch == ch) - return 1; - - return 0; -} - -static void -positionate_name(struct battle_entity *et, const struct battle *bt) -{ - unsigned int lw; - struct sprite *sprite; - - /* Show the character name below its sprite. */ - sprite = et->ch->sprites[CHARACTER_SPRITE_NORMAL]; - - et->name.text = et->ch->name; - et->name.flags = LABEL_FLAGS_SHADOW; - label_query(&et->name, &lw, NULL); - et->name.y = et->y + sprite->cellh + BATTLE_THEME(bt)->padding; - et->name.x = et->x + (sprite->cellw / 2) - (lw / 2); -} - -static void -positionate_names(struct battle *bt) -{ - struct battle_entity *et; - - BATTLE_TEAM_FOREACH(bt, et) - if (character_ok(et->ch)) - positionate_name(et, bt); - BATTLE_ENEMY_FOREACH(bt, et) - if (character_ok(et->ch)) - positionate_name(et, bt); -} - -static void -positionate_team(struct battle *bt) -{ - struct battle_entity *et; - unsigned int requirement = 0, nmemb = 0, spacing; - int x, y; - - BATTLE_TEAM_FOREACH(bt, et) { - /* Stop in case any member of the team has been positionated. */ - if (et->x != 0 || et->y != 0) - return; - - if (battle_entity_ok(bt->team[i])) { - nmemb++; - requirement += et->ch->sprites[CHARACTER_SPRITE_NORMAL]->cellh; - } - } - - /* TODO: compute a correct x placement. */ - spacing = (window.h - requirement) / (nmemb + 1); - x = window.w - 200; - y = spacing; - - BATTLE_TEAM_FOREACH(bt, et) { - if (battle_entity_ok(et)) { - et->x = x; - et->y = y; - y += et->ch->sprites[CHARACTER_SPRITE_NORMAL]->cellh + spacing; - } - } -} - -static void -draw_entities(const struct battle *bt, struct battle_entity **entities, size_t entitiesz) -{ - for (size_t i = 0; i < entitiesz; ++i) { - if (battle_entity_ok(entities[i])) - battle_entity_draw(entities[i], bt); - } -} - -static void -update_entities(struct battle_entity **entities, size_t entitiesz, unsigned int ticks) -{ - for (size_t i = 0; i < entitiesz; ++i) { - if (battle_entity_ok(entities[i])) - battle_entity_update(entities[i], ticks); - } -} - -void -battle_init(struct battle *bt) -{ - assert(bt); - - memset(bt, 0, sizeof (*bt)); -} - -int -battle_ok(const struct battle *bt) -{ - return bt && bt->state && bt->bar && bt->enemiesz && bt->team; -} - -void -battle_start(struct battle *bt) -{ - assert(bt); - - struct battle_entity *et; - - BATTLE_TEAM_FOREACH(bt, et) - if (battle_entity_ok(et)) - battle_entity_init(et); - BATTLE_ENEMY_FOREACH(bt, et) - if (battle_entity_ok(et)) - battle_entity_init(et); - - positionate_team(bt); - positionate_names(bt); - - /* Start the state "opening" animation. */ - battle_state_opening(bt); - - /* Play music if present. */ - if (bt->music[0]) - music_play(bt->music[0], MUSIC_LOOP); - - battle_order(bt); -} - -void -battle_switch(struct battle *bt, struct battle_state *st) -{ - assert(bt); - assert(st); - - if (bt->state) - battle_state_finish(bt->state, bt); - - bt->state = st; -} - -void -battle_order(struct battle *bt) -{ - struct battle_entity **porder; - - /* Create a pointer list to every entity. */ - bt->order = alloc_rearray0(bt->order, bt->ordersz, - bt->teamsz + bt->enemiesz, sizeof (*bt->order)); - bt->ordersz = bt->teamsz + bt->enemiesz; - bt->ordercur = porder = bt->order; - - for (size_t i = 0; i < bt->teamsz; ++i) - if (bt->team[i] && character_ok(bt->team[i]->ch)) - *porder++ = bt->team[i]; - for (size_t i = 0; i < bt->enemiesz; ++i) - if (bt->enemies[i] && character_ok(bt->enemies[i]->ch)) - *porder++ = bt->enemies[i]; - - /* Now sort. */ - qsort(bt->order, bt->ordersz, sizeof (*bt->order), cmp_order); -} - -struct battle_entity * -battle_current(const struct battle *bt) -{ - assert(bt); - - return *bt->ordercur; -} - -size_t -battle_index(const struct battle *bt) -{ - assert(bt); - - return bt->ordercur - bt->order; -} - -void -battle_attack(struct battle *bt, - struct character *source, - struct character *target) -{ - assert(bt); - assert(character_ok(source)); - - /* Target is empty? select randomly. */ - if (!target) { - if (is_team(bt, source)) - target = random_select(bt->enemies, bt->enemiesz)->ch; - else - target = random_select(bt->team, bt->teamsz)->ch; - } - - battle_state_attacking(battle_find(bt, source), battle_find(bt, target), bt); -} - -void -battle_cast(struct battle *bt, - struct character *source, - const struct spell *spell, - const struct selection *selection) -{ - assert(bt); - assert(source); - assert(spell); - assert((unsigned int)source->mp >= spell->mp); - - /* TODO: animate. */ - source->mp -= spell->mp; - spell_action(spell, bt, source, selection); -} - -void -battle_use(struct battle *bt, const struct item *item, struct character *owner, struct character *target) -{ - assert(bt); - assert(item); - assert(owner); - assert(target); - - /* - * Change the state to check prior to execute the item so it can change to something else - * if needed. - */ - battle_state_check(bt); - - inventory_consume(bt->inventory, item, 1); - item_exec_battle(item, bt, owner, target); -} - -void -battle_next(struct battle *bt) -{ - assert(bt); - - if (!bt->ordercur) - battle_order(bt); - else { - if (bt->ordercur - bt->order + (size_t)1U >= bt->ordersz) - battle_order(bt); - else - bt->ordercur++; - } - - if (is_team(bt, battle_current(bt)->ch)) { - battle_bar_start(bt->bar, bt); - battle_state_menu(bt); - } else - battle_state_ai(bt); -} - -struct battle_entity * -battle_find(struct battle *bt, const struct character *ch) -{ - assert(bt); - - return find(bt, ch); -} - -void -battle_indicator_hp(struct battle *bt, const struct character *target, long amount) -{ - assert(bt); - assert(target); - - const struct battle_entity *et = find(bt, target); - struct indicator *id; - - if (!(bt->effects)) { - tracef("unable to add id without a drawable_stack"); - return; - } - - id = alloc_new0(sizeof (*id)); - id->bti.color = BATTLE_INDICATOR_HP_COLOR; - id->bti.amount = labs(amount); - - /* TODO: positionate better. */ - id->dw.x = et->x + target->sprites[CHARACTER_SPRITE_NORMAL]->cellw; - id->dw.y = et->y + target->sprites[CHARACTER_SPRITE_NORMAL]->cellh; - id->dw.data = id; - id->dw.update = indicator_update; - id->dw.draw = indicator_draw; - id->dw.finish = indicator_free; - - battle_indicator_start(&id->bti); - - if (drawable_stack_add(bt->effects, &id->dw) < 0) - drawable_finish(&id->dw); -} - -void -battle_handle_component(struct battle *bt, const union event *ev, enum battle_component comp) -{ - assert(bt); - assert(ev); - - if (comp & BATTLE_COMPONENT_BAR) - battle_bar_handle(bt->bar, bt, ev); - if ((comp & BATTLE_COMPONENT_ACTIONS) && bt->actions) - action_stack_handle(bt->actions, ev); -} - -void -battle_handle(struct battle *bt, const union event *ev) -{ - assert(bt); - assert(ev); - - battle_state_handle(bt->state, bt, ev); -} - -void -battle_update_component(struct battle *bt, unsigned int ticks, enum battle_component comp) -{ - assert(bt); - - if (comp & BATTLE_COMPONENT_ENTITIES) { - update_entities(bt->team, bt->teamsz, ticks); - update_entities(bt->enemies, bt->enemiesz, ticks); - } - if (comp & BATTLE_COMPONENT_BAR) - battle_bar_update(bt->bar, bt, ticks); - if ((comp & BATTLE_COMPONENT_ACTIONS) && bt->actions) - action_stack_update(bt->actions, ticks); - if ((comp & BATTLE_COMPONENT_DRAWABLES) && bt->effects) - drawable_stack_update(bt->effects, ticks); -} - -int -battle_update(struct battle *bt, unsigned int ticks) -{ - assert(bt && bt->state); - - return battle_state_update(bt->state, bt, ticks); -} - -void -battle_draw_component(const struct battle *bt, enum battle_component comp) -{ - assert(bt); - - if ((comp & BATTLE_COMPONENT_BACKGROUND) && texture_ok(bt->background)) - texture_scale(bt->background, - 0, 0, bt->background->w, bt->background->h, - 0, 0, window.w, window.h, - 0.f); - if (comp & BATTLE_COMPONENT_ENTITIES) { - draw_entities(bt, bt->team, bt->teamsz); - draw_entities(bt, bt->enemies, bt->enemiesz); - } - if (comp & BATTLE_COMPONENT_BAR) - battle_bar_draw(bt->bar, bt); - if ((comp & BATTLE_COMPONENT_ACTIONS) && bt->actions) - action_stack_draw(bt->actions); - if ((comp & BATTLE_COMPONENT_DRAWABLES) && bt->effects) - drawable_stack_draw(bt->effects); -} - -void -battle_draw(const struct battle *bt) -{ - assert(battle_ok(bt)); - - battle_state_draw(bt->state, bt); -} - -void -battle_finish(struct battle *bt) -{ - assert(bt); - - if (bt->state) - battle_state_finish(bt->state, bt); - - free(bt->order); - memset(bt, 0, sizeof (*bt)); -}
--- a/src/libmlk-rpg/rpg/battle.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -/* - * battle.h -- battles - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_BATTLE_H -#define MLK_RPG_BATTLE_H - -#include <mlk/core/action.h> -#include <mlk/core/action-stack.h> -#include <mlk/core/core.h> -#include <mlk/core/drawable.h> -#include <mlk/core/drawable-stack.h> - -#include <mlk/ui/frame.h> -#include <mlk/ui/gridmenu.h> - -#include "battle-entity.h" -#include "battle-state.h" -#include "selection.h" -#include "spell.h" - -union event; - -struct battle_bar; -struct character; -struct inventory; -struct item; -struct music; -struct selection; -struct spell; -struct theme; - -#define BATTLE_TEAM_FOREACH(bt, iter) \ - for (size_t i = 0; i < (bt)->teamsz && ((iter) = (bt)->team[i]); ++i) -#define BATTLE_ENEMY_FOREACH(bt, iter) \ - for (size_t i = 0; i < (bt)->enemiesz && ((iter) = (bt)->enemies[i]); ++i) - -#define BATTLE_THEME(bt) ((bt)->theme ? (bt)->theme : theme_default()) - -enum battle_status { - BATTLE_STATUS_NONE, - BATTLE_STATUS_RUNNING, - BATTLE_STATUS_WON, - BATTLE_STATUS_LOST, -}; - -enum battle_component { - BATTLE_COMPONENT_BACKGROUND = (1 << 0), - BATTLE_COMPONENT_ENTITIES = (1 << 1), - BATTLE_COMPONENT_BAR = (1 << 2), - BATTLE_COMPONENT_ACTIONS = (1 << 3), - BATTLE_COMPONENT_DRAWABLES = (1 << 4), - BATTLE_COMPONENT_ALL = 0xff -}; - -struct battle { - struct battle_state *state; - enum battle_status status; - struct battle_entity **team; - size_t teamsz; - struct battle_entity **enemies; - size_t enemiesz; - struct battle_entity **order; - struct battle_entity **ordercur; - size_t ordersz; - struct texture *background; - struct music *music[3]; - struct theme *theme; - struct drawable_stack *effects; - struct action_stack *actions; - struct inventory *inventory; - struct battle_bar *bar; -}; - -CORE_BEGIN_DECLS - -void -battle_init(struct battle *); - -int -battle_ok(const struct battle *); - -void -battle_start(struct battle *); - -void -battle_next(struct battle *); - -struct battle_entity * -battle_find(struct battle *, const struct character *); - -void -battle_switch(struct battle *, struct battle_state *); - -void -battle_order(struct battle *); - -struct battle_entity * -battle_current(const struct battle *); - -size_t -battle_index(const struct battle *); - -void -battle_attack(struct battle *, struct character *, struct character *); - -void -battle_cast(struct battle *, struct character *, const struct spell *, const struct selection *); - -void -battle_use(struct battle *, const struct item *, struct character *, struct character *); - -void -battle_indicator_hp(struct battle *, const struct character *, long); - -void -battle_handle_component(struct battle *, const union event *, enum battle_component); - -void -battle_handle(struct battle *, const union event *); - -void -battle_update_component(struct battle *, unsigned int, enum battle_component); - -int -battle_update(struct battle *, unsigned int); - -void -battle_draw_component(const struct battle *, enum battle_component); - -void -battle_draw(const struct battle *); - -void -battle_finish(struct battle *); - -CORE_END_DECLS - -#endif /* MLK_RPG_BATTLE_H */
--- a/src/libmlk-rpg/rpg/character.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -/* - * character.c -- character definition - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include <mlk/core/sprite.h> - -#include <assets/sql/character-save.h> -#include <assets/sql/character-load.h> - -#include "character.h" -#include "equipment.h" -#include "save.h" - -int -character_ok(const struct character *ch) -{ - return ch && ch->name && ch->reset && sprite_ok(ch->sprites[CHARACTER_SPRITE_NORMAL]); -} - -const char * -character_status_string(enum character_status status) -{ - /* - * We expect the user to only specify one status as character_status - * is a bitmask. - */ - switch (status) { - case CHARACTER_STATUS_POISON: - return "poison"; - default: - return "normal"; - } -} - -void -character_reset(struct character *ch) -{ - assert(character_ok(ch)); - - ch->reset(ch); - - /* For all equipments, apply its equip function. */ - for (int i = 0; i < CHARACTER_EQUIPMENT_NUM; ++i) - if (ch->equipments[i]) - equipment_equip(ch->equipments[i], ch); -} - -void -character_exec(struct character *ch, struct battle *bt) -{ - assert(character_ok(ch)); - - if (ch->exec) - ch->exec(ch, bt); -} - -int -character_save(const struct character *ch, struct save *s) -{ - assert(ch); - assert(save_ok(s)); - - return save_exec(s, (const char *)assets_character_save, "s iii i iiiiii", - ch->name, - ch->hp, - ch->mp, - ch->level, - ch->team_order, - ch->hpbonus, - ch->mpbonus, - ch->atkbonus, - ch->defbonus, - ch->agtbonus, - ch->luckbonus - ); -} - -int -character_load(struct character *ch, struct save *s) -{ - assert(ch); - assert(save_ok(s)); - - struct save_stmt stmt; - enum save_stmt_errno ret; - - if (save_stmt_init(&stmt, s, (const char *)assets_character_load, "s", ch->name) < 0) - return -1; - - ret = save_stmt_next(&stmt, "iii i iiiiii", - &ch->hp, - &ch->mp, - &ch->level, - &ch->team_order, - &ch->hpbonus, - &ch->mpbonus, - &ch->atkbonus, - &ch->defbonus, - &ch->agtbonus, - &ch->luckbonus - ) == SAVE_STMT_ROW; - - save_stmt_finish(&stmt); - - return ret ? 0 : -1; -}
--- a/src/libmlk-rpg/rpg/character.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/* - * character.h -- character definition - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_CHARACTER_H -#define MLK_RPG_CHARACTER_H - -#include <mlk/core/core.h> - -#define CHARACTER_SPELL_MAX (64) - -struct battle; -struct save; -struct sprite; -struct spell; - -enum character_status { - CHARACTER_STATUS_NORMAL, - CHARACTER_STATUS_POISON = (1 << 0) -}; - -enum character_sprite { - CHARACTER_SPRITE_AXE, - CHARACTER_SPRITE_BOW, - CHARACTER_SPRITE_CROSSBOW, - CHARACTER_SPRITE_DAGGER, - CHARACTER_SPRITE_HAMMER, - CHARACTER_SPRITE_NORMAL, - CHARACTER_SPRITE_SPIKE, - CHARACTER_SPRITE_SWORD, - CHARACTER_SPRITE_WAND, - CHARACTER_SPRITE_NUM -}; - -enum character_equipment { - CHARACTER_EQUIPMENT_GLOVES, - CHARACTER_EQUIPMENT_HELMET, - CHARACTER_EQUIPMENT_SHIELD, - CHARACTER_EQUIPMENT_TOP, - CHARACTER_EQUIPMENT_TROUSERS, - CHARACTER_EQUIPMENT_WEAPON, - CHARACTER_EQUIPMENT_NUM -}; - -struct character { - const char *name; - enum character_status status; - unsigned int level; - int hp; - unsigned int hpmax; - unsigned int hpbonus; - int mp; - unsigned int mpmax; - unsigned int mpbonus; - int atk; - unsigned int atkbonus; - int def; - unsigned int defbonus; - int agt; - unsigned int agtbonus; - int luck; - unsigned int luckbonus; - unsigned int team_order; - - struct sprite *sprites[CHARACTER_SPRITE_NUM]; - const struct equipment *equipments[CHARACTER_EQUIPMENT_NUM]; - const struct spell *spells[CHARACTER_SPELL_MAX]; - - void (*reset)(struct character *owner); - void (*exec)(struct character *owner, struct battle *bt); -}; - -CORE_BEGIN_DECLS - -int -character_ok(const struct character *ch); - -const char * -character_status_string(enum character_status status); - -void -character_reset(struct character *ch); - -void -character_exec(struct character *ch, struct battle *bt); - -int -character_save(const struct character *ch, struct save *s); - -int -character_load(struct character *, struct save *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_CHARACTER_H */
--- a/src/libmlk-rpg/rpg/equipment.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * equipment.h -- character equipment - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include "character.h" -#include "equipment.h" - -int -equipment_ok(const struct equipment *eq) -{ - return eq && eq->name && eq->description; -} - -void -equipment_equip(const struct equipment *eq, struct character *ch) -{ - assert(equipment_ok(eq)); - assert(character_ok(ch)); - - if (eq->equip) - eq->equip(eq, ch); -}
--- a/src/libmlk-rpg/rpg/equipment.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * equipment.h -- character equipment - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_EQUIPMENT_H -#define MLK_RPG_EQUIPMENT_H - -#include <mlk/core/core.h> - -struct character; -struct texture; - -enum equipment_type { - /* Attack weapons. */ - EQUIPMENT_TYPE_AXE, - EQUIPMENT_TYPE_BOW, - EQUIPMENT_TYPE_CROSSBOW, - EQUIPMENT_TYPE_DAGGER, - EQUIPMENT_TYPE_HAMMER, - EQUIPMENT_TYPE_SPIKE, - EQUIPMENT_TYPE_SWORD, - EQUIPMENT_TYPE_WAND, - - /* Defense equipment. */ - EQUIPMENT_TYPE_GLOVES, - EQUIPMENT_TYPE_HELMET, - EQUIPMENT_TYPE_SHIELD, - EQUIPMENT_TYPE_TOP, - EQUIPMENT_TYPE_TROUSERS, -}; - -struct equipment { - const char *name; - const char *description; - unsigned int price; - enum equipment_type type; - struct texture *icon; - - void (*equip)(const struct equipment *, struct character *); -}; - -CORE_BEGIN_DECLS - -int -equipment_ok(const struct equipment *); - -void -equipment_equip(const struct equipment *, struct character *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_EQUIPMENT_H */
--- a/src/libmlk-rpg/rpg/inventory.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * inventory.c -- item inventory - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stddef.h> - -#include "inventory.h" - -static struct inventory_slot * -find(struct inventory *iv, const struct item *item) -{ - for (size_t i = 0; i < INVENTORY_ITEM_MAX; ++i) - if (iv->items[i].item == item) - return &iv->items[i]; - - return NULL; -} - -int -inventory_add(struct inventory *iv, const struct item *item, unsigned int amount) -{ - assert(iv); - assert(item); - - struct inventory_slot *slot; - - /* Find one existing, otherwise find one empty. */ - if (!(slot = find(iv, item))) - slot = find(iv, NULL); - - if (!slot) - return 0; - - slot->item = item; - slot->amount += amount; - - return -1; -} - -void -inventory_consume(struct inventory *iv, const struct item *item, unsigned int amount) -{ - assert(iv); - assert(item); - - struct inventory_slot *slot; - - if ((slot = find(iv, item))) { - slot->amount -= amount; - - if (slot->amount == 0) - slot->item = NULL; - } -}
--- a/src/libmlk-rpg/rpg/inventory.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * inventory.h -- item inventory - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_INVENTORY_H -#define MLK_RPG_INVENTORY_H - -#include <mlk/core/core.h> - -#define INVENTORY_ITEM_MAX (512) - -struct item; - -struct inventory_slot { - unsigned int amount; - const struct item *item; -}; - -struct inventory { - struct inventory_slot items[INVENTORY_ITEM_MAX]; -}; - -CORE_BEGIN_DECLS - -int -inventory_add(struct inventory *, const struct item *, unsigned int); - -void -inventory_consume(struct inventory *, const struct item *, unsigned int); - -CORE_END_DECLS - -#endif /* !MLK_RPG_INVENTORY_H */
--- a/src/libmlk-rpg/rpg/item.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * item.c -- inventory items - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include "item.h" - -void -item_exec_menu(const struct item *item, struct character *ch) -{ - assert(item); - assert(ch); - - item->exec_menu(item, ch); -} - -void -item_exec_battle(const struct item *item, - struct battle *bt, - struct character *src, - struct character *tgt) -{ - assert(item); - assert(bt); - assert(src); - assert(tgt); - - item->exec_battle(item, bt, src, tgt); -}
--- a/src/libmlk-rpg/rpg/item.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * item.h -- inventory items - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_ITEM_H -#define MLK_RPG_ITEM_H - -#include <mlk/core/core.h> - -struct battle; -struct character; -struct texture; - -struct item { - const char *name; - const char *description; - struct texture *icon; - - void (*exec_menu)(const struct item *, struct character *); - - void (*exec_battle)(const struct item *, - struct battle *, - struct character *, - struct character *); -}; - -CORE_BEGIN_DECLS - -void -item_exec_menu(const struct item *, struct character *); - -void -item_exec_battle(const struct item *, - struct battle *, - struct character *, - struct character *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_ITEM_H */
--- a/src/libmlk-rpg/rpg/map-file.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,312 +0,0 @@ -/* - * map-file.c -- map file loader - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <errno.h> -#include <limits.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <mlk/util/util.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/error.h> -#include <mlk/core/image.h> -#include <mlk/core/trace.h> -#include <mlk/core/util.h> - -#include "map-file.h" - -#define MAX_F(v) MAX_F_(v) -#define MAX_F_(v) "%" #v "[^\n|]" - -struct context { - struct map_file *mf; /* Map loader. */ - struct map *map; /* Map object to fill. */ - FILE *fp; /* Map file pointer. */ - char basedir[PATH_MAX]; /* Parent map directory */ -}; - -static int -parse_layer_tiles(struct context *ctx, const char *layer_name) -{ - enum map_layer_type layer_type; - size_t amount, current; - - if (strcmp(layer_name, "background") == 0) - layer_type = MAP_LAYER_TYPE_BACKGROUND; - else if (strcmp(layer_name, "foreground") == 0) - layer_type = MAP_LAYER_TYPE_FOREGROUND; - else if (strcmp(layer_name, "above") == 0) - layer_type = MAP_LAYER_TYPE_ABOVE; - else - return errorf("invalid layer type: %s", layer_name); - - amount = ctx->map->columns * ctx->map->rows; - current = 0; - - /* - * The next line after a layer declaration is a list of plain integer - * that fill the layer tiles. - */ - if (!(ctx->mf->layers[layer_type].tiles = alloc_array0(amount, sizeof (unsigned short)))) - return -1; - - for (int tile; fscanf(ctx->fp, "%d\n", &tile) && current < amount; ++current) - ctx->mf->layers[layer_type].tiles[current] = tile; - - ctx->map->layers[layer_type].tiles = ctx->mf->layers[layer_type].tiles; - - return 0; -} - -static int -parse_actions(struct context *ctx) -{ - char exec[128 + 1]; - int x = 0, y = 0, block = 0; - unsigned int w = 0, h = 0; - - while (fscanf(ctx->fp, "%d|%d|%u|%u|%d|%128[^\n]\n", &x, &y, &w, &h, &block, exec) >= 5) { - struct map_block *reg; - - if (!ctx->mf->load_action) { - tracef("ignoring action %d,%d,%u,%u,%d,%s", x, y, w, h, block, exec); - continue; - } - - ctx->mf->load_action(ctx->map, x, y, w, h, exec); - - /* - * Actions do not have concept of collisions because they are - * not only used on maps. The map structure has its very own - * object to manage collisions but the .map file use the same - * directive for simplicity. So create a block region if the - * directive has one. - */ - if (block) { - if (!(reg = alloc_pool_new(&ctx->mf->blocks))) - return -1; - - reg->x = x; - reg->y = y; - reg->w = w; - reg->h = h; - } - } - - /* Reference the blocks array from map_file. */ - ctx->map->blocks = ctx->mf->blocks.data; - ctx->map->blocksz = ctx->mf->blocks.size; - - return 0; -} - -static int -parse_layer(struct context *ctx, const char *line) -{ - char layer_name[32 + 1] = {0}; - - /* Check if weight/height has been specified. */ - if (ctx->map->columns == 0 || ctx->map->rows == 0) - return errorf("missing map dimensions before layer"); - - /* Determine layer type. */ - if (sscanf(line, "layer|%32s", layer_name) <= 0) - return errorf("missing layer type definition"); - - if (strcmp(layer_name, "actions") == 0) - return parse_actions(ctx); - - return parse_layer_tiles(ctx, layer_name); -} - -static int -parse_tileset(struct context *ctx, const char *line) -{ - char path[PATH_MAX] = {0}, *p; - struct map_file *mf = ctx->mf; - struct tileset_file *tf = &mf->tileset_file; - - if (!(p = strchr(line, '|'))) - return errorf("could not parse tileset"); - - snprintf(path, sizeof (path), "%s/%s", ctx->basedir, p + 1); - - if (tileset_file_open(tf, &mf->tileset, path) < 0) - return -1; - - ctx->map->tileset = &mf->tileset; - - return 0; -} - -static int -parse_title(struct context *ctx, const char *line) -{ - if (sscanf(line, "title|" MAX_F(MAP_FILE_TITLE_MAX), ctx->mf->title) != 1 || strlen(ctx->mf->title) == 0) - return errorf("null map title"); - - ctx->map->title = ctx->mf->title; - - return 0; -} - -static int -parse_columns(struct context *ctx, const char *line) -{ - if (sscanf(line, "columns|%u", &ctx->map->columns) != 1 || ctx->map->columns == 0) - return errorf("null map columns"); - - return 0; -} - -static int -parse_rows(struct context *ctx, const char *line) -{ - if (sscanf(line, "rows|%u", &ctx->map->rows) != 1 || ctx->map->rows == 0) - return errorf("null map rows"); - - return 0; -} - -static int -parse_origin(struct context *ctx, const char *line) -{ - if (sscanf(line, "origin|%d|%d", &ctx->map->player_x, &ctx->map->player_y) != 2) - return errorf("invalid origin"); - - return 0; -} - -static int -parse_line(struct context *ctx, const char *line) -{ - static const struct { - const char *property; - int (*read)(struct context *, const char *); - } props[] = { - { "title", parse_title }, - { "columns", parse_columns }, - { "rows", parse_rows }, - { "tileset", parse_tileset }, - { "origin", parse_origin }, - { "layer", parse_layer }, - }; - - for (size_t i = 0; i < UTIL_SIZE(props); ++i) - if (strncmp(line, props[i].property, strlen(props[i].property)) == 0) - return props[i].read(ctx, line); - - return 0; -} - -static int -parse(struct context *ctx, const char *path) -{ - char line[1024]; - char basedir[PATH_MAX]; - - util_strlcpy(basedir, path, sizeof (basedir)); - util_strlcpy(ctx->basedir, util_dirname(basedir), sizeof (ctx->basedir)); - - while (fgets(line, sizeof (line), ctx->fp)) { - /* Remove \n if any */ - line[strcspn(line, "\r\n")] = '\0'; - - if (parse_line(ctx, line) < 0) - return -1; - } - - return 0; -} - -static int -check(struct map *map) -{ - /* - * Check that we have parsed every required components. - */ - if (!map->title) - return errorf("missing title"); - - /* - * We don't need to check width/height because parsing layers and - * tilesets already check for their presence, so only check layers. - */ - if (!map->layers[0].tiles) - return errorf("missing background layer"); - if (!map->layers[1].tiles) - return errorf("missing foreground layer"); - if (!tileset_ok(map->tileset)) - return errorf("missing tileset"); - - return 0; -} - -int -map_file_open(struct map_file *file, struct map *map, const char *path) -{ - assert(file); - assert(path); - assert(map); - - struct context ctx = { - .mf = file, - .map = map, - }; - int ret = 0; - - memset(map, 0, sizeof (*map)); - alloc_pool_init(&file->blocks, sizeof (*map->blocks), NULL); - - if (!(ctx.fp = fopen(path, "r"))) - goto fail; - if ((ret = parse(&ctx, path)) < 0 || (ret = check(map)) < 0) - goto fail; - - fclose(ctx.fp); - - return 0; - -fail: - map_finish(map); - map_file_finish(file); - - if (ctx.fp) - fclose(ctx.fp); - - return -1; -} - -void -map_file_finish(struct map_file *file) -{ - assert(file); - - free(file->layers[0].tiles); - free(file->layers[1].tiles); - free(file->layers[2].tiles); - - tileset_file_finish(&file->tileset_file); - alloc_pool_finish(&file->blocks); - - memset(file, 0, sizeof (*file)); -}
--- a/src/libmlk-rpg/rpg/map-file.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * map-file.h -- map file loader - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_MAP_FILE_H -#define MLK_RPG_MAP_FILE_H - -#include <mlk/core/alloc.h> -#include <mlk/core/core.h> -#include <mlk/core/sprite.h> -#include <mlk/core/texture.h> - -#include "map.h" -#include "tileset.h" -#include "tileset-file.h" - -#define MAP_FILE_TITLE_MAX 64 - -struct map_file { - void (*load_action)(struct map *, int, int, int, int, const char *); - - char title[MAP_FILE_TITLE_MAX]; - struct map_layer layers[MAP_LAYER_TYPE_NUM]; - struct tileset_file tileset_file; - struct tileset tileset; - struct alloc_pool blocks; -}; - -CORE_BEGIN_DECLS - -int -map_file_open(struct map_file *file, struct map *map, const char *path); - -void -map_file_finish(struct map_file *file); - -CORE_END_DECLS - -#endif /* !MLK_RPG_MAP_FILE_H */
--- a/src/libmlk-rpg/rpg/map.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,672 +0,0 @@ -/* - * map.c -- game map - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <mlk/core/error.h> -#include <mlk/core/event.h> -#include <mlk/core/image.h> -#include <mlk/core/maths.h> -#include <mlk/core/painter.h> -#include <mlk/core/sprite.h> -#include <mlk/core/sys.h> -#include <mlk/core/texture.h> -#include <mlk/core/window.h> - -#include <mlk/ui/debug.h> - -#include "map.h" -#include "tileset.h" - -/* - * This is the speed the player moves on the map. - * - * SPEED represents the number of pixels it must move per SEC. - * SEC simply represends the number of milliseconds in one second. - */ -#define SPEED 100 -#define SEC 1000 - -/* - * Those are margins within the edge of the screen. The camera always try to - * keep those padding between the player and the screen. - */ -#define MARGIN_WIDTH 160 -#define MARGIN_HEIGHT 90 - -#define WIDTH(map) ((map)->columns * (map)->tileset->sprite->cellw) -#define HEIGHT(map) ((map)->rows * (map)->tileset->sprite->cellh) - -/* - * This structure defines the possible movement of the player as flags since - * it's possible to make diagonal movements. - */ -enum movement { - MOVING_UP = 1 << 0, - MOVING_RIGHT = 1 << 1, - MOVING_DOWN = 1 << 2, - MOVING_LEFT = 1 << 3 -}; - -/* - * A bit of explanation within this array. The structure walksprite requires - * an orientation between 0-7 depending on the user direction. - * - * Since keys for moving the character may be pressed at the same time, we need - * a conversion table from "key pressed" to "orientation". - * - * When an orientation is impossible, it is set to -1. Example, when both left - * and right are pressed. - * - * MOVING_UP = 0001 = 0x1 - * MOVING_RIGHT = 0010 = 0x2 - * MOVING_DOWN = 0100 = 0x3 - * MOVING_LEFT = 1000 = 0x4 - */ -static unsigned int orientations[16] = { - [0x1] = 0, - [0x2] = 2, - [0x3] = 1, - [0x4] = 4, - [0x6] = 3, - [0x8] = 6, - [0x9] = 7, - [0xC] = 5 -}; - -/* - * Check if this block is usable for collision detection. For example if the - * player is moving upwards but the collision shape is below it is unnecessary - * to check. - */ -static int -is_block_relevant(const struct map *map, - const struct map_block *block, - int drow, - int dcol) -{ - if (drow) { - /* Object outside of left-right bounds. */ - if (block->x + (int)block->w <= map->player_x || - block->x >= map->player_x + (int)map->player_sprite->cellw) - return 0; - - if ((drow < 0 && block->y >= map->player_y + (int)map->player_sprite->cellh) || - (drow > 0 && block->y + block->h <= map->player_y + map->player_sprite->cellh)) - return 0; - } else if (dcol) { - /* Object outside of up-down bounds. */ - if (block->y + (int)block->h <= map->player_y || - block->y >= map->player_y + (int)map->player_sprite->cellh) - return 0; - - if ((dcol < 0 && block->x >= map->player_x + (int)map->player_sprite->cellw) || - (dcol > 0 && block->x + block->w <= map->player_x + map->player_sprite->cellw)) - return 0; - } - - return 1; -} - -/* - * Determine if this collision shape is "closer" to the player by checking the - * new block coordinates with the previous one. - */ -static int -is_block_better(const struct map_block *now, - const struct map_block *new, - int drow, - int dcol) -{ - return ((drow < 0 && new->y + new->h > now->y + now->h) || - (drow > 0 && new->y < now->y) || - (dcol < 0 && new->x + new->w > now->x + now->w) || - (dcol > 0 && new->x < now->x)); - -} - -static void -center(struct map *map) -{ - map->view_x = map->player_x - (int)(map->view_w / 2); - map->view_y = map->player_y - (int)(map->view_h / 2); - - if (map->view_x < 0) - map->view_x = 0; - else if ((unsigned int)map->view_x > WIDTH(map) - map->view_w) - map->view_x = WIDTH(map) - map->view_w; - - if (map->view_y < 0) - map->view_y = 0; - else if ((unsigned int)map->view_y > HEIGHT(map) - map->view_h) - map->view_y = HEIGHT(map) - map->view_h; -} - -static void -init(struct map *map) -{ - /* Adjust view. */ - map->view_w = window.w; - map->view_h = window.h; - - /* Adjust margin. */ - map->margin_w = map->view_w - (MARGIN_WIDTH * 2) - map->player_sprite->cellw; - map->margin_h = map->view_h - (MARGIN_HEIGHT * 2) - map->player_sprite->cellh; - - /* Center the view by default. */ - center(map); - - /* Final bits. */ - walksprite_init(&map->player_ws, map->player_sprite, 150); -} - -static void -handle_keydown(struct map *map, const union event *event) -{ - switch (event->key.key) { - case KEY_UP: - map->player_movement |= MOVING_UP; - break; - case KEY_RIGHT: - map->player_movement |= MOVING_RIGHT; - break; - case KEY_DOWN: - map->player_movement |= MOVING_DOWN; - break; - case KEY_LEFT: - map->player_movement |= MOVING_LEFT; - break; - default: - break; - } - - map->player_angle = orientations[map->player_movement]; -} - -static void -handle_keyup(struct map *map, const union event *event) -{ - switch (event->key.key) { - case KEY_TAB: - map->flags ^= MAP_FLAGS_SHOW_GRID | MAP_FLAGS_SHOW_COLLIDE; - break; - case KEY_UP: - map->player_movement &= ~(MOVING_UP); - break; - case KEY_RIGHT: - map->player_movement &= ~(MOVING_RIGHT); - break; - case KEY_DOWN: - map->player_movement &= ~(MOVING_DOWN); - break; - case KEY_LEFT: - map->player_movement &= ~(MOVING_LEFT); - break; - default: - break; - } -} - -static int -cmp_tile(const struct tileset_tiledef *td1, const struct tileset_tiledef *td2) -{ - if (td1->id < td2->id) - return -1; - if (td1->id > td2->id) - return 1; - - return 0; -} - -static struct tileset_tiledef * -find_tiledef_by_id(const struct map *map, unsigned short id) -{ - typedef int (*cmp)(const void *, const void *); - - const struct tileset_tiledef key = { - .id = id - }; - - return bsearch(&key, map->tileset->tiledefs, map->tileset->tiledefsz, - sizeof (key), (cmp)cmp_tile); -} - -static struct tileset_tiledef * -find_tiledef_by_row_column_in_layer(const struct map *map, - const struct map_layer *layer, - int row, - int col) -{ - unsigned short id; - - if (row < 0 || (unsigned int)row >= map->rows || - col < 0 || (unsigned int)col >= map->columns) - return 0; - - if ((id = layer->tiles[col + row * map->columns]) == 0) - return NULL; - - return find_tiledef_by_id(map, id - 1); -} - -static struct tileset_tiledef * -find_tiledef_by_row_column(const struct map *map, int row, int col) -{ - struct tileset_tiledef *tile; - - /* TODO: probably a for loop when we have indefinite layers. */ - if (!(tile = find_tiledef_by_row_column_in_layer(map, &map->layers[1], row, col))) - tile = find_tiledef_by_row_column_in_layer(map, &map->layers[0], row, col); - - return tile; -} - -static void -find_block_iterate(const struct map *map, - struct map_block *block, - int rowstart, - int rowend, - int colstart, - int colend, - int drow, - int dcol) -{ - assert(map); - assert(block); - - /* First, check with tiledefs. */ - for (int r = rowstart; r <= rowend; ++r) { - for (int c = colstart; c <= colend; ++c) { - struct tileset_tiledef *td; - struct map_block tmp; - - if (!(td = find_tiledef_by_row_column(map, r, c))) - continue; - - /* Convert to absolute values. */ - tmp.x = td->x + c * map->tileset->sprite->cellw; - tmp.y = td->y + r * map->tileset->sprite->cellh; - tmp.w = td->w; - tmp.h = td->h; - - /* This tiledef is out of context. */ - if (!is_block_relevant(map, &tmp, drow, dcol)) - continue; - - if (is_block_better(block, &tmp, drow, dcol)) { - block->x = tmp.x; - block->y = tmp.y; - block->w = tmp.w; - block->h = tmp.h; - } - } - } - - /* Now check if there are objects closer than tiledefs. */ - for (size_t i = 0; i < map->blocksz; ++i) { - const struct map_block *new = &map->blocks[i]; - - if (is_block_relevant(map, new, drow, dcol) && - is_block_better(block, new, drow, dcol)) { - block->x = new->x; - block->y = new->y; - block->w = new->w; - block->h = new->h; - } - } -} - -static void -find_collision(const struct map *map, struct map_block *block, int drow, int dcolumn) -{ - assert((drow && !dcolumn) || (dcolumn && !drow)); - - const int playercol = map->player_x / map->tileset->sprite->cellw; - const int playerrow = map->player_y / map->tileset->sprite->cellh; - const int ncols = (map->player_sprite->cellw / map->tileset->sprite->cellw) + 1; - const int nrows = (map->player_sprite->cellh / map->tileset->sprite->cellh) + 1; - int rowstart, rowend, colstart, colend; - - if (drow) { - colstart = playercol; - colend = playercol + ncols; - - if (drow < 0) { - /* Moving UP. */ - rowstart = 0; - rowend = playerrow; - block->x = block->y = block->h = 0; - block->w = WIDTH(map); - } else { - /* Moving DOWN. */ - rowstart = playerrow; - rowend = HEIGHT(map); - block->x = block->h = 0; - block->y = HEIGHT(map); - block->w = WIDTH(map); - } - } else { - rowstart = playerrow; - rowend = playerrow + nrows; - - if (dcolumn < 0) { - /* Moving LEFT. */ - colstart = 0; - colend = playercol; - block->x = block->y = block->w = 0; - block->h = HEIGHT(map); - } else { - /* Moving RIGHT. */ - colstart = playercol; - colend = WIDTH(map); - block->x = WIDTH(map); - block->y = block->w = 0; - block->h = block->h; - } - } - - find_block_iterate(map, block, rowstart, rowend, colstart, colend, drow, dcolumn); -} - -static void -move_x(struct map *map, int delta) -{ - struct map_block block; - - find_collision(map, &block, 0, delta < 0 ? -1 : +1); - - if (delta < 0 && map->player_x + delta < (int)(block.x + block.w)) - delta = map->player_x - block.x - block.w; - else if (delta > 0 && (int)(map->player_x + map->player_sprite->cellw + delta) >= block.x) - delta = block.x - map->player_x - (int)(map->player_sprite->cellw); - - map->player_x += delta; - - if ((delta < 0 && map->player_x < map->margin_x) || - (delta > 0 && map->player_x >= (int)(map->margin_x + map->margin_w))) - map->view_x += delta; - - if (map->view_x < 0) - map->view_x = 0; - else if (map->view_x >= (int)(WIDTH(map) - map->view_w)) - map->view_x = WIDTH(map) - map->view_w; -} - -static void -move_y(struct map *map, int delta) -{ - struct map_block block; - - find_collision(map, &block, delta < 0 ? -1 : +1, 0); - - if (delta < 0 && map->player_y + delta < (int)(block.y + block.h)) - delta = map->player_y - block.y - block.h; - else if (delta > 0 && (int)(map->player_y + map->player_sprite->cellh + delta) >= block.y) - delta = block.y - map->player_y - (int)(map->player_sprite->cellh); - - map->player_y += delta; - - if ((delta < 0 && map->player_y < map->margin_y) || - (delta > 0 && map->player_y >= (int)(map->margin_y + map->margin_h))) - map->view_y += delta; - - if (map->view_y < 0) - map->view_y = 0; - else if (map->view_y >= (int)(HEIGHT(map) - map->view_h)) - map->view_y = HEIGHT(map) - map->view_h; -} - -static void -move(struct map *map, unsigned int ticks) -{ - /* This is the amount of pixels the player must move. */ - const int delta = SPEED * ticks / SEC; - - /* This is the rectangle within the view where users must be. */ - map->margin_x = map->view_x + MARGIN_WIDTH; - map->margin_y = map->view_y + MARGIN_HEIGHT; - - int dx = 0; - int dy = 0; - - if (map->player_movement == 0) - return; - - if (map->player_movement & MOVING_UP) - dy = -1; - if (map->player_movement & MOVING_DOWN) - dy = 1; - if (map->player_movement & MOVING_LEFT) - dx = -1; - if (map->player_movement & MOVING_RIGHT) - dx = 1; - - /* Move the player and adjust view if needed. */ - if (dx) - move_x(map, dx * delta); - if (dy) - move_y(map, dy * delta); - - walksprite_update(&map->player_ws, ticks); -} - -static inline void -draw_layer_tile(const struct map *map, - const struct map_layer *layer, - struct texture *colbox, - int start_col, - int start_row, - int start_x, - int start_y, - unsigned int r, - unsigned int c) -{ - const struct tileset_tiledef *td; - int index, id, sc, sr, mx, my; - - index = (start_col + c) + ((start_row + r) * map->columns); - - if ((id = layer->tiles[index]) == 0) - return; - - id -= 1; - - /* Sprite row/column. */ - sc = (id) % map->tileset->sprite->ncols; - sr = (id) / map->tileset->sprite->ncols; - - /* On screen coordinates. */ - mx = start_x + (int)c * (int)map->tileset->sprite->cellw; - my = start_y + (int)r * (int)map->tileset->sprite->cellh; - - tileset_draw(map->tileset, sr, sc, mx, my); - - if ((td = find_tiledef_by_id(map, id)) && texture_ok(colbox)) - texture_scale(colbox, 0, 0, 5, 5, mx + td->x, my + td->y, td->w, td->h, 0); - - if (map->flags & MAP_FLAGS_SHOW_GRID) { - painter_set_color(0x202e37ff); - painter_draw_line(mx, my, mx + (int)map->tileset->sprite->cellw, my); - painter_draw_line( - mx + (int)map->tileset->sprite->cellw - 1, my, - mx + (int)map->tileset->sprite->cellw - 1, my + (int)map->tileset->sprite->cellh); - } -} - -static void -draw_layer(const struct map *map, const struct map_layer *layer) -{ - assert(map); - assert(layer); - - /* Beginning of view in row/column. */ - const unsigned int start_col = map->view_x / map->tileset->sprite->cellw; - const unsigned int start_row = map->view_y / map->tileset->sprite->cellh; - - /* Convert into x/y coordinate. */ - const int start_x = 0 - (map->view_x % (int)map->tileset->sprite->cellw); - const int start_y = 0 - (map->view_y % (int)map->tileset->sprite->cellh); - - /* Number of row/columns to draw starting from there. */ - const unsigned int ncols = (map->view_w / map->tileset->sprite->cellw) + 2; - const unsigned int nrows = (map->view_h / map->tileset->sprite->cellh) + 2; - - struct texture colbox = {0}; - - if (!layer->tiles) - return; - - /* Show collision box if requested. */ - if (map->flags & MAP_FLAGS_SHOW_COLLIDE && texture_new(&colbox, 16, 16) == 0) { - texture_set_blend_mode(&colbox, TEXTURE_BLEND_BLEND); - texture_set_alpha_mod(&colbox, 100); - PAINTER_BEGIN(&colbox); - painter_set_color(0xa53030ff); - painter_clear(); - PAINTER_END(); - } - - for (unsigned int r = 0; r < nrows; ++r) { - for (unsigned int c = 0; c < ncols; ++c) { - if (start_col + c >= map->columns || - start_row + r >= map->rows) - continue; - - draw_layer_tile(map, layer, &colbox, start_col, start_row, start_x, start_y, r, c); - } - } - - texture_finish(&colbox); -} - -static void -draw_collide(const struct map *map) -{ - struct texture box = {0}; - - if (map->flags & MAP_FLAGS_SHOW_COLLIDE && texture_new(&box, 64, 64) == 0) { - /* Draw collide box around player if requested. */ - texture_set_alpha_mod(&box, 100); - texture_set_blend_mode(&box, TEXTURE_BLEND_BLEND); - PAINTER_BEGIN(&box); - painter_set_color(0x4f8fbaff); - painter_clear(); - PAINTER_END(); - texture_scale(&box, 0, 0, 64, 64, - map->player_x - map->view_x, map->player_y - map->view_y, - map->player_sprite->cellw, map->player_sprite->cellh, 0.f); - - /* Do the same for every objects. */ - PAINTER_BEGIN(&box); - painter_set_color(0xa8ca58ff); - painter_clear(); - PAINTER_END(); - - for (size_t i = 0; i < map->blocksz; ++i) { - texture_scale(&box, 0, 0, 64, 64, - map->blocks[i].x - map->view_x, map->blocks[i].y - map->view_y, - map->blocks[i].w, map->blocks[i].h, - 0.f); - } - - texture_finish(&box); - } -} - -int -map_init(struct map *map) -{ - assert(map); - - init(map); - tileset_start(map->tileset); - - return 0; -} - -void -map_handle(struct map *map, const union event *ev) -{ - assert(map); - assert(ev); - - switch (ev->type) { - case EVENT_KEYDOWN: - handle_keydown(map, ev); - break; - case EVENT_KEYUP: - handle_keyup(map, ev); - break; - default: - break; - } - - action_stack_handle(&map->astack_par, ev); - action_stack_handle(&map->astack_seq, ev); -} - -void -map_update(struct map *map, unsigned int ticks) -{ - assert(map); - - action_stack_update(&map->astack_par, ticks); - action_stack_update(&map->astack_seq, ticks); - - tileset_update(map->tileset, ticks); - - /* No movements if the sequential actions are running. */ - if (action_stack_completed(&map->astack_seq)) - move(map, ticks); -} - -void -map_draw(const struct map *map) -{ - assert(map); - - /* Draw the texture about background/foreground. */ - draw_layer(map, &map->layers[MAP_LAYER_TYPE_BACKGROUND]); - draw_layer(map, &map->layers[MAP_LAYER_TYPE_FOREGROUND]); - - walksprite_draw( - &map->player_ws, - map->player_angle, - map->player_x - map->view_x, - map->player_y - map->view_y); - - draw_layer(map, &map->layers[MAP_LAYER_TYPE_ABOVE]); - draw_collide(map); - - action_stack_draw(&map->astack_par); - action_stack_draw(&map->astack_seq); -} - -void -map_finish(struct map *map) -{ - assert(map); - - action_stack_finish(&map->astack_par); - action_stack_finish(&map->astack_seq); - - memset(map, 0, sizeof (*map)); -}
--- a/src/libmlk-rpg/rpg/map.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/* - * map.h -- game map - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_MAP_H -#define MLK_RPG_MAP_H - -#include <stddef.h> - -#include <mlk/core/action.h> -#include <mlk/core/action-stack.h> -#include <mlk/core/core.h> - -#include "walksprite.h" - -struct tileset; - -union event; - -enum map_layer_type { - MAP_LAYER_TYPE_BACKGROUND, - MAP_LAYER_TYPE_FOREGROUND, - MAP_LAYER_TYPE_ABOVE, - MAP_LAYER_TYPE_NUM -}; - -struct map_layer { - unsigned short *tiles; -}; - -enum map_flags { - MAP_FLAGS_NONE = 0, - MAP_FLAGS_SHOW_GRID = (1 << 0), - MAP_FLAGS_SHOW_COLLIDE = (1 << 2) -}; - -struct map_block { - int x; - int y; - unsigned int w; - unsigned int h; -}; - -struct map { - const char *title; /*!< (+) Map title name. */ - unsigned int columns; /*!< (-) Number of columns. */ - unsigned int rows; /*!< (-) Number of rows. */ - - /* Tileset. */ - struct tileset *tileset; /*!< (+&?) Tileset to use. */ - - /* View options. */ - enum map_flags flags; /*!< (+) View options. */ - - /* Extra collisions blocks. */ - struct map_block *blocks; /*!< (+&?) Extra collisions. */ - size_t blocksz; /*!< (+) Number of collisions. */ - - /* List of actions. */ - struct action_stack astack_par; /*!< (+) Parallel actions. */ - struct action_stack astack_seq; /*!< (+) Blocking actions. */ - - /* Player. */ - struct sprite *player_sprite; /*!< (+) The sprite to use */ - struct walksprite player_ws; /*!< (-) Walking sprite for moving the player. */ - int player_x; /*!< (+) Player position in x */ - int player_y; /*!< (+) Player position in y */ - int player_angle; /*!< (+) Player angle (see walksprite) */ - unsigned int player_movement; /*!< (*) Current player movements. */ - - /* View to zoom/locate. */ - int view_x; /*!< (+) Position in x */ - int view_y; /*!< (+) Position in y */ - unsigned int view_w; /*!< (+) View width */ - unsigned int view_h; /*!< (+) View height */ - - /* View margin. */ - int margin_x; /*!< (+) View margin in x. */ - int margin_y; /*!< (+) View margin in y. */ - unsigned int margin_w; /*!< (+) Margin width. */ - unsigned int margin_h; /*!< (+) Margin height. */ - - /* Different tile layers. */ - struct map_layer layers[MAP_LAYER_TYPE_NUM]; -}; - -CORE_BEGIN_DECLS - -int -map_init(struct map *map); - -void -map_handle(struct map *map, const union event *ev); - -void -map_update(struct map *map, unsigned int ticks); - -void -map_draw(const struct map *map); - -void -map_finish(struct map *map); - -CORE_END_DECLS - -#endif /* !MLK_RPG_MAP_H */
--- a/src/libmlk-rpg/rpg/message.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,316 +0,0 @@ -/* - * message.c -- message dialog - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> -#include <string.h> - -#include <mlk/core/action.h> -#include <mlk/core/event.h> -#include <mlk/core/font.h> -#include <mlk/core/maths.h> -#include <mlk/core/painter.h> -#include <mlk/core/panic.h> -#include <mlk/core/sprite.h> -#include <mlk/core/trace.h> -#include <mlk/core/util.h> - -#include <mlk/ui/align.h> -#include <mlk/ui/frame.h> -#include <mlk/ui/label.h> -#include <mlk/ui/theme.h> - -#include "message.h" - -#define THEME(msg) (msg->theme ? msg->theme : theme_default()) - -static void -handle(struct action *action, const union event *ev) -{ - assert(action); - assert(ev); - - message_handle(action->data, ev); -} - -static int -update(struct action *action, unsigned int ticks) -{ - assert(action); - - return message_update(action->data, ticks); -} - -static void -draw(struct action *action) -{ - assert(action); - - message_draw(action->data); -} - -static void -draw_frame(const struct message *msg) -{ - assert(msg); - - struct frame frame = { - .w = msg->w, - .h = msg->h, - .theme = msg->theme - }; - - frame_draw(&frame); -} - -static inline unsigned int -min_width(const struct message *msg) -{ - assert(msg); - - unsigned int maxw = 0, w = 0; - - for (size_t i = 0; i < msg->linesz; ++i) { - if (!msg->lines[i]) - continue; - if (font_query(THEME(msg)->fonts[THEME_FONT_INTERFACE], msg->lines[i], &w, NULL) < 0) - panic(); - if (w > maxw) - maxw = w; - } - - return (THEME(msg)->padding * 2) + maxw; -} - -static inline unsigned int -min_height(const struct message *msg) -{ - assert(msg); - - const struct theme *th = THEME(msg); - const unsigned int lh = font_height(th->fonts[THEME_FONT_INTERFACE]); - - return (th->padding * 2) + (msg->linesz * lh) + ((msg->linesz - 1) * msg->spacing); -} - -static void -draw_lines(const struct message *msg) -{ - const struct theme *theme = THEME(msg); - struct label label; - unsigned int lw, lh; - - for (size_t i = 0; i < msg->linesz; ++i) { - if (!msg->lines[i]) - continue; - if (font_query(theme->fonts[THEME_FONT_INTERFACE], msg->lines[i], &lw, &lh) < 0) - panic(); - - label.theme = theme; - label.x = theme->padding; - label.y = theme->padding + (i * (lh + msg->spacing)); - label.text = msg->lines[i]; - label.flags = LABEL_FLAGS_SHADOW; - - if (label.x + lw > msg->w) - tracef("message width too small: %u < %u", msg->w, min_width(msg)); - if (label.y + lh > msg->h) - tracef("message height too small: %u < %u", msg->h, min_height(msg)); - - /* - * The function label_draw will use THEME_COLOR_NORMAL to draw - * text and THEME_COLOR_SHADOW so if we have selected a line - * we need to cheat the normal color. - */ - if (msg->flags & MESSAGE_FLAGS_QUESTION && msg->index == (unsigned int)i) - label.flags |= LABEL_FLAGS_SELECTED; - else - label.flags &= ~(LABEL_FLAGS_SELECTED); - - label_draw(&label); - } -} - -void -message_start(struct message *msg) -{ - assert(msg); - - if (msg->flags & (MESSAGE_FLAGS_FADEIN|MESSAGE_FLAGS_FADEOUT)) - assert(msg->delay > 0); - - msg->elapsed = 0; - msg->scale = msg->flags & MESSAGE_FLAGS_FADEIN ? 0.0 : 1.0; - msg->state = msg->flags & MESSAGE_FLAGS_FADEIN - ? MESSAGE_STATE_OPENING - : MESSAGE_STATE_SHOWING; - - if (msg->flags & MESSAGE_FLAGS_AUTOMATIC && msg->timeout == 0) - tracef("message is automatic but has zero timeout"); -} - -void -message_query(const struct message *msg, unsigned int *w, unsigned int *h) -{ - assert(msg); - - if (w) - *w = min_width(msg); - if (h) - *h = min_height(msg); -} - -void -message_handle(struct message *msg, const union event *ev) -{ - assert(msg); - assert(ev); - - /* Skip if the message animation hasn't complete. */ - if (msg->state != MESSAGE_STATE_SHOWING) - return; - - /* Only keyboard event are valid. */ - if (ev->type != EVENT_KEYDOWN || msg->state == MESSAGE_STATE_NONE) - return; - - switch (ev->key.key) { - case KEY_UP: - if (msg->index > 0) - msg->index--; - break; - case KEY_DOWN: - if (msg->index + 1 < msg->linesz && msg->lines[msg->index + 1]) - msg->index++; - break; - case KEY_ENTER: - msg->state = msg->flags & MESSAGE_FLAGS_FADEOUT - ? MESSAGE_STATE_HIDING - : MESSAGE_STATE_NONE; - msg->elapsed = 0; - break; - default: - break; - } -} - -int -message_update(struct message *msg, unsigned int ticks) -{ - assert(msg); - - msg->elapsed += ticks; - - switch (msg->state) { - case MESSAGE_STATE_OPENING: - msg->scale = (double)msg->elapsed / (double)msg->delay; - - if (msg->scale > 1) - msg->scale = 1; - - if (msg->elapsed >= msg->delay) { - msg->state = MESSAGE_STATE_SHOWING; - msg->elapsed = 0; - } - - break; - case MESSAGE_STATE_SHOWING: - /* Do automatically switch state if requested by the user. */ - if (msg->flags & MESSAGE_FLAGS_AUTOMATIC && msg->elapsed >= msg->timeout) { - msg->state = msg->flags & MESSAGE_FLAGS_FADEOUT - ? MESSAGE_STATE_HIDING - : MESSAGE_STATE_NONE; - msg->elapsed = 0; - } - - break; - case MESSAGE_STATE_HIDING: - msg->scale = 1 - (double)msg->elapsed / (double)msg->delay; - - if (msg->scale < 0) - msg->scale = 0; - if (msg->elapsed >= msg->delay) { - msg->state = MESSAGE_STATE_NONE; - msg->elapsed = 0; - } - - break; - default: - break; - } - - return msg->state == MESSAGE_STATE_NONE; -} - -void -message_draw(const struct message *msg) -{ - assert(msg); - - struct texture tex; - int x, y; - unsigned int w, h; - - if (msg->w == 0 || msg->h == 0) { - tracef("message has null dimensions"); - return; - } - - if (texture_new(&tex, msg->w, msg->h) < 0) - panic(); - - PAINTER_BEGIN(&tex); - draw_frame(msg); - draw_lines(msg); - PAINTER_END(); - - /* Compute scaling. */ - w = msg->w * msg->scale; - h = msg->h * msg->scale; - - /* Centerize within its drawing area. */ - align(ALIGN_CENTER, &x, &y, w, h, msg->x, msg->y, msg->w, msg->h); - - /* Draw and clear. */ - texture_scale(&tex, 0, 0, msg->w, msg->h, x, y, w, h, 0); - texture_finish(&tex); -} - -void -message_hide(struct message *msg) -{ - assert(msg); - - msg->state = MESSAGE_STATE_HIDING; - msg->elapsed = 0; -} - -void -message_action(struct message *msg, struct action *action) -{ - assert(msg); - assert(action); - - memset(action, 0, sizeof (struct action)); - action->data = msg; - action->handle = handle; - action->update = update; - action->draw = draw; - - message_start(msg); -}
--- a/src/libmlk-rpg/rpg/message.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * message.h -- message dialog - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_MESSAGE_H -#define MLK_RPG_MESSAGE_H - -#include <mlk/core/core.h> -#include <mlk/core/texture.h> - -struct action; -struct font; -struct theme; - -union event; - -#define MESSAGE_DELAY_DEFAULT (150) -#define MESSAGE_TIMEOUT_DEFAULT (5000) - -enum message_flags { - MESSAGE_FLAGS_AUTOMATIC = (1 << 0), - MESSAGE_FLAGS_QUESTION = (1 << 1), - MESSAGE_FLAGS_FADEIN = (1 << 2), - MESSAGE_FLAGS_FADEOUT = (1 << 3) -}; - -enum message_state { - MESSAGE_STATE_NONE, - MESSAGE_STATE_OPENING, - MESSAGE_STATE_SHOWING, - MESSAGE_STATE_HIDING -}; - -struct message { - int x; - int y; - unsigned int w; - unsigned int h; - unsigned int spacing; - unsigned int delay; - unsigned int timeout; - const char * const *lines; - size_t linesz; - unsigned int index; - enum message_flags flags; - enum message_state state; - const struct theme *theme; - unsigned int elapsed; - double scale; -}; - -CORE_BEGIN_DECLS - -void -message_start(struct message *msg); - -void -message_query(const struct message *msg, unsigned int *w, unsigned int *h); - -void -message_handle(struct message *msg, const union event *ev); - -int -message_update(struct message *msg, unsigned int ticks); - -void -message_draw(const struct message *msg); - -void -message_hide(struct message *msg); - -void -message_action(struct message *msg, struct action *act); - -CORE_END_DECLS - -#endif /* !MLK_RPG_MESSAGE_H */
--- a/src/libmlk-rpg/rpg/property.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * property.c -- manage game properties - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include <assets/sql/property-save.h> -#include <assets/sql/property-remove.h> -#include <assets/sql/property-load.h> - -#include "property.h" -#include "save.h" - -int -property_save(const struct property *p, struct save *s) -{ - assert(p); - assert(save_ok(s)); - - return save_exec(s, (const char *)assets_property_save, "ss", p->key, p->value); -} - -int -property_load(struct property *p, struct save *s) -{ - assert(p); - assert(save_ok(s)); - - struct save_stmt stmt; - enum save_stmt_errno ret; - - if (save_stmt_init(&stmt, s, (const char *)assets_property_load, "s", p->key) < 0) - return -1; - - ret = save_stmt_next(&stmt, "s", p->value, sizeof (p->value)) == SAVE_STMT_ROW; - save_stmt_finish(&stmt); - - return ret ? 0 : -1; -} - -int -property_remove(struct property *p, struct save *s) -{ - assert(p); - assert(save_ok(s)); - - return save_exec(s, (const char *)assets_property_remove, "s", p->key); -} -
--- a/src/libmlk-rpg/rpg/property.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * property.h -- manage game properties - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_PROPERTY_H -#define MLK_RPG_PROPERTY_H - -#include <mlk/core/core.h> - -#define PROPERTY_KEY_MAX (64) -#define PROPERTY_VALUE_MAX (1024) - -struct save; - -struct property { - char key[PROPERTY_KEY_MAX + 1]; - char value[PROPERTY_VALUE_MAX + 1]; -}; - -CORE_BEGIN_DECLS - -int -property_save(const struct property *, struct save *); - -int -property_load(struct property *, struct save *); - -int -property_remove(struct property *, struct save *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_PROPERTY_H */
--- a/src/libmlk-rpg/rpg/quest.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * quest.c -- in game quests - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include <assets/sql/quest-remove.h> -#include <assets/sql/quest-save.h> -#include <assets/sql/quest-step-load.h> -#include <assets/sql/quest-step-save.h> - -#include "quest.h" -#include "save.h" - -int -quest_save(struct quest *q, struct save *s) -{ - assert(q); - assert(s); - - const struct quest_step *step; - - if (save_tx_begin(s) < 0) - return -1; - - if (save_exec(s, (const char *)assets_quest_save, "s", q->name) < 0) { - save_tx_rollback(s); - return -1; - } - - for (size_t i = 0; i < q->stepsz; ++i) { - step = &q->steps[i]; - - if (save_exec(s, (const char *)assets_quest_step_save, "ssi", q->name, step->name, step->percent) < 0) { - save_tx_rollback(s); - return -1; - } - } - - save_tx_commit(s); - - return 0; -} - -int -quest_load(struct quest *q, struct save *s) -{ - assert(q); - assert(s); - - struct save_stmt stmt; - struct quest_step *step; - - for (size_t i = 0; i < q->stepsz; ++i) { - step = &q->steps[i]; - - if (save_stmt_init(&stmt, s, (const char *)assets_quest_step_load, "s", step->name)) - return -1; - - if (save_stmt_next(&stmt, "i", &step->percent) < 0) { - save_stmt_finish(&stmt); - return -1; - } - - save_stmt_finish(&stmt); - } - - return 0; -}
--- a/src/libmlk-rpg/rpg/quest.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * quest.h -- in game quests - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_QUEST_H -#define MLK_RPG_QUEST_H - -#include <stddef.h> - -#include <mlk/core/core.h> - -struct save; - -struct quest_step { - const char *name; - const char *description; - int percent; -}; - -struct quest { - const char *name; - const char *description; - struct quest_step *steps; - size_t stepsz; -}; - -CORE_BEGIN_DECLS - -int -quest_save(struct quest *, struct save *); - -int -quest_load(struct quest *, struct save *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_QUEST_H */
--- a/src/libmlk-rpg/rpg/rpg.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * rpg.c -- librpg convenient header - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "rpg.h" - -int -rpg_init(void) -{ - return 0; -} - -void -rpg_finish(void) -{ -}
--- a/src/libmlk-rpg/rpg/rpg.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - * rpg.h -- librpg convenient header - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_RPG_H -#define MLK_RPG_RPG_H - -#include <mlk/core/core.h> - -CORE_BEGIN_DECLS - -int -rpg_init(void); - -void -rpg_finish(void); - -CORE_END_DECLS - -#endif /* !MLK_RPG_H */
--- a/src/libmlk-rpg/rpg/save.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,318 +0,0 @@ -/* - * save.c -- save functions - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <sqlite3.h> - -#include <mlk/util/util.h> - -#include <mlk/core/error.h> -#include <mlk/core/sys.h> -#include <mlk/core/util.h> - -#include <assets/sql/init.h> - -#include "property.h" -#include "save.h" - -#define SQL_BEGIN "BEGIN EXCLUSIVE TRANSACTION" -#define SQL_COMMIT "COMMIT" -#define SQL_ROLLBACK "ROLLBACK" - -static int -exec(struct save *db, const char *sql) -{ - if (sqlite3_exec(db->handle, sql, NULL, NULL, NULL) != SQLITE_OK) - return errorf("%s", sqlite3_errmsg(db->handle)); - - return 0; -} - -static const char * -path(unsigned int idx) -{ - return util_pathf("%s%u.db", sys_dir(SYS_DIR_SAVE), idx); -} - -static int -execu(struct save *db, const unsigned char *sql) -{ - return exec(db, (const char *)sql); -} - -static int -verify(struct save *db) -{ - struct { - time_t *date; - struct property prop; - } table[] = { - { .date = &db->created, { .key = "molko.create-date" } }, - { .date = &db->updated, { .key = "molko.update-date" } }, - }; - - /* Ensure create and update dates are present. */ - for (size_t i = 0; i < UTIL_SIZE(table); ++i) { - if (property_load(&table[i].prop, db) < 0) { - sqlite3_close(db->handle); - return errorf("database not initialized correctly"); - } - - *table[i].date = strtoull(table[i].prop.value, NULL, 10); - } - - return 0; -} - -static int -prepare(struct save *s, struct save_stmt *stmt, const char *sql, const char *args, va_list ap) -{ - stmt->parent = s; - stmt->handle = NULL; - - if (sqlite3_prepare(s->handle, sql, -1, (sqlite3_stmt **)&stmt->handle, NULL) != SQLITE_OK) - goto sqlite3_err; - - for (int i = 1; args && *args; ++args) { - switch (*args) { - case 'i': - case 'u': - if (sqlite3_bind_int(stmt->handle, i++, va_arg(ap, int)) != SQLITE_OK) - return -1; - break; - case 's': - if (sqlite3_bind_text(stmt->handle, i++, va_arg(ap, const char *), -1, NULL) != SQLITE_OK) - return -1; - break; - case 't': - if (sqlite3_bind_int64(stmt->handle, i++, va_arg(ap, time_t)) != SQLITE_OK) - return -1; - break; - case ' ': - break; - default: - return errorf("invalid format: %c", *args); - } - } - - return 0; - -sqlite3_err: - return errorf("%s", sqlite3_errmsg(s->handle)); -} - -static int -extract(struct save_stmt *stmt, const char *args, va_list ap) -{ - const int ncols = sqlite3_column_count(stmt->handle); - - for (int c = 0; args && *args; ++args) { - if (c >= ncols) - return errorf("too many arguments"); - - /* TODO: type check. */ - switch (*args) { - case 'i': - case 'u': - *va_arg(ap, int *) = sqlite3_column_int(stmt->handle, c++); - break; - case 's': { - char *str = va_arg(ap, char *); - size_t max = va_arg(ap, size_t); - - util_strlcpy(str, (const char *)sqlite3_column_text(stmt->handle, c++), max); - break; - } - case 't': - *va_arg(ap, time_t *) = sqlite3_column_int64(stmt->handle, c++); - break; - case ' ': - break; - default: - return errorf("invalid format: %c", *args); - } - } - - return 0; -} - -int -save_open(struct save *db, unsigned int idx, enum save_mode mode) -{ - assert(db); - - return save_open_path(db, path(idx), mode); -} - -int -save_open_path(struct save *db, const char *path, enum save_mode mode) -{ - assert(db); - assert(path); - - int flags = 0; - - switch (mode) { - case SAVE_MODE_WRITE: - flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; - break; - default: - flags = SQLITE_OPEN_READONLY; - break; - } - - if (sqlite3_open_v2(path, (sqlite3**)&db->handle, flags, NULL) != SQLITE_OK) - goto sqlite3_err; - - if (mode == SAVE_MODE_WRITE && execu(db, assets_init) < 0) - goto sqlite3_err; - - return verify(db); - -sqlite3_err: - errorf("%s", sqlite3_errmsg(db->handle)); - sqlite3_close(db->handle); - - memset(db, 0, sizeof (*db)); - - return -1; -} - -int -save_ok(const struct save *db) -{ - assert(db); - - return db && db->handle; -} - -int -save_exec(struct save *db, const char *sql, const char *args, ...) -{ - assert(save_ok(db)); - assert(sql); - - struct save_stmt stmt; - enum save_stmt_errno ret; - va_list ap; - - va_start(ap, args); - ret = prepare(db, &stmt, sql, args, ap); - va_end(ap); - - if (ret < 0) - return -1; - - ret = save_stmt_next(&stmt, NULL); - save_stmt_finish(&stmt); - - return ret == SAVE_STMT_ERROR ? -1 : 0; -} - -void -save_finish(struct save *db) -{ - assert(db); - - if (db->handle) - sqlite3_close(db->handle); - - memset(db, 0, sizeof (*db)); -} - -int -save_stmt_init(struct save_stmt *stmt, struct save *db, const char *sql, const char *args, ...) -{ - assert(stmt); - assert(save_ok(db)); - assert(args); - - va_list ap; - int ret; - - va_start(ap, args); - ret = prepare(db, stmt, sql, args, ap); - va_end(ap); - - return ret; -} - -enum save_stmt_errno -save_stmt_next(struct save_stmt *stmt, const char *args, ...) -{ - assert(stmt); - - va_list ap; - enum save_stmt_errno ret = SAVE_STMT_ERROR; - - switch (sqlite3_step(stmt->handle)) { - case SQLITE_ROW: - va_start(ap, args); - - if (extract(stmt, args, ap) == 0) - ret = SAVE_STMT_ROW; - - va_end(ap); - break; - case SQLITE_DONE: - ret = SAVE_STMT_DONE; - break; - default: - errorf("%s", sqlite3_errmsg(stmt->parent->handle)); - break; - } - - return ret; -} - -void -save_stmt_finish(struct save_stmt *stmt) -{ - assert(stmt); - - sqlite3_finalize(stmt->handle); - memset(stmt, 0, sizeof (*stmt)); -} - -int -save_tx_begin(struct save *s) -{ - assert(save_ok(s)); - - return save_exec(s, "BEGIN EXCLUSIVE TRANSACTION", NULL); -} - -void -save_tx_rollback(struct save *s) -{ - assert(save_ok(s)); - - (void)save_exec(s, "ROLLBACK", NULL); -} - -void -save_tx_commit(struct save *s) -{ - assert(save_ok(s)); - - (void)save_exec(s, "COMMIT", NULL); -}
--- a/src/libmlk-rpg/rpg/save.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * save.h -- save functions - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_SAVE_H -#define MLK_RPG_SAVE_H - -#include <time.h> - -#include <mlk/core/core.h> - -struct save { - time_t created; - time_t updated; - void *handle; -}; - -enum save_mode { - SAVE_MODE_READ, - SAVE_MODE_WRITE -}; - -struct save_stmt { - struct save *parent; - void *handle; -}; - -enum save_stmt_errno { - SAVE_STMT_DONE, - SAVE_STMT_ROW, - SAVE_STMT_ERROR -}; - -CORE_BEGIN_DECLS - -int -save_open(struct save *, unsigned int, enum save_mode); - -int -save_open_path(struct save *, const char *, enum save_mode); - -int -save_ok(const struct save *); - -int -save_exec(struct save *, const char *, const char *, ...); - -void -save_finish(struct save *); - -/* Prepared statements. */ -int -save_stmt_init(struct save_stmt *, struct save *, const char *, const char *, ...); - -enum save_stmt_errno -save_stmt_next(struct save_stmt *, const char *, ...); - -void -save_stmt_finish(struct save_stmt *); - -/* Explicit transactions. */ -int -save_tx_begin(struct save *); - -void -save_tx_rollback(struct save *); - -void -save_tx_commit(struct save *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_SAVE_H */
--- a/src/libmlk-rpg/rpg/selection.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * selection.c -- kind of selection - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include <mlk/core/util.h> - -#include "battle.h" -#include "character.h" -#include "selection.h" - -static void -random(struct selection *slt, struct battle_entity **entities, size_t entitiesz) -{ - do { - slt->index_character = util_nrand(0, entitiesz); - } while (!battle_entity_ok(entities[slt->index_character])); -} - -static void -first(struct selection *slt, struct battle_entity **entities, size_t entitiesz) -{ - for (size_t i = 0; i < entitiesz; ++i) { - if (battle_entity_ok(entities[i])) { - slt->index_character = i; - break; - } - } -} - -void -selection_first(struct selection *slt, const struct battle *bt) -{ - assert(slt); - assert(bt); - - if (slt->index_side == 0) - first(slt, bt->enemies, bt->enemiesz); - else - first(slt, bt->team, bt->teamsz); -} - -void -selection_random(struct selection *slt, const struct battle *bt) -{ - assert(slt); - assert(bt); - - if (slt->index_side == 0) - random(slt, bt->enemies, bt->enemiesz); - else - random(slt, bt->team, bt->teamsz); -}
--- a/src/libmlk-rpg/rpg/selection.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * selection.h -- kind of selection - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_SELECTION_H -#define MLK_RPG_SELECTION_H - -#include <mlk/core/core.h> - -struct battle; - -enum selection_kind { - SELECTION_KIND_SELF, - SELECTION_KIND_ONE, - SELECTION_KIND_ALL, - SELECTION_KIND_BOTH -}; - -enum selection_side { - /* Which side allowed (can be both). */ - SELECTION_SIDE_TEAM = (1 << 0), - SELECTION_SIDE_ENEMY = (1 << 1) -}; - -struct selection { - enum selection_kind allowed_kinds; - enum selection_side allowed_sides; - - /* Character index in battle entity array. */ - unsigned int index_character; - - /* Side index (0 = enemy, 1 = team). */ - unsigned int index_side; -}; - -CORE_BEGIN_DECLS - -void -selection_first(struct selection *, const struct battle *); - -void -selection_random(struct selection *, const struct battle *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_SELECTION_H */
--- a/src/libmlk-rpg/rpg/spell.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * spell.c -- magic spells - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> - -#include "spell.h" - -void -spell_select(const struct spell *s, const struct battle *bt, struct selection *slt) -{ - assert(s && s->select); - assert(bt); - assert(slt); - - s->select(bt, slt); -} - -void -spell_action(const struct spell *s, struct battle *bt, struct character *owner, const struct selection *slt) -{ - assert(s && s->action); - assert(bt); - assert(owner); - assert(slt); - - s->action(bt, owner, slt); -} - -void -spell_use(struct spell *s, struct character *owner, const struct selection *slt) -{ - assert(s && s->use); - assert(owner); - assert(slt); - - s->use(owner, slt); -}
--- a/src/libmlk-rpg/rpg/spell.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * spell.h -- magic spells - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_SPELL_H -#define MLK_RPG_SPELL_H - -#include <mlk/core/core.h> - -#include "selection.h" - -struct character; -struct battle; -struct selection; - -enum spell_type { - SPELL_TYPE_NEUTRAL, - SPELL_TYPE_FIRE, - SPELL_TYPE_WIND, - SPELL_TYPE_WATER, - SPELL_TYPE_EARTH, - SPELL_TYPE_CHAOS, - SPELL_TYPE_HOLY, - SPELL_TYPE_TIME -}; - -struct spell { - const char *name; - const char *description; - unsigned int mp; - enum spell_type type; - enum selection_kind select_kind; - enum selection_side select_side; - - void (*select)(const struct battle *, struct selection *); - void (*action)(struct battle *, struct character *, const struct selection *); - void (*use)(struct character *, const struct selection *); -}; - -CORE_BEGIN_DECLS - -void -spell_select(const struct spell *, const struct battle *, struct selection *); - -void -spell_action(const struct spell *, struct battle *, struct character *, const struct selection *); - -void -spell_use(struct spell *, struct character *, const struct selection *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_SPELL_H */
--- a/src/libmlk-rpg/rpg/team.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -/* - * team.c -- team storage - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* Nothing yet. */ -enum { some_compiler_needs_more_than_nothing = 1 };
--- a/src/libmlk-rpg/rpg/team.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * team.h -- team storage - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_TEAM_H -#define MLK_RPG_TEAM_H - -#define TEAM_MEMBER_MAX (4) - -struct character; - -struct team { - struct character *members[TEAM_MEMBER_MAX]; -}; - -#endif /* MLK_RPG_TEAM_H */
--- a/src/libmlk-rpg/rpg/tileset-file.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,334 +0,0 @@ -/* - * tileset-file.c -- tileset file loader - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <errno.h> -#include <limits.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <mlk/util/util.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/animation.h> -#include <mlk/core/error.h> -#include <mlk/core/image.h> -#include <mlk/core/util.h> - -#include "tileset-file.h" -#include "tileset.h" - -#define MAX_F(v) MAX_F_(v) -#define MAX_F_(v) "%" #v "[^\n|]" - -/* - * This is how memory for animations is allocated in the tileset_file - * structure. - * - * As animations require a texture and a sprite to be present, we need to store - * them locally in the tileset_file structure. - * - * tileset_file->anims[0] array (struct tileset_animation_block): - * - * [0] [1] [N] - * | texture | texture | texture - * | sprite | sprite | sprite - * | animation | animation | animation - * - * tileset_file->anims[1] array (struct tileset_animation): - * - * [0] [1] [N] - * | id | id | id - * | animation ^ | animation ^ | animation ^ - * - * The second array is the exposed array through the tileset->anims pointer, - * animations are referenced from the first array. This is because user may need - * or replace the tileset by itself and as such we need to keep track of the - * resource the tileset_file has allocated itself. - */ - -struct tileset_animation_block { - struct texture texture; - struct sprite sprite; - struct animation animation; -}; - -struct context { - struct tileset_file *tf; - struct tileset *tileset; - FILE *fp; - - char basedir[PATH_MAX]; - - /* - * The following properties aren't stored in the tileset because they - * are not needed after loading. - */ - unsigned int tilewidth; - unsigned int tileheight; - - /* Number of rows/columns in the image. */ - unsigned int nrows; - unsigned int ncolumns; -}; - -static void -tileset_animation_block_finish(void *data) -{ - struct tileset_animation_block *anim = data; - - texture_finish(&anim->texture); -} - -static int -tileset_tiledef_cmp(const void *d1, const void *d2) -{ - const struct tileset_tiledef *mtd1 = d1; - const struct tileset_tiledef *mtd2 = d2; - - if (mtd1->id < mtd2->id) - return -1; - if (mtd1->id > mtd2->id) - return 1; - - return 0; -} - -static int -tileset_animation_cmp(const void *d1, const void *d2) -{ - const struct tileset_animation *mtd1 = d1; - const struct tileset_animation *mtd2 = d2; - - if (mtd1->id < mtd2->id) - return -1; - if (mtd1->id > mtd2->id) - return 1; - - return 0; -} - -static int -parse_tilewidth(struct context *ctx, const char *line) -{ - if (sscanf(line, "tilewidth|%u", &ctx->tilewidth) != 1 || ctx->tilewidth == 0) - return errorf("tilewidth is null"); - - return 0; -} - -static int -parse_tileheight(struct context *ctx, const char *line) -{ - if (sscanf(line, "tileheight|%u", &ctx->tileheight) != 1 || ctx->tileheight == 0) - return errorf("tileheight is null"); - - return 0; -} - -static int -parse_tiledefs(struct context *ctx, const char *line) -{ - (void)line; - - short x, y; - unsigned short id, w, h; - struct tileset_tiledef *td; - - alloc_pool_init(&ctx->tf->tiledefs, sizeof (*td), NULL); - - while (fscanf(ctx->fp, "%hu|%hd|%hd|%hu|%hu\n", &id, &x, &y, &w, &h) == 5) { - td = alloc_pool_new(&ctx->tf->tiledefs); - td->id = id; - td->x = x; - td->y = y; - td->w = w; - td->h = h; - } - - /* Sort the array and expose it through the tileset->tiledefs pointer. */ - qsort(ctx->tf->tiledefs.data, ctx->tf->tiledefs.size, ctx->tf->tiledefs.elemsize, tileset_tiledef_cmp); - ctx->tileset->tiledefs = ctx->tf->tiledefs.data; - ctx->tileset->tiledefsz = ctx->tf->tiledefs.size; - - return 0; -} - -static int -parse_animations(struct context *ctx, const char *line) -{ - (void)line; - - unsigned short id; - unsigned int delay; - char filename[FILENAME_MAX + 1]; - struct tileset_animation_block *anim; - - alloc_pool_init(&ctx->tf->anims[0], sizeof (struct tileset_animation_block), tileset_animation_block_finish); - alloc_pool_init(&ctx->tf->anims[1], sizeof (struct tileset_animation), NULL); - - /* - * 1. Create the first array of animation, sprite and texture that are - * owned by the tileset_file structure. - */ - while (fscanf(ctx->fp, "%hu|" MAX_F(FILENAME_MAX) "|%u", &id, filename, &delay) == 3) { - anim = alloc_pool_new(&ctx->tf->anims[0]); - - if (image_open(&anim->texture, util_pathf("%s/%s", ctx->basedir, filename)) < 0) - return -1; - - sprite_init(&anim->sprite, &anim->texture, ctx->tilewidth, ctx->tileheight); - animation_init(&anim->animation, &anim->sprite, delay); - } - - /* - * 2. Create the second array that only consist of pointers to - * animations referencing the first array. - */ - for (size_t i = 0; i < ctx->tf->anims[0].size; ++i) { - struct tileset_animation_block *anim = alloc_pool_get(&ctx->tf->anims[0], i); - struct tileset_animation *ta; - - if (!(ta = alloc_pool_new(&ctx->tf->anims[1]))) - return -1; - - ta->id = id; - ta->animation = &anim->animation; - } - - /* - * 3. Finally expose the second array through the tileset->anims pointer - * and sort it. - */ - qsort(ctx->tf->anims[1].data, ctx->tf->anims[1].size, ctx->tf->anims[1].elemsize, tileset_animation_cmp); - ctx->tileset->anims = ctx->tf->anims[1].data; - ctx->tileset->animsz = ctx->tf->anims[1].size; - - return 0; -} - -static int -parse_image(struct context *ctx, const char *line) -{ - char *p; - - if (ctx->tilewidth == 0 || ctx->tileheight == 0) - return errorf("missing tile dimensions before image"); - if (!(p = strchr(line, '|'))) - return errorf("could not parse image"); - - if (image_open(&ctx->tf->image, util_pathf("%s/%s", ctx->basedir, p + 1)) < 0) - return -1; - - sprite_init(&ctx->tf->sprite, &ctx->tf->image, ctx->tilewidth, ctx->tileheight); - ctx->tileset->sprite = &ctx->tf->sprite; - - return 0; -} - -static int -parse_line(struct context *ctx, const char *line) -{ - static const struct { - const char *property; - int (*read)(struct context *, const char *); - } props[] = { - { "tilewidth", parse_tilewidth }, - { "tileheight", parse_tileheight }, - { "tiledefs", parse_tiledefs }, - { "animations", parse_animations }, - { "image", parse_image } - }; - - for (size_t i = 0; i < UTIL_SIZE(props); ++i) { - if (strncmp(line, props[i].property, strlen(props[i].property)) == 0) - return props[i].read(ctx, line); - } - - return 0; -} - -static int -parse(struct context *ctx, const char *path) -{ - char line[1024]; - char basedir[PATH_MAX]; - - util_strlcpy(basedir, path, sizeof (basedir)); - util_strlcpy(ctx->basedir, util_dirname(basedir), sizeof (ctx->basedir)); - - while (fgets(line, sizeof (line), ctx->fp)) { - /* Remove \n if any */ - line[strcspn(line, "\r\n")] = '\0'; - - if (parse_line(ctx, line) < 0) - return -1; - } - - return 0; -} - -static int -check(const struct tileset *tileset) -{ - if (!tileset->sprite) - return errorf("missing tileset image"); - - return 0; -} - -int -tileset_file_open(struct tileset_file *tf, struct tileset *tileset, const char *path) -{ - assert(tf); - assert(tileset); - assert(path); - - struct context ctx = { - .tf = tf, - .tileset = tileset - }; - int ret = 0; - - memset(tileset, 0, sizeof (*tileset)); - - if (!(ctx.fp = fopen(path, "r"))) - return -1; - if ((ret = parse(&ctx, path)) < 0 || (ret = check(tileset)) < 0) - tileset_file_finish(tf); - - fclose(ctx.fp); - - return ret; -} - -void -tileset_file_finish(struct tileset_file *tf) -{ - assert(tf); - - alloc_pool_finish(&tf->tiledefs); - alloc_pool_finish(&tf->anims[0]); - alloc_pool_finish(&tf->anims[1]); - - texture_finish(&tf->image); - - memset(tf, 0, sizeof (*tf)); -}
--- a/src/libmlk-rpg/rpg/tileset-file.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * tileset-file.h -- tileset file loader - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_TILESET_FILE_H -#define MLK_RPG_TILESET_FILE_H - -#include <stddef.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/core.h> -#include <mlk/core/sprite.h> -#include <mlk/core/texture.h> - -struct tileset; -struct tileset_tiledef; - -struct tileset_file { - struct alloc_pool tiledefs; - struct alloc_pool anims[2]; - struct texture image; - struct sprite sprite; -}; - -CORE_BEGIN_DECLS - -int -tileset_file_open(struct tileset_file *, struct tileset *, const char *); - -void -tileset_file_finish(struct tileset_file *); - -CORE_END_DECLS - -#endif /* !MLK_RPG_TILESET_FILE_H */
--- a/src/libmlk-rpg/rpg/tileset.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * tileset.c -- map tileset definition - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> - -#include <mlk/core/animation.h> -#include <mlk/core/sprite.h> - -#include "tileset.h" - -static inline int -anim_cmp(const void *d1, const void *d2) -{ - const struct tileset_animation *mtd1 = d1; - const struct tileset_animation *mtd2 = d2; - - if (mtd1->id < mtd2->id) - return -1; - if (mtd1->id > mtd2->id) - return 1; - - return 0; -} - -static inline const struct tileset_animation * -find(const struct tileset *ts, unsigned int r, unsigned int c) -{ - const struct tileset_animation key = { - .id = c + (r * ts->sprite->ncols) - }; - - return bsearch(&key, ts->anims, ts->animsz, sizeof (key), anim_cmp); -} - -int -tileset_ok(const struct tileset *ts) -{ - return ts && sprite_ok(ts->sprite); -} - -void -tileset_start(struct tileset *ts) -{ - for (size_t i = 0; i < ts->animsz; ++i) { - struct tileset_animation *ta = &ts->anims[i]; - - if (ta->animation) - animation_start(ta->animation); - } -} - -void -tileset_update(struct tileset *ts, unsigned int ticks) -{ - for (size_t i = 0; i < ts->animsz; ++i) { - struct tileset_animation *ta = &ts->anims[i]; - - if (!ta->animation) - continue; - - if (animation_update(ta->animation, ticks)) - animation_start(ta->animation); - } -} - -void -tileset_draw(const struct tileset *ts, unsigned int r, unsigned int c, int x, int y) -{ - assert(ts); - - const struct tileset_animation *ta; - - if ((ta = find(ts, r, c))) - animation_draw(ta->animation, x, y); - else - sprite_draw(ts->sprite, r, c, x, y); -}
--- a/src/libmlk-rpg/rpg/tileset.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * tileset.h -- map tileset definition - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_TILESET_H -#define MLK_RPG_TILESET_H - -#include <stddef.h> - -#include <mlk/core/core.h> - -struct sprite; - -struct tileset_tiledef { - unsigned short id; - short x; - short y; - unsigned short w; - unsigned short h; -}; - -struct tileset_animation { - unsigned short id; - struct animation *animation; -}; - -struct tileset { - struct tileset_tiledef *tiledefs; - size_t tiledefsz; - struct tileset_animation *anims; - size_t animsz; - struct sprite *sprite; -}; - -CORE_BEGIN_DECLS - -int -tileset_ok(const struct tileset *); - -void -tileset_start(struct tileset *); - -void -tileset_update(struct tileset *, unsigned int); - -void -tileset_draw(const struct tileset *, unsigned int, unsigned int, int, int); - -CORE_END_DECLS - -#endif /* !MLK_RPG_TILESET_H */
--- a/src/libmlk-rpg/rpg/walksprite.c Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * walksprite.c -- sprite designed for walking entities - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <string.h> - -#include <mlk/core/sprite.h> - -#include "walksprite.h" - -void -walksprite_init(struct walksprite *ws, struct sprite *sprite, unsigned int delay) -{ - assert(ws); - assert(sprite); - - memset(ws, 0, sizeof (*ws)); - ws->sprite = sprite; - ws->delay = delay; -} - -void -walksprite_reset(struct walksprite *ws) -{ - assert(ws); - - ws->index = 0; -} - -void -walksprite_update(struct walksprite *ws, unsigned int ticks) -{ - assert(ws); - - ws->elapsed += ticks; - - if (ws->elapsed >= ws->delay) { - ws->index += 1; - - if (ws->index >= ws->sprite->ncols) - ws->index = 0; - - ws->elapsed = 0; - } -} - -void -walksprite_draw(const struct walksprite *ws, unsigned int orientation, int x, int y) -{ - assert(ws); - assert(orientation < 8); - - sprite_draw(ws->sprite, orientation, ws->index, x, y); -}
--- a/src/libmlk-rpg/rpg/walksprite.h Sat Oct 15 21:19:25 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * walksprite.h -- sprite designed for walking entities - * - * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_WALKSPRITE_H -#define MLK_RPG_WALKSPRITE_H - -#include <mlk/core/core.h> - -struct sprite; - -/** - * \brief Sprite designed for walking entities. - * - * This structure works with sprite images that are defined as using the - * following conventions: - * - * ``` - * 7 0 1 - * ↖ ↑ ↗ - * 6 ← → 2 - * ↙ ↓ ↘ - * 5 4 3 - * ``` - * - * Where numbers define row in the sprite according to the character - * orientation. In other terms, your image sprite should look like this: - * - * ``` - * row columns in your image - * ---|--------------------- - * 0 | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ - * 1 | ↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗ - * 2 | →→→→→→→→→→→→→→→→→→→→ - * 3 | ↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘ - * 4 | ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ - * 5 | ↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙ - * 6 | ←←←←←←←←←←←←←←←←←←←← - * 7 | ↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖ - * ``` - */ -struct walksprite { - struct sprite *sprite; - unsigned int delay; - unsigned int index; - unsigned int elapsed; -}; - -CORE_BEGIN_DECLS - -void -walksprite_init(struct walksprite *, struct sprite *, unsigned int); - -void -walksprite_reset(struct walksprite *); - -void -walksprite_update(struct walksprite *, unsigned int); - -void -walksprite_draw(const struct walksprite *, unsigned int, int, int); - -CORE_END_DECLS - -#endif /* !MLK_RPG_WALKSPRITE_H */
--- a/tests/test-character.c Sat Oct 15 21:19:25 2022 +0200 +++ b/tests/test-character.c Sat Oct 15 21:24:17 2022 +0200 @@ -19,8 +19,8 @@ #include <stdio.h> #include <string.h> -#include <rpg/character.h> -#include <rpg/save.h> +#include <mlk/rpg/character.h> +#include <mlk/rpg/save.h> #include <dt.h>
--- a/tests/test-map.c Sat Oct 15 21:19:25 2022 +0200 +++ b/tests/test-map.c Sat Oct 15 21:24:17 2022 +0200 @@ -22,8 +22,8 @@ #include <mlk/core/sys.h> #include <mlk/core/window.h> -#include <rpg/map-file.h> -#include <rpg/map.h> +#include <mlk/rpg/map-file.h> +#include <mlk/rpg/map.h> #include <dt.h>
--- a/tests/test-save-quest.c Sat Oct 15 21:19:25 2022 +0200 +++ b/tests/test-save-quest.c Sat Oct 15 21:24:17 2022 +0200 @@ -20,8 +20,8 @@ #include <mlk/core/util.h> -#include <rpg/quest.h> -#include <rpg/save.h> +#include <mlk/rpg/quest.h> +#include <mlk/rpg/save.h> #include <dt.h>
--- a/tests/test-save.c Sat Oct 15 21:19:25 2022 +0200 +++ b/tests/test-save.c Sat Oct 15 21:24:17 2022 +0200 @@ -18,8 +18,8 @@ #include <stdio.h> -#include <rpg/property.h> -#include <rpg/save.h> +#include <mlk/rpg/property.h> +#include <mlk/rpg/save.h> #include <dt.h>
--- a/tests/test-tileset.c Sat Oct 15 21:19:25 2022 +0200 +++ b/tests/test-tileset.c Sat Oct 15 21:24:17 2022 +0200 @@ -19,8 +19,8 @@ #include <mlk/core/core.h> #include <mlk/core/window.h> -#include <rpg/tileset-file.h> -#include <rpg/tileset.h> +#include <mlk/rpg/tileset-file.h> +#include <mlk/rpg/tileset.h> #include <dt.h>