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] = &registry_sprites[REGISTRY_TEXTURE_JOHN_WALK],
+			[CHARACTER_SPRITE_NORMAL] = &registry_sprites[REGISTRY_TEXTURE_JOHN_WALK],
 			[CHARACTER_SPRITE_SWORD] = &registry_sprites[REGISTRY_TEXTURE_JOHN_SWORD],
 		},
 		.spells = {
@@ -127,7 +127,7 @@
 	.level = 30,
 	.reset = haunted_wood_reset,
 	.sprites = {
-		[CHARACTER_SPRITE_WALK] = &registry_sprites[REGISTRY_TEXTURE_HAUNTED_WOOD],
+		[CHARACTER_SPRITE_NORMAL] = &registry_sprites[REGISTRY_TEXTURE_HAUNTED_WOOD],
 	},
 	.exec = haunted_wood_strat
 };
@@ -138,7 +138,7 @@
 	.level = 6,
 	.reset = black_cat_reset,
 	.sprites = {
-		[CHARACTER_SPRITE_WALK] = &registry_sprites[REGISTRY_TEXTURE_BLACK_CAT],
+		[CHARACTER_SPRITE_NORMAL] = &registry_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 */