Mercurial > molko
changeset 290:9948e288925b
rpg: add support for items in battle
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 08 Jan 2021 12:56:10 +0100 |
parents | 63d9fb56c609 |
children | 5d8700074dd7 |
files | libmlk-adventure/adventure/item/potion.c libmlk-adventure/adventure/molko.c libmlk-adventure/adventure/state/mainmenu.c libmlk-rpg/CMakeLists.txt libmlk-rpg/rpg/battle-bar.c libmlk-rpg/rpg/battle-bar.h libmlk-rpg/rpg/battle-state-item.c libmlk-rpg/rpg/battle-state-menu.c libmlk-rpg/rpg/battle-state-selection.c libmlk-rpg/rpg/battle-state-sub.c libmlk-rpg/rpg/battle-state.h libmlk-rpg/rpg/battle.c libmlk-rpg/rpg/battle.h libmlk-rpg/rpg/inventory.c libmlk-rpg/rpg/item.c libmlk-rpg/rpg/item.h |
diffstat | 16 files changed, 347 insertions(+), 58 deletions(-) [+] |
line wrap: on
line diff
--- a/libmlk-adventure/adventure/item/potion.c Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-adventure/adventure/item/potion.c Fri Jan 08 12:56:10 2021 +0100 @@ -20,6 +20,7 @@ #include <core/sound.h> +#include <rpg/battle.h> #include <rpg/character.h> #include <rpg/item.h> @@ -29,14 +30,32 @@ #include "potion.h" static void -exec(const struct item *i, struct character *ch) +heal(struct character *ch) +{ + ch->hp = fmin(ch->hp + 50, ch->hpmax); + sound_play(&assets_sounds[ASSETS_SOUND_ITEM_POTION], -1, 0); +} + +static void +exec_menu(const struct item *item, struct character *ch) { - sound_play(&assets_sounds[ASSETS_SOUND_ITEM_POTION], -1, 0); - ch->hp = fmin(ch->hp + 50, ch->hpmax); + (void)item; + + heal(ch); +} + +static void +exec_battle(const struct item *item, struct battle *bt, struct character *src, struct character *tgt) +{ + (void)item; + + heal(tgt); + battle_indicator_hp(bt, tgt, 50); } const struct item item_potion = { .name = N_("Potion"), .description = N_("Recover 50 HP."), - .exec = exec + .exec_menu = exec_menu, + .exec_battle = exec_battle };
--- a/libmlk-adventure/adventure/molko.c Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-adventure/adventure/molko.c Fri Jan 08 12:56:10 2021 +0100 @@ -52,6 +52,7 @@ #include "character/neth.h" +#include "item/potion.h" static jmp_buf panic_buf; @@ -97,6 +98,7 @@ game_switch(state_mainmenu_new(), true); molko.team.members[0] = &character_neth; molko.team.members[1] = &character_neth; + inventory_add(&molko.inventory, &item_potion, 100); molko_teleport("maps/map-world.map", -1, -1); #endif }
--- a/libmlk-adventure/adventure/state/mainmenu.c Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-adventure/adventure/state/mainmenu.c Fri Jan 08 12:56:10 2021 +0100 @@ -42,6 +42,7 @@ #include <adventure/molko.h> #include <adventure/adventure_p.h> +#include <adventure/item/potion.h> #include <adventure/character/neth.h> #include "mainmenu.h" @@ -67,6 +68,8 @@ character_reset(molko.team.members[0]); molko.team.members[0]->hp = molko.team.members[0]->hpmax; molko.team.members[0]->mp = molko.team.members[0]->mpmax; + inventory_add(&molko.inventory, &item_potion, 10); + molko_teleport("maps/map-world.map", -1, -1); }
--- a/libmlk-rpg/CMakeLists.txt Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-rpg/CMakeLists.txt Fri Jan 08 12:56:10 2021 +0100 @@ -46,6 +46,7 @@ ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-attacking.c ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-check.c ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-closing.c + ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-item.c ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-lost.c ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-menu.c ${libmlk-rpg_SOURCE_DIR}/rpg/battle-state-opening.c
--- a/libmlk-rpg/rpg/battle-bar.c Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-rpg/rpg/battle-bar.c Fri Jan 08 12:56:10 2021 +0100 @@ -323,6 +323,8 @@ void battle_bar_open_menu(struct battle_bar *bar) { + gridmenu_reset(&bar->sub_grid); + bar->state = BATTLE_BAR_STATE_MENU; bar->menu = BATTLE_BAR_MENU_ATTACK; } @@ -348,8 +350,11 @@ init_gridmenu(bar, bt); for (size_t i = 0; i < INVENTORY_ITEM_MAX; ++i) { - if (bt->inventory->items[i].item) - bar->sub_grid.menu[i] = bt->inventory->items[i].item->name; + 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);
--- a/libmlk-rpg/rpg/battle-bar.h Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-rpg/rpg/battle-bar.h Fri Jan 08 12:56:10 2021 +0100 @@ -81,6 +81,7 @@ enum battle_bar_menu menu; /* Sub menu selection (spells/objects). */ + char sub_items[GRIDMENU_ENTRY_MAX][128]; struct gridmenu sub_grid; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/rpg/battle-state-item.c Fri Jan 08 12:56:10 2021 +0100 @@ -0,0 +1,158 @@ +/* + * battle-state-item.c -- battle state (using item) + * + * Copyright (c) 2020 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 <core/alloc.h> +#include <core/panic.h> +#include <core/window.h> + +#include <rpg/inventory.h> +#include <rpg/item.h> + +#include <ui/align.h> +#include <ui/frame.h> +#include <ui/label.h> + +#include "battle-entity-state.h" +#include "battle-state.h" +#include "battle.h" + +enum substate { + SUBSTATE_ADVANCING, + SUBSTATE_MESSAGE, + SUBSTATE_RETURNING +}; + +struct msg { + struct frame frame; + struct label label; + unsigned int elapsed; +}; + +struct self { + enum substate substate; + struct msg msg; + struct battle_entity *source; + struct battle_entity *target; + struct battle_state state; + struct inventory_slot *slot; + int origin_x; +}; + +static bool +update(struct battle_state *st, struct battle *bt, unsigned int ticks) +{ + struct self *self = st->data; + + switch (self->substate) { + case SUBSTATE_ADVANCING: + /* Entity is updating from battle, so just inspect its status. */ + if (battle_entity_update(self->source, 0)) { + self->substate = SUBSTATE_MESSAGE; + battle_entity_state_normal(self->source); + } + break; + case SUBSTATE_MESSAGE: + self->msg.elapsed += ticks; + + if (self->msg.elapsed >= 2000) { + self->substate = SUBSTATE_RETURNING; + battle_entity_state_moving(self->source, self->origin_x, self->source->y); + } + break; + default: + if (battle_entity_update(self->source, 0)) { + battle_entity_state_normal(self->source); + battle_use(bt, self->slot->item, self->source->ch, self->target->ch); + } + break; + } + + return false; +} + +static void +draw(const struct battle_state *st, const struct battle *bt) +{ + struct self *self = st->data; + + if (self->substate == SUBSTATE_MESSAGE) { + frame_draw(&self->msg.frame); + label_draw(&self->msg.label); + } +} + +static void +finish(struct battle_state *st, struct battle *bt) +{ + (void)bt; + + free(st->data); +} + +void +battle_state_item(struct battle *bt, + struct character *source, + struct character *target, + struct inventory_slot *slot) +{ + assert(bt); + assert(source); + assert(target); + assert(slot); + + struct self *self; + unsigned int lw, lh; + + if (!(self = alloc_new0(sizeof (*self)))) + panic(); + + self->source = battle_find(bt, source); + self->target = battle_find(bt, target); + self->slot = slot; + self->origin_x = self->source->x; + + /* Prepare message frame. */ + self->msg.frame.w = window.w / 3; + self->msg.frame.h = window.h / 15; + self->msg.frame.theme = bt->theme; + + align(ALIGN_TOP, + &self->msg.frame.x, &self->msg.frame.y, self->msg.frame.w, self->msg.frame.h, + 0, 20, window.w, window.h); + + /* Prepare message label box. */ + self->msg.label.text = slot->item->name; + self->msg.label.flags = LABEL_FLAGS_SHADOW; + self->msg.label.theme = bt->theme; + label_query(&self->msg.label, &lw, &lh); + + align(ALIGN_CENTER, + &self->msg.label.x, &self->msg.label.y, lw, lh, + self->msg.frame.x, self->msg.frame.y, self->msg.frame.w, self->msg.frame.h); + + self->state.data = self; + self->state.update = update; + self->state.draw = draw; + self->state.finish = finish; + + battle_entity_state_moving(self->source, self->origin_x - 100, self->source->y); + battle_switch(bt, &self->state); +}
--- a/libmlk-rpg/rpg/battle-state-menu.c Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-rpg/rpg/battle-state-menu.c Fri Jan 08 12:56:10 2021 +0100 @@ -83,5 +83,6 @@ .handle = handle, }; + battle_bar_open_menu(&bt->bar); battle_switch(bt, &self); }
--- a/libmlk-rpg/rpg/battle-state-selection.c Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-rpg/rpg/battle-state-selection.c Fri Jan 08 12:56:10 2021 +0100 @@ -32,6 +32,8 @@ #include "battle-bar.h" #include "battle-state.h" #include "character.h" +#include "inventory.h" +#include "selection.h" #include "spell.h" struct select { @@ -40,6 +42,25 @@ }; static void +use(const struct select *select, struct battle *bt) +{ + struct inventory_slot *slot; + struct character *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->ch; + target = select->slt.index_side == 0 + ? bt->enemies[select->slt.index_character].ch + : bt->team[select->slt.index_character].ch; + + battle_state_item(bt, source, target, slot); +} + +static void attack(struct select *select, struct battle *bt) { struct character *target; @@ -121,6 +142,9 @@ case BATTLE_BAR_MENU_MAGIC: cast(select, bt); break; + case BATTLE_BAR_MENU_OBJECTS: + use(select, bt); + break; default: break; }
--- a/libmlk-rpg/rpg/battle-state-sub.c Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-rpg/rpg/battle-state-sub.c Fri Jan 08 12:56:10 2021 +0100 @@ -25,6 +25,9 @@ #include <ui/theme.h> +#include <rpg/inventory.h> +#include <rpg/item.h> + #include "battle.h" #include "battle-bar.h" #include "battle-state.h" @@ -57,26 +60,58 @@ static void start_select_object(struct battle *bt) { - (void)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 = ch->spells[bt->bar.sub_grid.selected]; - struct label label = {0}; - unsigned int lw, lh; + const struct spell *sp; - if (!sp) + if (bt->bar.sub_grid.selected >= CHARACTER_SPELL_MAX) + return; + if ((sp = ch->spells[bt->bar.sub_grid.selected])) return; - label.flags = LABEL_FLAGS_SHADOW; - label.text = sp->description; - 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); + 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 @@ -89,7 +124,6 @@ switch (ev->key.key) { case KEY_ESCAPE: /* Escape go to the previous state. */ - bt->bar.state = BATTLE_BAR_STATE_MENU; battle_state_menu(bt); return; default: @@ -120,6 +154,8 @@ if (bt->bar.menu == BATTLE_BAR_MENU_MAGIC) draw_spell_help(bt); + else if (bt->bar.menu == BATTLE_BAR_MENU_OBJECTS) + draw_object_help(bt); } void
--- a/libmlk-rpg/rpg/battle-state.h Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-rpg/rpg/battle-state.h Fri Jan 08 12:56:10 2021 +0100 @@ -33,10 +33,10 @@ #include <stdbool.h> -#include "selection.h" - struct battle; struct character; +struct inventory_slot; +struct selection; union event; @@ -68,7 +68,10 @@ battle_state_attacking(struct battle *bt, struct character *source, struct character *target); void -battle_state_check(struct battle *bt); +battle_state_item(struct battle *bt, + struct character *source, + struct character *target, + struct inventory_slot *slot); void battle_state_check(struct battle *bt);
--- a/libmlk-rpg/rpg/battle.c Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-rpg/rpg/battle.c Fri Jan 08 12:56:10 2021 +0100 @@ -40,6 +40,8 @@ #include "battle-indicator.h" #include "battle-state.h" #include "character.h" +#include "inventory.h" +#include "item.h" #include "spell.h" struct indicator { @@ -304,6 +306,24 @@ } 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); @@ -345,7 +365,7 @@ } void -battle_indicator_hp(struct battle *bt, const struct character *target, unsigned int amount) +battle_indicator_hp(struct battle *bt, const struct character *target, long amount) { assert(bt); assert(target); @@ -354,7 +374,7 @@ struct indicator *id = alloc_new0(sizeof (*id)); id->bti.color = BATTLE_INDICATOR_HP_COLOR; - id->bti.amount = amount; + id->bti.amount = labs(amount); /* TODO: positionate better. */ id->dw.x = et->x + target->sprites[CHARACTER_SPRITE_NORMAL]->cellw;
--- a/libmlk-rpg/rpg/battle.h Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-rpg/rpg/battle.h Fri Jan 08 12:56:10 2021 +0100 @@ -37,6 +37,7 @@ struct character; struct inventory; +struct item; struct music; struct selection; struct spell; @@ -78,44 +79,42 @@ }; void -battle_start(struct battle *bt); - -void -battle_next(struct battle *bt); - -struct battle_entity * -battle_find(struct battle *bt, const struct character *ch); +battle_start(struct battle *); void -battle_switch(struct battle *bt, struct battle_state *st); +battle_next(struct battle *); + +struct battle_entity * +battle_find(struct battle *, const struct character *); void -battle_order(struct battle *bt); +battle_switch(struct battle *, struct battle_state *); void -battle_attack(struct battle *bt, - struct character *source, - struct character *target); +battle_order(struct battle *); + +void +battle_attack(struct battle *, struct character *, struct character *); void -battle_cast(struct battle *bt, - struct character *source, - const struct spell *spell, - const struct selection *slt); +battle_cast(struct battle *, struct character *, const struct spell *, const struct selection *); void -battle_indicator_hp(struct battle *bt, const struct character *target, unsigned int amount); +battle_use(struct battle *, const struct item *, struct character *, struct character *); + +void +battle_indicator_hp(struct battle *, const struct character *, long); void -battle_handle(struct battle *bt, const union event *ev); +battle_handle(struct battle *, const union event *); bool -battle_update(struct battle *bt, unsigned int ticks); +battle_update(struct battle *, unsigned int); void -battle_draw(struct battle *bt); +battle_draw(struct battle *); void -battle_finish(struct battle *bt); +battle_finish(struct battle *); #endif /* MOLKO_RPG_BATTLE_H */
--- a/libmlk-rpg/rpg/inventory.c Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-rpg/rpg/inventory.c Fri Jan 08 12:56:10 2021 +0100 @@ -46,6 +46,7 @@ if (!slot) return false; + slot->item = item; slot->amount += amount; return true; @@ -59,6 +60,10 @@ struct inventory_slot *slot; - if (!(slot = find(iv, item))) + if ((slot = find(iv, item))) { slot->amount -= amount; + + if (slot->amount == 0) + slot->item = NULL; + } }
--- a/libmlk-rpg/rpg/item.c Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-rpg/rpg/item.c Fri Jan 08 12:56:10 2021 +0100 @@ -21,19 +21,24 @@ #include "item.h" void -item_exec(const struct item *item, struct character *ch) +item_exec_menu(const struct item *item, struct character *ch) { assert(item); assert(ch); - return item->exec(item, ch); + item->exec_menu(item, ch); } -bool -item_allowed(const struct item *item, struct character *ch) +void +item_exec_battle(const struct item *item, + struct battle *bt, + struct character *src, + struct character *tgt) { assert(item); - assert(ch); + assert(bt); + assert(src); + assert(tgt); - return item->allowed ? item->allowed(item, ch) : true; + item->exec_battle(item, bt, src, tgt); }
--- a/libmlk-rpg/rpg/item.h Thu Jan 07 15:52:56 2021 +0100 +++ b/libmlk-rpg/rpg/item.h Fri Jan 08 12:56:10 2021 +0100 @@ -19,8 +19,7 @@ #ifndef MOLKO_RPG_ITEM_H #define MOLKO_RPG_ITEM_H -#include <stdbool.h> - +struct battle; struct character; struct texture; @@ -28,14 +27,22 @@ const char *name; const char *description; struct texture *icon; - void (*exec)(const struct item *item, struct character *ch); - bool (*allowed)(const struct item *item, const struct character *ch); + + void (*exec_menu)(const struct item *item, struct character *ch); + + void (*exec_battle)(const struct item *item, + struct battle *bt, + struct character *src, + struct character *tgt); }; void -item_exec(const struct item *item, struct character *ch); +item_exec_menu(const struct item *item, struct character *ch); -bool -item_allowed(const struct item *item, struct character *ch); +void +item_exec_battle(const struct item *item, + struct battle *bt, + struct character *src, + struct character *tgt); #endif /* !MOLKO_RPG_ITEM_H */