Mercurial > molko
changeset 235:fb304a94a05c
rpg: prepare equipment
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 26 Nov 2020 18:00:45 +0100 |
parents | c89e2f7dbc01 |
children | 4896bb07a8db |
files | doc/build.rst examples/example-battle/main.c examples/example-battle/spell-fire.c librpg/CMakeLists.txt librpg/rpg/battle-entity-state-blinking.c librpg/rpg/battle-entity-state-moving.c librpg/rpg/battle-entity.c librpg/rpg/battle-state-attacking.c librpg/rpg/battle-state-check.c librpg/rpg/battle.c librpg/rpg/character.c librpg/rpg/character.h librpg/rpg/equipment.c librpg/rpg/equipment.h |
diffstat | 14 files changed, 234 insertions(+), 33 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/build.rst Thu Nov 26 13:33:31 2020 +0100 +++ b/doc/build.rst Thu Nov 26 18:00:45 2020 +0100 @@ -33,24 +33,48 @@ features from both C versions are required. Here's a list of functionalities that are required: -From C99: +From C99 +^^^^^^^^ + +Features: - `Compound literals`_, -- `stdbool.h`_ header, -- `snprintf`_ function and friends, - `inline`_ keyword. -From C11: +Headers: + +- `stdbool.h`_ + +Functions: + +- `snprintf`_ -- `stdnoreturn.h`_ header. +From C11 +^^^^^^^^ -From POSIX: +- `stdnoreturn.h`_ + +From POSIX +^^^^^^^^^^ -We use a few parts of POSIX_ specification but try to keep its use limited as -not all platforms are POSIX compliant. +Expectations: + +- We use a few parts of POSIX_ specification but try to keep its use limited as + not all platforms are POSIX compliant. +- We assume that ``fopen``, ``malloc`` and friends set errno in case of failures. + +Functions: -- `getopt(3)`_: to parse arguments, -- We assume that ``fopen``, ``malloc`` and friends set errno in case of failures. +- `dirname`_, +- `getopt`_. + +Headers: + +- `libgen.h`_ + +Macros: + +- PATH_MAX: in limits.h. .. note:: When a POSIX requirement isn't present it is replaced by a shim specified for the platform. @@ -65,8 +89,10 @@ .. _SDL2_ttf: https://www.libsdl.org/projects/SDL_ttf .. _brew: https://brew.sh .. _cmake: http://cmake.org -.. _getopt(3): https://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html +.. _dirname: https://pubs.opengroup.org/onlinepubs/9699919799/functions/dirname.html +.. _getopt: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html .. _inline: https://en.cppreference.com/w/c/language/inline +.. _libgen.h: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/libgen.h.html .. _snprintf: https://en.cppreference.com/w/c/io/fprintf .. _stdbool.h: https://en.cppreference.com/w/c/language/arithmetic_types#Boolean_type .. _stdnoreturn.h: https://en.cppreference.com/w/c/types
--- a/examples/example-battle/main.c Thu Nov 26 13:33:31 2020 +0100 +++ b/examples/example-battle/main.c Thu Nov 26 18:00:45 2020 +0100 @@ -94,7 +94,7 @@ .mp = 50, .reset = adventurer_reset, .sprites = { - [CHARACTER_SPRITE_WALK] = ®istry_sprites[REGISTRY_TEXTURE_JOHN_WALK], + [CHARACTER_SPRITE_NORMAL] = ®istry_sprites[REGISTRY_TEXTURE_JOHN_WALK], [CHARACTER_SPRITE_SWORD] = ®istry_sprites[REGISTRY_TEXTURE_JOHN_SWORD], }, .spells = { @@ -127,7 +127,7 @@ .level = 30, .reset = haunted_wood_reset, .sprites = { - [CHARACTER_SPRITE_WALK] = ®istry_sprites[REGISTRY_TEXTURE_HAUNTED_WOOD], + [CHARACTER_SPRITE_NORMAL] = ®istry_sprites[REGISTRY_TEXTURE_HAUNTED_WOOD], }, .exec = haunted_wood_strat }; @@ -138,7 +138,7 @@ .level = 6, .reset = black_cat_reset, .sprites = { - [CHARACTER_SPRITE_WALK] = ®istry_sprites[REGISTRY_TEXTURE_BLACK_CAT], + [CHARACTER_SPRITE_NORMAL] = ®istry_sprites[REGISTRY_TEXTURE_BLACK_CAT], }, .exec = black_cat_strat }; @@ -171,8 +171,8 @@ /* Positionate the single ennemy to the left. */ align(ALIGN_LEFT, &bt->enemies[0].x, &bt->enemies[0].y, - haunted_wood.sprites[0]->cellw, - haunted_wood.sprites[0]->cellh, + haunted_wood.sprites[CHARACTER_SPRITE_NORMAL]->cellw, + haunted_wood.sprites[CHARACTER_SPRITE_NORMAL]->cellh, 0, 0, window.w, window.h); /* Black cat is near the previous monster. */
--- a/examples/example-battle/spell-fire.c Thu Nov 26 13:33:31 2020 +0100 +++ b/examples/example-battle/spell-fire.c Thu Nov 26 18:00:45 2020 +0100 @@ -51,7 +51,7 @@ { const struct data *data = act->data; const struct battle_entity *et = &data->battle->enemies[data->selection]; - const struct sprite *sprite = et->ch->sprites[CHARACTER_SPRITE_WALK]; + const struct sprite *sprite = et->ch->sprites[CHARACTER_SPRITE_NORMAL]; int x, y; align(ALIGN_CENTER,
--- a/librpg/CMakeLists.txt Thu Nov 26 13:33:31 2020 +0100 +++ b/librpg/CMakeLists.txt Thu Nov 26 18:00:45 2020 +0100 @@ -62,6 +62,8 @@ ${librpg_SOURCE_DIR}/rpg/battle-state-victory.h ${librpg_SOURCE_DIR}/rpg/character.c ${librpg_SOURCE_DIR}/rpg/character.h + ${librpg_SOURCE_DIR}/rpg/equipment.c + ${librpg_SOURCE_DIR}/rpg/equipment.h ${librpg_SOURCE_DIR}/rpg/item.c ${librpg_SOURCE_DIR}/rpg/item.h ${librpg_SOURCE_DIR}/rpg/map.c
--- a/librpg/rpg/battle-entity-state-blinking.c Thu Nov 26 13:33:31 2020 +0100 +++ b/librpg/rpg/battle-entity-state-blinking.c Thu Nov 26 18:00:45 2020 +0100 @@ -76,7 +76,7 @@ if (!(blk = alloc_new0(sizeof (*blk)))) panic(); - blk->tex = et->ch->sprites[CHARACTER_SPRITE_WALK]->texture; + blk->tex = et->ch->sprites[CHARACTER_SPRITE_NORMAL]->texture; texture_set_alpha_mod(blk->tex, TRANSPARENT); blk->state.data = blk;
--- a/librpg/rpg/battle-entity-state-moving.c Thu Nov 26 13:33:31 2020 +0100 +++ b/librpg/rpg/battle-entity-state-moving.c Thu Nov 26 18:00:45 2020 +0100 @@ -99,7 +99,7 @@ if (!(pos = alloc_new0(sizeof (*pos)))) panic(); - walksprite_init(&pos->ws, et->ch->sprites[CHARACTER_SPRITE_WALK], 40); + walksprite_init(&pos->ws, et->ch->sprites[CHARACTER_SPRITE_NORMAL], 40); pos->x = destx; pos->y = desty;
--- a/librpg/rpg/battle-entity.c Thu Nov 26 13:33:31 2020 +0100 +++ b/librpg/rpg/battle-entity.c Thu Nov 26 18:00:45 2020 +0100 @@ -50,7 +50,7 @@ assert(et); character_reset(et->ch); - texture_set_alpha_mod(et->ch->sprites[CHARACTER_SPRITE_WALK]->texture, 255); + texture_set_alpha_mod(et->ch->sprites[CHARACTER_SPRITE_NORMAL]->texture, 255); battle_entity_state_normal(et); } @@ -84,7 +84,7 @@ void battle_entity_draw_sprite(const struct battle_entity *et) { - struct sprite *sprite = et->ch->sprites[CHARACTER_SPRITE_WALK]; + struct sprite *sprite = et->ch->sprites[CHARACTER_SPRITE_NORMAL]; int row; /*
--- a/librpg/rpg/battle-state-attacking.c Thu Nov 26 13:33:31 2020 +0100 +++ b/librpg/rpg/battle-state-attacking.c Thu Nov 26 18:00:45 2020 +0100 @@ -141,7 +141,7 @@ data->origin_y = data->source->y; /* We go to the enemy. */ - x = data->target->x + data->target->ch->sprites[CHARACTER_SPRITE_WALK]->cellw; + x = data->target->x + data->target->ch->sprites[CHARACTER_SPRITE_NORMAL]->cellw; y = data->target->y; /* If it is an enemy we don't move it but blink instead. */
--- a/librpg/rpg/battle-state-check.c Thu Nov 26 13:33:31 2020 +0100 +++ b/librpg/rpg/battle-state-check.c Thu Nov 26 18:00:45 2020 +0100 @@ -56,7 +56,7 @@ return true; fade->alpha -= 10; - texture_set_alpha_mod(ch->sprites[CHARACTER_SPRITE_WALK]->texture, fade->alpha); + texture_set_alpha_mod(ch->sprites[CHARACTER_SPRITE_NORMAL]->texture, fade->alpha); } return false; @@ -67,7 +67,7 @@ { const struct fadeout *fade = act->data; - sprite_draw(fade->ch->sprites[CHARACTER_SPRITE_WALK], 0, 0, fade->x, fade->y); + sprite_draw(fade->ch->sprites[CHARACTER_SPRITE_NORMAL], 0, 0, fade->x, fade->y); } static void
--- a/librpg/rpg/battle.c Thu Nov 26 13:33:31 2020 +0100 +++ b/librpg/rpg/battle.c Thu Nov 26 18:00:45 2020 +0100 @@ -118,7 +118,7 @@ struct sprite *sprite; /* Show the character name below its sprite. */ - sprite = et->ch->sprites[CHARACTER_SPRITE_WALK]; + sprite = et->ch->sprites[CHARACTER_SPRITE_NORMAL]; et->name.text = et->ch->name; et->name.flags = LABEL_FLAGS_SHADOW; @@ -154,7 +154,7 @@ if (battle_entity_ok(&bt->team[i])) { nmemb++; - requirement += et->ch->sprites[CHARACTER_SPRITE_WALK]->cellh; + requirement += et->ch->sprites[CHARACTER_SPRITE_NORMAL]->cellh; } } @@ -167,7 +167,7 @@ if (battle_entity_ok(et)) { et->x = x; et->y = y; - y += et->ch->sprites[CHARACTER_SPRITE_WALK]->cellh + spacing; + y += et->ch->sprites[CHARACTER_SPRITE_NORMAL]->cellh + spacing; } } } @@ -336,8 +336,8 @@ id->bti.amount = amount; /* TODO: positionate better. */ - id->dw.x = et->x + target->sprites[CHARACTER_SPRITE_WALK]->cellw; - id->dw.y = et->y + target->sprites[CHARACTER_SPRITE_WALK]->cellh; + 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;
--- a/librpg/rpg/character.c Thu Nov 26 13:33:31 2020 +0100 +++ b/librpg/rpg/character.c Thu Nov 26 18:00:45 2020 +0100 @@ -21,17 +21,21 @@ #include <core/sprite.h> #include "character.h" +#include "equipment.h" bool character_ok(struct character *ch) { - return ch && ch->name && ch->type && ch->reset && sprite_ok(ch->sprites[CHARACTER_SPRITE_WALK]); + return ch && ch->name && ch->type && ch->reset && sprite_ok(ch->sprites[CHARACTER_SPRITE_NORMAL]); } const char * character_status_string(enum character_status status) { - /* We have to use a switch-case as it is a bitmask. */ + /* + * We expect the user to only specify one status as character_status + * is a bitmask. + */ switch (status) { case CHARACTER_STATUS_POISON: return "poison"; @@ -43,9 +47,14 @@ void character_reset(struct character *ch) { - assert(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
--- a/librpg/rpg/character.h Thu Nov 26 13:33:31 2020 +0100 +++ b/librpg/rpg/character.h Thu Nov 26 18:00:45 2020 +0100 @@ -45,14 +45,38 @@ /** * \brief Sprites per action. + * + * This enumeration should be synced with \ref equipment_type. */ enum character_sprite { - CHARACTER_SPRITE_WALK, /*!< Sprite for walking. */ + CHARACTER_SPRITE_AXE, /*!< Attacking with axe. */ + CHARACTER_SPRITE_BOW, /*!< Attacking with bow. */ + CHARACTER_SPRITE_CROSSBOW, /*!< Attacking with crossbow. */ + CHARACTER_SPRITE_DAGGER, /*!< Attacking with dagger. */ + CHARACTER_SPRITE_HAMMER, /*!< Attacking with hammer. */ + CHARACTER_SPRITE_NORMAL, /*!< Sprite for walking. */ + CHARACTER_SPRITE_SPIKE, /*!< Attacking with spike. */ CHARACTER_SPRITE_SWORD, /*!< Attacking with sword. */ + CHARACTER_SPRITE_WAND, /*!< Attacking with wand. */ CHARACTER_SPRITE_NUM /*!< Total number of sprites. */ }; /** + * \brief Equipment per character. + * + * This enumeration should be synced with \ref equipment_type. + */ +enum character_equipment { + CHARACTER_EQUIPMENT_GLOVES, /*!< Gloves equiped. */ + CHARACTER_EQUIPMENT_HELMET, /*!< Helmet equiped. */ + CHARACTER_EQUIPMENT_SHIELD, /*!< Shield equiped. */ + CHARACTER_EQUIPMENT_TOP, /*!< Top equiped. */ + CHARACTER_EQUIPMENT_TROUSERS, /*!< Trousers equiped. */ + CHARACTER_EQUIPMENT_WEAPON, /*!< Weapon equiped. */ + CHARACTER_EQUIPMENT_NUM /*!< Total number of equipments equiped. */ +}; + +/** * \brief Character object * * This structure owns the current character statistics used in battle. @@ -83,6 +107,11 @@ struct sprite *sprites[CHARACTER_SPRITE_NUM]; /** + * (+&) Equipments for this character. + */ + const struct equipment *equipments[CHARACTER_EQUIPMENT_NUM]; + + /** * (+&?) List of spells for this character. */ const struct spell *spells[CHARACTER_SPELL_MAX];
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/equipment.c Thu Nov 26 18:00:45 2020 +0100 @@ -0,0 +1,38 @@ +/* + * equipment.h -- character equipment + * + * 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 "character.h" +#include "equipment.h" + +bool +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/librpg/rpg/equipment.h Thu Nov 26 18:00:45 2020 +0100 @@ -0,0 +1,97 @@ +/* + * equipment.h -- character equipment + * + * 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. + */ + +#ifndef MOLKO_RPG_EQUIPMENT_H +#define MOLKO_RPG_EQUIPMENT_H + +/** + * \file equipment.h + * \brief Character equipment. + */ + +#include <stdbool.h> + +struct character; +struct texture; + +/** + * \brief Kind of equipment. + * + * There are different kind of equipments. Weapons are listed in this + * enumeration even though a character can carry only one of them at a time. On + * the other hand, a character is able to carry each of the defensive item. + */ +enum equipment_type { + /* Attack weapons. */ + EQUIPMENT_TYPE_AXE, /*!< Axe. */ + EQUIPMENT_TYPE_BOW, /*!< Bow. */ + EQUIPMENT_TYPE_CROSSBOW, /*!< Cross bow. */ + EQUIPMENT_TYPE_DAGGER, /*!< Small dagger. */ + EQUIPMENT_TYPE_HAMMER, /*!< Large hammer. */ + EQUIPMENT_TYPE_SPIKE, /*!< Spike. */ + EQUIPMENT_TYPE_SWORD, /*!< Sword. */ + EQUIPMENT_TYPE_WAND, /*!< Magic wands. */ + + /* Defense equipment. */ + EQUIPMENT_TYPE_GLOVES, /*!< Hand gloves. */ + EQUIPMENT_TYPE_HELMET, /*!< Head helmet. */ + EQUIPMENT_TYPE_SHIELD, /*!< Shield. */ + EQUIPMENT_TYPE_TOP, /*!< Top protection. */ + EQUIPMENT_TYPE_TROUSERS, /*!< Trousers. */ +}; + +/** + * \brief Equipment structure. + */ +struct equipment { + const char *name; /*!< (+&) Equipment short name. */ + const char *description; /*!< (+&) Longer description. */ + unsigned int price; /*!< (+) Standard price. */ + enum equipment_type type; /*!< (+) Kind of equipment. */ + struct texture *icon; /*!< (+&) Icon to show in menus. */ + + /** + * (+?) Function called when user equip the object. + * + * \param eq this equipment + * \param ch the character owner + */ + void (*equip)(const struct equipment *eq, struct character *ch); +}; + +/** + * Tells if this equipment object is valid. + * + * \param eq the equipment to check (may be NULL) + * \return True if valid. + */ +bool +equipment_ok(const struct equipment *eq); + +/** + * Shortcut for eq->equip (if not NULL). + * + * \pre equipment_ok(eq) + * \pre character_ok(ch) + * \param eq this equipment + * \param ch the character owner + */ +void +equipment_equip(const struct equipment *eq, struct character *ch); + +#endif /* !MOLKO_RPG_EQUIPMENT_H */