Mercurial > molko
changeset 385:3f13dc6c0e37
rpg: separate battle and the bar, closes #2522
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 15 Feb 2022 14:45:11 +0100 |
parents | c458441ff472 |
children | 7d5032755b7d |
files | examples/example-battle/main.c src/libmlk-core/core/event.h src/libmlk-rpg/CMakeLists.txt 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-state-attacking.h src/libmlk-rpg/rpg/battle-state-menu.c src/libmlk-rpg/rpg/battle-state-selection.c src/libmlk-rpg/rpg/battle-state-sub.c src/libmlk-rpg/rpg/battle.c src/libmlk-rpg/rpg/battle.h |
diffstat | 13 files changed, 858 insertions(+), 566 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/example-battle/main.c Sun Feb 13 11:34:19 2022 +0100 +++ b/examples/example-battle/main.c Tue Feb 15 14:45:11 2022 +0100 @@ -41,6 +41,7 @@ #include <ui/ui.h> #include <rpg/character.h> +#include <rpg/battle-bar-default.h> #include <rpg/battle.h> #include <rpg/rpg.h> #include <rpg/spell.h> @@ -179,6 +180,7 @@ bt->background = ®istry_images[REGISTRY_IMAGE_BATTLE_BACKGROUND]; + battle_bar_default(bt); battle_start(bt); fight_state.data = bt;
--- a/src/libmlk-core/core/event.h Sun Feb 13 11:34:19 2022 +0100 +++ b/src/libmlk-core/core/event.h Tue Feb 15 14:45:11 2022 +0100 @@ -30,6 +30,7 @@ EVENT_KEYUP, EVENT_MOUSE, EVENT_QUIT, + EVENT_NUM }; struct event_key {
--- a/src/libmlk-rpg/CMakeLists.txt Sun Feb 13 11:34:19 2022 +0100 +++ b/src/libmlk-rpg/CMakeLists.txt Tue Feb 15 14:45:11 2022 +0100 @@ -20,6 +20,8 @@ set( SOURCES + ${libmlk-rpg_SOURCE_DIR}/rpg/battle-bar-default.c + ${libmlk-rpg_SOURCE_DIR}/rpg/battle-bar-default.h ${libmlk-rpg_SOURCE_DIR}/rpg/battle-bar.c ${libmlk-rpg_SOURCE_DIR}/rpg/battle-bar.h ${libmlk-rpg_SOURCE_DIR}/rpg/battle-entity-state-attacking.c @@ -56,8 +58,6 @@ ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-opening.h ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-selection.c ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-selection.h - ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-sub.c - ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-sub.h ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-victory.c ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-victory.h ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libmlk-rpg/rpg/battle-bar-default.c Tue Feb 15 14:45:11 2022 +0100 @@ -0,0 +1,698 @@ +/* + * 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 <core/alloc.h> +#include <core/event.h> +#include <core/font.h> +#include <core/sprite.h> +#include <core/trace.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/align.h> +#include <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 "rpg_p.h" +#include "spell.h" + +struct self { + struct battle_bar_default data; + struct battle_bar bar; +}; + +/* + * 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, bt->order_cur->ch, target); +} + +static void +validate_magic(struct battle_bar_default *bar, struct battle *bt, const struct selection *sel) +{ + struct character *source = bt->order_cur->ch; + const struct spell *spell = source->spells[bar->sub_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->sub_grid.selected >= INVENTORY_ITEM_MAX) + return; + if (!(slot = &bt->inventory->items[bar->sub_grid.selected])) + return; + + source = bt->order_cur; + 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 *bt) +{ + struct selection sel = { + .allowed_kinds = SELECTION_KIND_ONE, + .allowed_sides = SELECTION_SIDE_ENEMY, + .index_side = 0 + }; + + /* Just make sure */ + + 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 = bt->order_cur->ch; + const struct spell *sp = ch->spells[bar->sub_grid.selected]; + struct selection sel = {0}; + + /* Don't forget to reset the gridmenu state. */ + gridmenu_reset(&bar->sub_grid); + + if (bar->sub_grid.selected > CHARACTER_SPELL_MAX) + return; + if (!(sp = ch->spells[bar->sub_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 = bt->order_curindex + }; + + 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 struct battle *bt, 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->sub_grid.x + (bar->sub_grid.w / 2) - (lw / 2); + label.y = bar->sub_grid.y - lh - BATTLE_THEME(bt)->padding; + label_draw(&label); +} + +static void +draw_spell_help(const struct battle_bar_default *bar, const struct battle *bt) +{ + const struct character *ch = bt->order_cur->ch; + const struct spell *sp; + + if (bar->sub_grid.selected >= CHARACTER_SPELL_MAX) + return; + if (!(sp = ch->spells[bar->sub_grid.selected])) + return; + + draw_help(bar, bt, sp->description); +} + +static void +draw_item_help(const struct battle_bar_default *bar, const struct battle *bt) +{ + const struct inventory_slot *slot; + + if (bar->sub_grid.selected >= INVENTORY_ITEM_MAX) + return; + + slot = &bt->inventory->items[bar->sub_grid.selected]; + + if (!slot->item) + return; + + draw_help(bar, bt, slot->item->description); +} + +static void +draw_status_character_stats(const struct battle *bt, + const struct character *ch, + int x, + int y, + unsigned int w, + unsigned int h) +{ + struct theme *theme = BATTLE_THEME(bt); + 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; + + /* HP. */ + snprintf(line, sizeof (line), "%d/%u", ch->hp, ch->hpmax); + label_query(&label, &lw, &lh); + label.x = x + w - lw - theme->padding; + label.y = y + spacing; + label_draw(&label); + + /* MP. */ + snprintf(line, sizeof (line), "%d/%u", ch->mp, ch->mpmax); + label_query(&label, &lw, &lh); + label.x = x + w - lw - 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, + unsigned int index) +{ + int x, y; + unsigned int w, h; + + /* Compute bounding box for rendering. */ + w = bar->status_frame.w / BATTLE_TEAM_MAX; + h = bar->status_frame.h; + x = bar->status_frame.x + (index * w); + y = bar->status_frame.y; + + draw_status_character_stats(bt, ch, x, y, w, h); +} + +static void +draw_status_characters(const struct battle_bar_default *bar, const struct battle *bt) +{ + 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, index); + + ++index; + } +} + +static void +draw_status(const struct battle_bar_default *bar, const struct battle *bt) +{ + frame_draw(&bar->status_frame); + draw_status_characters(bar, bt); +} + +static void +draw_menu(const struct battle_bar_default *bar, const struct battle *bt) +{ + 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 + } + } + }; + + struct theme theme; + int bx, by; + unsigned int bw, bh; + + /* Copy theme according to menu selection. */ + theme_shallow(&theme, bt->theme); + + /* Compute bounding box with margins removed. */ + bx = bar->menu_frame.x + theme.padding; + by = bar->menu_frame.y + theme.padding; + bw = bar->menu_frame.w - theme.padding * 2; + bh = bar->menu_frame.h - theme.padding * 2; + + /* Draw menu frame. */ + frame_draw(&bar->menu_frame); + + 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 /*&& bar->state != BATTLE_BAR_DEFAULT_STATE_NONE*/) + theme.colors[THEME_COLOR_NORMAL] = BATTLE_THEME(bt)->colors[THEME_COLOR_SELECTED]; + else + theme.colors[THEME_COLOR_NORMAL] = BATTLE_THEME(bt)->colors[THEME_COLOR_NORMAL]; + + 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(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, bt->order_cur->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) { + gridmenu_reset(&bar->sub_grid); + bar->state = BATTLE_BAR_DEFAULT_STATE_MENU; + return; + } + + gridmenu_handle(&bar->sub_grid, ev); + + if (bar->sub_grid.state == GRIDMENU_STATE_ACTIVATED) { + gridmenu_reset(&bar->sub_grid); + + 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 + }; + + handlers[bar->state](bar, bt, ev); +} + +#if 0 + +static void +handle_clickdown(struct battle_bar_default *bar, struct battle *bt, const union event *ev) +{ + (void)bar; + (void)bt; + (void)ev; + assert(ev->type == EVENT_CLICKDOWN); + + 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). */ + gridmenu_handle(&bar->sub_grid, ev); + + if (bar->sub_grid.state == GRIDMENU_STATE_ACTIVATED) + default: + break; + } + + return 0; +} + +#endif + +static void +init_gridmenu(struct battle_bar_default *bar, const struct battle *bt) +{ + bar->sub_grid.x = bar->x; + bar->sub_grid.y = bar->menu_frame.y; + bar->sub_grid.w = bar->status_frame.w; + bar->sub_grid.h = bar->h; + bar->sub_grid.theme = bt->theme; + bar->sub_grid.nrows = 3; + bar->sub_grid.ncols = 4; + + memset(bar->sub_grid.menu, 0, sizeof (bar->sub_grid.menu)); +} + +static void +start(struct battle_bar *bar, struct battle *bt) +{ + (void)bt; + + battle_bar_default_start(bar->data); +} + +static void +select(struct battle_bar *bar, struct battle *bt, const struct selection *sel) +{ + battle_bar_default_select(bar->data, bt, sel); +} + +static void +handle(struct battle_bar *bar, struct battle *bt, const union event *ev) +{ + battle_bar_default_handle(bar->data, bt, ev); +} + +static void +draw(const struct battle_bar *bar, const struct battle *bt) +{ + battle_bar_default_draw(bar->data, bt); +} + +static void +finish(struct battle_bar *bar, struct battle *bt) +{ + (void)bt; + + battle_bar_default_finish(bar->data); + free(bar->data); +} + +void +battle_bar_default_positionate(struct battle_bar_default *bar, const struct battle *bt) +{ + assert(bar); + assert(bt); + + bar->w = window.w; + bar->h = window.h * 0.12; + bar->x = 0; + bar->y = window.h - bar->h; + + /* Menu in the middle of the bar (take 20%). */ + bar->menu_frame.w = bar->w * 0.2; + bar->menu_frame.h = bar->h; + bar->menu_frame.x = bar->x + (bar->w / 2) - (bar->menu_frame.w / 2); + bar->menu_frame.y = window.h - bar->h; + bar->menu_frame.theme = bt->theme; + + /* Status bar on the right. */ + bar->status_frame.x = bar->menu_frame.x + bar->menu_frame.w; + bar->status_frame.y = bar->menu_frame.y; + bar->status_frame.w = (bar->w - bar->menu_frame.w) / 2; + bar->status_frame.h = bar->h; + bar->status_frame.theme = bt->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); + + init_gridmenu(bar, bt); + + for (size_t i = 0; i < CHARACTER_SPELL_MAX; ++i) + if (ch->spells[i]) + bar->sub_grid.menu[i] = ch->spells[i]->name; + + gridmenu_repaint(&bar->sub_grid); + + bar->state = BATTLE_BAR_DEFAULT_STATE_GRID; +} + +void +battle_bar_default_open_item(struct battle_bar_default *bar, const struct battle *bt) +{ + asssert(bar); + assert(bt); + + init_gridmenu(bar, bt); + + 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]; + } + } + + gridmenu_repaint(&bar->sub_grid); + + bar->state = BATTLE_BAR_DEFAULT_STATE_GRID; +} + +void +battle_bar_default_start(struct battle_bar_default *bar) +{ + assert(bar); + + gridmenu_reset(&bar->sub_grid); + + 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); + + draw_status(bar, bt); + draw_menu(bar, bt); + + 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->sub_grid); +} + +void +battle_bar_default_finish(struct battle_bar_default *bar) +{ + assert(bar); + + gridmenu_finish(&bar->sub_grid); + + memset(bar, 0, sizeof (*bar)); +} + +void +battle_bar_default(struct battle *bt) +{ + assert(bt); + + struct self *self; + + self = alloc_new0(sizeof (*self)); + self->bar.data = self; + self->bar.start = start; + self->bar.select = select; + self->bar.handle = handle; + self->bar.draw = draw; + self->bar.finish = finish; + + battle_bar_default_positionate(&self->data, bt); + + bt->bar = &self->bar; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libmlk-rpg/rpg/battle-bar-default.h Tue Feb 15 14:45:11 2022 +0100 @@ -0,0 +1,95 @@ +/* + * 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 <core/core.h> + +#include <ui/frame.h> +#include <ui/gridmenu.h> + +struct battle; +struct character; +struct selection; + +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_MENU, + BATTLE_BAR_DEFAULT_STATE_GRID +}; + +struct battle_bar_default { + int x; + int y; + unsigned int w; + unsigned int h; + enum battle_bar_default_state state; + + /* Right status frame. */ + struct frame status_frame; + + /* Main menu selection. */ + struct frame menu_frame; + enum battle_bar_default_menu menu; + + /* Sub menu selection (spells/objects). */ + char sub_items[GRIDMENU_ENTRY_MAX][128]; + struct gridmenu sub_grid; +}; + +CORE_BEGIN_DECLS + +void +battle_bar_default_positionate(struct battle_bar_default *, const struct battle *); + +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 *bar, struct battle *bt, 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 *); + +CORE_END_DECLS + +#endif /* !MLK_RPG_BATTLE_BAR_DEFAULT_H */
--- a/src/libmlk-rpg/rpg/battle-bar.c Sun Feb 13 11:34:19 2022 +0100 +++ b/src/libmlk-rpg/rpg/battle-bar.c Tue Feb 15 14:45:11 2022 +0100 @@ -1,5 +1,5 @@ /* - * battle-bar.h -- battle status bar and menu + * battle-bar.c -- abstract battle bar * * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> * @@ -17,349 +17,50 @@ */ #include <assert.h> -#include <stdio.h> -#include <string.h> -#include <core/event.h> -#include <core/font.h> -#include <core/window.h> -#include <core/util.h> - -#include <ui/align.h> -#include <ui/theme.h> - -#include "battle.h" #include "battle-bar.h" -#include "character.h" -#include "inventory.h" -#include "item.h" -#include "spell.h" -#include "rpg_p.h" - -static void -init_gridmenu(struct battle_bar *bar, const struct battle *bt) -{ - bar->sub_grid.x = bar->x; - bar->sub_grid.y = bar->menu_frame.y; - bar->sub_grid.w = bar->status_frame.w; - bar->sub_grid.h = bar->h; - bar->sub_grid.theme = bt->theme; - bar->sub_grid.nrows = 3; - bar->sub_grid.ncols = 4; - - memset(bar->sub_grid.menu, 0, sizeof (bar->sub_grid.menu)); -} - -static void -draw_status_character_stats(const struct battle *bt, - const struct character *ch, - int x, - int y, - unsigned int w, - unsigned int h) -{ - struct theme *theme = BATTLE_THEME(bt); - 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; - /* HP. */ - snprintf(line, sizeof (line), "%d/%u", ch->hp, ch->hpmax); - label_query(&label, &lw, &lh); - label.x = x + w - lw - theme->padding; - label.y = y + spacing; - label_draw(&label); - - /* MP. */ - snprintf(line, sizeof (line), "%d/%u", ch->mp, ch->mpmax); - label_query(&label, &lw, &lh); - label.x = x + w - lw - 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 *bar, - const struct battle *bt, - const struct character *ch, - unsigned int index) -{ - int x, y; - unsigned int w, h; - - /* Compute bounding box for rendering. */ - w = bar->status_frame.w / BATTLE_TEAM_MAX; - h = bar->status_frame.h; - x = bar->status_frame.x + (index * w); - y = bar->status_frame.y; - - draw_status_character_stats(bt, ch, x, y, w, h); -} - -static void -draw_status_characters(const struct battle_bar *bar, const struct battle *bt) -{ - 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, index); - - ++index; - } -} - -static void -draw_status(const struct battle_bar *bar, const struct battle *bt) -{ - frame_draw(&bar->status_frame); - draw_status_characters(bar, bt); -} - -static void -draw_menu(const struct battle_bar *bar, const struct battle *bt) +void +battle_bar_start(struct battle_bar *bar, struct battle *bt) { - 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 - } - } - }; - - struct theme theme; - int bx, by; - unsigned int bw, bh; - - /* Copy theme according to menu selection. */ - theme_shallow(&theme, bt->theme); - - /* Compute bounding box with margins removed. */ - bx = bar->menu_frame.x + theme.padding; - by = bar->menu_frame.y + theme.padding; - bw = bar->menu_frame.w - theme.padding * 2; - bh = bar->menu_frame.h - theme.padding * 2; - - /* Draw menu frame. */ - frame_draw(&bar->menu_frame); - - 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 && bar->state != BATTLE_BAR_STATE_NONE) - theme.colors[THEME_COLOR_NORMAL] = BATTLE_THEME(bt)->colors[THEME_COLOR_SELECTED]; - else - theme.colors[THEME_COLOR_NORMAL] = BATTLE_THEME(bt)->colors[THEME_COLOR_NORMAL]; + assert(bar); + assert(bt); - 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); - } -} - -static void -draw_sub(const struct battle_bar *bar) -{ - gridmenu_draw(&bar->sub_grid); -} - -static int -handle_keydown(struct battle_bar *bar, const union event *ev) -{ - assert(ev->type == EVENT_KEYDOWN); - - switch (bar->state) { - case BATTLE_BAR_STATE_MENU: - /* We are selecting a main menu entry. */ - switch (ev->key.key) { - case KEY_UP: - bar->menu = BATTLE_BAR_MENU_ATTACK; - break; - case KEY_RIGHT: - bar->menu = BATTLE_BAR_MENU_MAGIC; - break; - case KEY_DOWN: - bar->menu = BATTLE_BAR_MENU_OBJECTS; - break; - case KEY_LEFT: - bar->menu = BATTLE_BAR_MENU_SPECIAL; - break; - case KEY_ENTER: - return 1; - default: - break; - } - break; - case BATTLE_BAR_STATE_SUB: - /* We are in the sub menu (objects/spells). */ - gridmenu_handle(&bar->sub_grid, ev); - return bar->sub_grid.state == GRIDMENU_STATE_ACTIVATED; - default: - break; - } - - return 0; -} - -static int -handle_clickdown(struct battle_bar *bar, const union event *ev) -{ - assert(ev->type == EVENT_CLICKDOWN); - - switch (bar->state) { - case BATTLE_BAR_STATE_MENU: - /* We are selecting a main menu entry. */ - /* TODO: implement click here too. */ - break; - case BATTLE_BAR_STATE_SUB: - /* We are in the sub menu (objects/spells). */ - gridmenu_handle(&bar->sub_grid, ev); - return bar->sub_grid.state == GRIDMENU_STATE_ACTIVATED; - default: - break; - } - - return 0; + if (bar->start) + bar->start(bar, bt); } void -battle_bar_positionate(struct battle_bar *bar, const struct battle *bt) +battle_bar_select(struct battle_bar *bar, struct battle *bt, const struct selection *sel) { assert(bar); + assert(bt); + assert(sel); - /* Menu in the middle of the bar (take 20%). */ - bar->menu_frame.w = bar->w * 0.2; - bar->menu_frame.h = bar->h; - bar->menu_frame.x = bar->x + (bar->w / 2) - (bar->menu_frame.w / 2); - bar->menu_frame.y = window.h - bar->h; - bar->menu_frame.theme = bt->theme; + if (bar->select) + bar->select(bar, bt, sel); - /* Status bar on the right. */ - bar->status_frame.x = bar->menu_frame.x + bar->menu_frame.w; - bar->status_frame.y = bar->menu_frame.y; - bar->status_frame.w = (bar->w - bar->menu_frame.w) / 2; - bar->status_frame.h = bar->h; - bar->status_frame.theme = bt->theme; } -int -battle_bar_handle(struct battle_bar *bar, const struct battle *bt, const union event *ev) +void +battle_bar_handle(struct battle_bar *bar, struct battle *bt, const union event *ev) { - /* Not needed yet. */ - (void)bt; - assert(bar); assert(bt); assert(ev); - if (bar->state == BATTLE_BAR_STATE_NONE) - return 0; - - switch (ev->type) { - case EVENT_KEYDOWN: - return handle_keydown(bar, ev); - case EVENT_CLICKDOWN: - return handle_clickdown(bar, ev); - default: - break; - } - - return 0; -} - -void -battle_bar_reset(struct battle_bar *bar) -{ - gridmenu_reset(&bar->sub_grid); - - bar->menu = BATTLE_BAR_MENU_ATTACK; - bar->state = BATTLE_BAR_STATE_NONE; + if (bar->handle) + bar->handle(bar, bt, ev); } void -battle_bar_open_menu(struct battle_bar *bar) +battle_bar_update(struct battle_bar *bar, struct battle *bt, unsigned int ticks) { - gridmenu_reset(&bar->sub_grid); - - bar->state = BATTLE_BAR_STATE_MENU; - bar->menu = BATTLE_BAR_MENU_ATTACK; -} - -void -battle_bar_open_spells(struct battle_bar *bar, const struct battle *bt, struct character *ch) -{ - init_gridmenu(bar, bt); - - for (size_t i = 0; i < CHARACTER_SPELL_MAX; ++i) { - if (ch->spells[i]) - bar->sub_grid.menu[i] = ch->spells[i]->name; - } - - gridmenu_repaint(&bar->sub_grid); + assert(bar); + assert(bt); - bar->state = BATTLE_BAR_STATE_SUB; -} - -void -battle_bar_open_items(struct battle_bar *bar, const struct battle *bt) -{ - init_gridmenu(bar, bt); - - 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]; - } - } - - gridmenu_repaint(&bar->sub_grid); - - bar->state = BATTLE_BAR_STATE_SUB; + if (bar->update) + bar->update(bar, bt, ticks); } void @@ -368,20 +69,16 @@ assert(bar); assert(bt); - draw_status(bar, bt); - draw_menu(bar, bt); - - /* Sub menu is only shown if state is set to it. */ - if (bar->state == BATTLE_BAR_STATE_SUB) - draw_sub(bar); + if (bar->draw) + bar->draw(bar, bt); } void -battle_bar_finish(struct battle_bar *bar) +battle_bar_finish(struct battle_bar *bar, struct battle *bt) { assert(bar); - - gridmenu_finish(&bar->sub_grid); + assert(bt); - memset(bar, 0, sizeof (*bar)); + if (bar->finish) + bar->finish(bar, bt); }
--- a/src/libmlk-rpg/rpg/battle-bar.h Sun Feb 13 11:34:19 2022 +0100 +++ b/src/libmlk-rpg/rpg/battle-bar.h Tue Feb 15 14:45:11 2022 +0100 @@ -1,5 +1,5 @@ /* - * battle-bar.h -- battle status bar and menu + * battle-bar.h -- abstract battle bar * * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> * @@ -21,73 +21,40 @@ #include <core/core.h> -#include <ui/frame.h> -#include <ui/gridmenu.h> - struct battle; -struct character; +struct selection; union event; -enum battle_bar_menu { - BATTLE_BAR_MENU_ATTACK = 0, - BATTLE_BAR_MENU_MAGIC = 1, - BATTLE_BAR_MENU_OBJECTS = 2, - BATTLE_BAR_MENU_SPECIAL = 3 -}; - -enum battle_bar_state { - BATTLE_BAR_STATE_NONE, - BATTLE_BAR_STATE_MENU, - BATTLE_BAR_STATE_SUB -}; - struct battle_bar { - int x; - int y; - unsigned int w; - unsigned int h; - enum battle_bar_state state; - - /* Right status frame. */ - struct frame status_frame; - - /* Main menu selection. */ - struct frame menu_frame; - enum battle_bar_menu menu; - - /* Sub menu selection (spells/objects). */ - char sub_items[GRIDMENU_ENTRY_MAX][128]; - struct gridmenu sub_grid; + 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_positionate(struct battle_bar *bar, const struct battle *bt); - -int -battle_bar_handle(struct battle_bar *bar, - const struct battle *bt, - const union event *ev); +battle_bar_start(struct battle_bar *, struct battle *); void -battle_bar_reset(struct battle_bar *bar); +battle_bar_select(struct battle_bar *, struct battle *, const struct selection *); void -battle_bar_open_menu(struct battle_bar *bar); - -void -battle_bar_open_spells(struct battle_bar *bar, const struct battle *bt, struct character *ch); +battle_bar_handle(struct battle_bar *, struct battle *, const union event *); void -battle_bar_open_items(struct battle_bar *bar, const struct battle *bt); +battle_bar_update(struct battle_bar *, struct battle *, unsigned int); void -battle_bar_draw(const struct battle_bar *bar, const struct battle *bt); +battle_bar_draw(const struct battle_bar *, const struct battle *); void -battle_bar_finish(struct battle_bar *bar); +battle_bar_finish(struct battle_bar *, struct battle *); CORE_END_DECLS
--- a/src/libmlk-rpg/rpg/battle-state-attacking.h Sun Feb 13 11:34:19 2022 +0100 +++ b/src/libmlk-rpg/rpg/battle-state-attacking.h Tue Feb 15 14:45:11 2022 +0100 @@ -43,7 +43,7 @@ void battle_state_attacking_init(struct battle_state_attacking *, struct battle_entity *, - struct battle_entity *); + struct battle_entity *); int battle_state_attacking_update(struct battle_state_attacking *, struct battle *);
--- a/src/libmlk-rpg/rpg/battle-state-menu.c Sun Feb 13 11:34:19 2022 +0100 +++ b/src/libmlk-rpg/rpg/battle-state-menu.c Tue Feb 15 14:45:11 2022 +0100 @@ -23,12 +23,10 @@ #include "battle-bar.h" #include "battle-state-menu.h" -#include "battle-state-selection.h" -#include "battle-state-sub.h" #include "battle-state.h" #include "battle.h" -#include "character.h" -#include "spell.h" + +#if 0 static void open_spells(struct battle *bt) @@ -55,6 +53,8 @@ battle_state_sub(bt); } +#endif + static void handle(struct battle_state *st, struct battle *bt, const union event *ev) { @@ -77,23 +77,7 @@ assert(bt); assert(ev); - if (battle_bar_handle(&bt->bar, bt, ev)) { - switch (bt->bar.menu) { - case BATTLE_BAR_MENU_ATTACK: - open_attack(bt); - break; - case BATTLE_BAR_MENU_MAGIC: - open_spells(bt); - break; - case BATTLE_BAR_MENU_OBJECTS: - open_items(bt); - break; - case BATTLE_BAR_MENU_SPECIAL: - break; - default: - break; - } - } + battle_bar_handle(bt->bar, bt, ev); } void @@ -108,6 +92,6 @@ state->handle = handle; state->finish = finish; - battle_bar_open_menu(&bt->bar); + battle_bar_start(bt->bar, bt); battle_switch(bt, state); }
--- a/src/libmlk-rpg/rpg/battle-state-selection.c Sun Feb 13 11:34:19 2022 +0100 +++ b/src/libmlk-rpg/rpg/battle-state-selection.c Tue Feb 15 14:45:11 2022 +0100 @@ -46,47 +46,6 @@ }; static void -use(const struct battle_state_selection *slt, struct battle *bt) -{ - struct inventory_slot *slot; - struct battle_entity *source, *target; - - if (bt->bar.sub_grid.selected >= INVENTORY_ITEM_MAX) - return; - if (!(slot = &bt->inventory->items[bt->bar.sub_grid.selected])) - return; - - source = bt->order_cur; - target = slt->select.index_side == 0 - ? &bt->enemies[slt->select.index_character] - : &bt->team[slt->select.index_character]; - - battle_state_item(bt, source, target, slot); -} - -static void -attack(struct battle_state_selection *slt, struct battle *bt) -{ - struct character *target; - - if (slt->select.index_side == 0) - target = bt->enemies[slt->select.index_character].ch; - else - target = bt->team[slt->select.index_character].ch; - - battle_attack(bt, bt->order_cur->ch, target); -} - -static void -cast(struct battle_state_selection *slt, struct battle *bt) -{ - struct character *source = bt->order_cur->ch; - const struct spell *spell = source->spells[bt->bar.sub_grid.selected]; - - battle_cast(bt, source, spell, &slt->select); -} - -static void select_adj_in(struct battle_state_selection *slt, const struct battle_entity *entities, size_t entitiesz, int step) { assert(slt->select.index_character != (unsigned int)-1); @@ -126,30 +85,10 @@ switch (ev->key.key) { case KEY_ESCAPE: - switch (bt->bar.menu) { - case BATTLE_BAR_MENU_MAGIC: - case BATTLE_BAR_MENU_OBJECTS: - battle_state_sub(bt); - break; - default: - battle_state_menu(bt); - break; - } + battle_state_menu(bt); break; case KEY_ENTER: - switch (bt->bar.menu) { - case BATTLE_BAR_MENU_ATTACK: - attack(stl, bt); - break; - case BATTLE_BAR_MENU_MAGIC: - cast(stl, bt); - break; - case BATTLE_BAR_MENU_OBJECTS: - use(stl, bt); - break; - default: - break; - } + battle_bar_select(bt->bar, bt, &stl->select); break; case KEY_LEFT: if (stl->select.allowed_sides & SELECTION_SIDE_ENEMY)
--- a/src/libmlk-rpg/rpg/battle-state-sub.c Sun Feb 13 11:34:19 2022 +0100 +++ b/src/libmlk-rpg/rpg/battle-state-sub.c Tue Feb 15 14:45:11 2022 +0100 @@ -38,85 +38,6 @@ #include "character.h" #include "spell.h" -static void -start_select_spell(struct battle *bt) -{ - const struct character *ch = bt->order_cur->ch; - const struct spell *sp = ch->spells[bt->bar.sub_grid.selected]; - struct selection slt = {0}; - - /* Don't forget to reset the gridmenu state. */ - gridmenu_reset(&bt->bar.sub_grid); - - if (bt->bar.sub_grid.selected > CHARACTER_SPELL_MAX) - return; - if (!(sp = ch->spells[bt->bar.sub_grid.selected]) || sp->mp > (unsigned int)(ch->mp)) - return; - - spell_select(sp, bt, &slt); - battle_state_selection(bt, &slt); - - /* A cursor should be present. */ - if (!sprite_ok(BATTLE_THEME(bt)->sprites[THEME_SPRITE_CURSOR])) - tracef("battle: no cursor sprite in theme"); -} - -static void -start_select_object(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 = bt->order_curindex - }; - - battle_state_selection(bt, &slt); -} - -static void -draw_help(const struct battle *bt, 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 = bt->bar.sub_grid.x + (bt->bar.sub_grid.w / 2) - (lw / 2); - label.y = bt->bar.sub_grid.y - lh - BATTLE_THEME(bt)->padding; - label_draw(&label); -} - -static void -draw_spell_help(const struct battle *bt) -{ - const struct character *ch = bt->order_cur->ch; - const struct spell *sp; - - if (bt->bar.sub_grid.selected >= CHARACTER_SPELL_MAX) - return; - if ((sp = ch->spells[bt->bar.sub_grid.selected])) - return; - - draw_help(bt, sp->description); -} - -static void -draw_object_help(const struct battle *bt) -{ - const struct inventory_slot *slot; - - if (bt->bar.sub_grid.selected >= INVENTORY_ITEM_MAX) - return; - - slot = &bt->inventory->items[bt->bar.sub_grid.selected]; - - if (!slot->item) - return; - - draw_help(bt, slot->item->description); -} static void handle(struct battle_state *st, struct battle *bt, const union event *ev)
--- a/src/libmlk-rpg/rpg/battle.c Sun Feb 13 11:34:19 2022 +0100 +++ b/src/libmlk-rpg/rpg/battle.c Tue Feb 15 14:45:11 2022 +0100 @@ -36,14 +36,15 @@ #include <ui/label.h> #include <ui/theme.h> -#include "battle.h" +#include "battle-bar.h" #include "battle-indicator.h" -#include "battle-state.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" @@ -190,18 +191,6 @@ } static void -positionate_bar(struct battle *bt) -{ - /* Bar is located at bottom. */ - bt->bar.w = window.w; - bt->bar.h = window.h * 0.12; - bt->bar.x = 0; - bt->bar.y = window.h - bt->bar.h; - - battle_bar_positionate(&bt->bar, bt); -} - -static void draw_entities(const struct battle *bt, struct battle_entity *entities, size_t entitiesz) { for (size_t i = 0; i < entitiesz; ++i) { @@ -232,7 +221,6 @@ battle_entity_init(et); positionate_team(bt); - positionate_bar(bt); positionate_names(bt); /* Start the state "opening" animation. */ @@ -333,8 +321,6 @@ { assert(bt); - battle_bar_reset(&bt->bar); - if (!bt->order_cur) { battle_order(bt); bt->order_cur = bt->order[bt->order_curindex = 0]; @@ -355,7 +341,7 @@ /* Change state depending on the kind of entity. */ if (is_team(bt, bt->order_cur->ch)) { - battle_bar_open_menu(&bt->bar); + battle_bar_start(bt->bar, bt); battle_state_menu(bt); } else battle_state_ai(bt); @@ -447,7 +433,7 @@ draw_entities(bt, bt->team, UTIL_SIZE(bt->team)); draw_entities(bt, bt->enemies, UTIL_SIZE(bt->enemies)); - battle_bar_draw(&bt->bar, bt); + battle_bar_draw(bt->bar, bt); action_stack_draw(&bt->actions[0]); action_stack_draw(&bt->actions[1]); @@ -470,5 +456,7 @@ action_stack_finish(&bt->actions[0]); action_stack_finish(&bt->actions[1]); + battle_bar_finish(bt->bar, bt); + memset(bt, 0, sizeof (*bt)); }
--- a/src/libmlk-rpg/rpg/battle.h Sun Feb 13 11:34:19 2022 +0100 +++ b/src/libmlk-rpg/rpg/battle.h Tue Feb 15 14:45:11 2022 +0100 @@ -28,7 +28,6 @@ #include <ui/frame.h> #include <ui/gridmenu.h> -#include "battle-bar.h" #include "battle-entity.h" #include "battle-state.h" #include "selection.h" @@ -36,6 +35,7 @@ union event; +struct battle_bar; struct character; struct inventory; struct item; @@ -76,7 +76,7 @@ struct drawable_stack effects; struct action_stack actions[2]; struct inventory *inventory; - struct battle_bar bar; + struct battle_bar *bar; }; CORE_BEGIN_DECLS