create a callback mechanism for equipment.

This commit is contained in:
Enno Rehling 2018-05-11 21:30:26 +02:00
parent 5c26155f2f
commit 7e6688552b
12 changed files with 122 additions and 85 deletions

View file

@ -399,7 +399,7 @@ static int tolua_equipunit(lua_State * L)
const char *eqname = tolua_tostring(L, 2, 0); const char *eqname = tolua_tostring(L, 2, 0);
int mask = (int)tolua_tonumber(L, 3, EQUIP_ALL); int mask = (int)tolua_tonumber(L, 3, EQUIP_ALL);
assert(u && mask > 0); assert(u && mask > 0);
equip_unit_mask(u, get_equipment(eqname), mask); equip_unit_mask(u, eqname, mask);
return 0; return 0;
} }

View file

@ -263,7 +263,7 @@ void add_recruits(unit * u, int number, int wanted)
len = snprintf(equipment, sizeof(equipment), "new_%s", u_race(u)->_name); len = snprintf(equipment, sizeof(equipment), "new_%s", u_race(u)->_name);
if (len > 0 && (size_t)len < sizeof(equipment)) { if (len > 0 && (size_t)len < sizeof(equipment)) {
equip_unit(unew, get_equipment(equipment)); equip_unit(unew, equipment);
} }
if (unew != u) { if (unew != u) {
transfermen(unew, u, unew->number); transfermen(unew, u, unew->number);

View file

@ -19,6 +19,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#ifndef H_KRNL_CALLBACKS_H #ifndef H_KRNL_CALLBACKS_H
#define H_KRNL_CALLBACKS_H #define H_KRNL_CALLBACKS_H
#include <stdbool.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -31,6 +33,7 @@ extern "C" {
struct resource_type; struct resource_type;
struct callback_struct { struct callback_struct {
bool (*equip_unit)(struct unit *u, const char *eqname, int mask);
int (*cast_spell)(struct castorder *co, const char *fname); int (*cast_spell)(struct castorder *co, const char *fname);
int (*use_item)(struct unit *u, const struct item_type *itype, int (*use_item)(struct unit *u, const struct item_type *itype,
int amount, struct order *ord); int amount, struct order *ord);

View file

@ -21,11 +21,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "equipment.h" #include "equipment.h"
/* kernel includes */ /* kernel includes */
#include "item.h" #include "callbacks.h"
#include "unit.h"
#include "faction.h" #include "faction.h"
#include "item.h"
#include "race.h" #include "race.h"
#include "spell.h" #include "spell.h"
#include "unit.h"
/* util includes */ /* util includes */
#include <selist.h> #include <selist.h>
@ -88,80 +89,90 @@ equipment_setitem(equipment * eq, const item_type * itype, const char *value)
} }
void void
equipment_setcallback(struct equipment *eq, equipment_setcallback(struct equipment *eq, equip_callback_fun callback)
void(*callback) (const struct equipment *, struct unit *))
{ {
eq->callback = callback; eq->callback = callback;
} }
void equip_unit(struct unit *u, const struct equipment *eq) bool equip_unit(struct unit *u, const char *eqname)
{ {
equip_unit_mask(u, eq, EQUIP_ALL); return equip_unit_mask(u, eqname, EQUIP_ALL);
} }
void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask) bool equip_unit_mask(struct unit *u, const char *eqname, int mask)
{ {
const equipment * eq = get_equipment(eqname);
if (eq) { if (eq) {
equip_unit_set(u, eq, mask);
return true;
}
if (callbacks.equip_unit) {
return callbacks.equip_unit(u, eqname, mask);
}
return false;
}
if (mask & EQUIP_SKILLS) { void equip_unit_set(struct unit *u, const equipment *eq, int mask)
int sk; {
for (sk = 0; sk != MAXSKILLS; ++sk) { if (mask & EQUIP_SKILLS) {
if (eq->skills[sk] != NULL) { int sk;
int i = dice_rand(eq->skills[sk]); for (sk = 0; sk != MAXSKILLS; ++sk) {
if (i > 0) { if (eq->skills[sk] != NULL) {
set_level(u, (skill_t)sk, i); int i = dice_rand(eq->skills[sk]);
if (sk == SK_STAMINA) {
u->hp = unit_max_hp(u) * u->number;
}
}
}
}
}
if (mask & EQUIP_SPELLS) {
if (eq->spells) {
selist * ql = eq->spells;
int qi;
sc_mage * mage = get_mage_depr(u);
for (qi = 0; ql; selist_advance(&ql, &qi, 1)) {
lazy_spell *sbe = (lazy_spell *)selist_get(ql, qi);
spell *sp = spellref_get(sbe->spref);
unit_add_spell(u, mage, sp, sbe->level);
}
}
}
if (mask & EQUIP_ITEMS) {
itemdata *idata;
for (idata = eq->items; idata != NULL; idata = idata->next) {
int i = u->number * dice_rand(idata->value);
if (i > 0) { if (i > 0) {
i_add(&u->items, i_new(idata->itype, i)); set_level(u, (skill_t)sk, i);
} if (sk == SK_STAMINA) {
} u->hp = unit_max_hp(u) * u->number;
}
if (eq->subsets) {
int i;
for (i = 0; eq->subsets[i].sets; ++i) {
if (chance(eq->subsets[i].chance)) {
double rnd = (1 + rng_int() % 1000) / 1000.0;
int k;
for (k = 0; eq->subsets[i].sets[k].set; ++k) {
if (rnd <= eq->subsets[i].sets[k].chance) {
equip_unit_mask(u, eq->subsets[i].sets[k].set, mask);
break;
}
rnd -= eq->subsets[i].sets[k].chance;
} }
} }
} }
} }
}
if (mask & EQUIP_SPECIAL) { if (mask & EQUIP_SPELLS) {
if (eq->callback) if (eq->spells) {
eq->callback(eq, u); selist * ql = eq->spells;
int qi;
sc_mage * mage = get_mage_depr(u);
for (qi = 0; ql; selist_advance(&ql, &qi, 1)) {
lazy_spell *sbe = (lazy_spell *)selist_get(ql, qi);
spell *sp = spellref_get(sbe->spref);
unit_add_spell(u, mage, sp, sbe->level);
}
}
}
if (eq->items && mask & EQUIP_ITEMS) {
itemdata *idata;
for (idata = eq->items; idata != NULL; idata = idata->next) {
int i = u->number * dice_rand(idata->value);
if (i > 0) {
i_add(&u->items, i_new(idata->itype, i));
}
}
}
if (eq->subsets) {
int i;
for (i = 0; eq->subsets[i].sets; ++i) {
if (chance(eq->subsets[i].chance)) {
double rnd = (1 + rng_int() % 1000) / 1000.0;
int k;
for (k = 0; eq->subsets[i].sets[k].set; ++k) {
if (rnd <= eq->subsets[i].sets[k].chance) {
equip_unit_set(u, eq->subsets[i].sets[k].set, mask);
break;
}
rnd -= eq->subsets[i].sets[k].chance;
}
}
}
}
if (mask & EQUIP_SPECIAL) {
if (eq->callback) {
eq->callback(eq, u);
} }
} }
} }

View file

@ -21,6 +21,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "skill.h" #include "skill.h"
#include <stdbool.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -44,12 +46,14 @@ extern "C" {
subsetitem *sets; subsetitem *sets;
} subset; } subset;
typedef void(*equip_callback_fun) (const struct equipment *, struct unit *);
typedef struct equipment { typedef struct equipment {
struct itemdata *items; struct itemdata *items;
char *skills[MAXSKILLS]; char *skills[MAXSKILLS];
struct selist *spells; struct selist *spells;
struct subset *subsets; struct subset *subsets;
void(*callback) (const struct equipment *, struct unit *); equip_callback_fun callback;
} equipment; } equipment;
void equipment_done(void); void equipment_done(void);
@ -64,18 +68,17 @@ extern "C" {
void equipment_setskill(struct equipment *eq, skill_t sk, void equipment_setskill(struct equipment *eq, skill_t sk,
const char *value); const char *value);
void equipment_addspell(struct equipment *eq, const char *name, int level); void equipment_addspell(struct equipment *eq, const char *name, int level);
void equipment_setcallback(struct equipment *eq, void equipment_setcallback(struct equipment *eq, equip_callback_fun callback);
void(*callback) (const struct equipment *, struct unit *));
void equip_unit(struct unit *u, const struct equipment *eq);
#define EQUIP_SKILLS (1<<1) #define EQUIP_SKILLS (1<<1)
#define EQUIP_SPELLS (1<<2) #define EQUIP_SPELLS (1<<2)
#define EQUIP_ITEMS (1<<3) #define EQUIP_ITEMS (1<<3)
#define EQUIP_SPECIAL (1<<4) #define EQUIP_SPECIAL (1<<4)
#define EQUIP_ALL (0xFF) #define EQUIP_ALL (0xFF)
void equip_unit_mask(struct unit *u, const struct equipment *eq,
int mask);
void equip_items(struct item **items, const struct equipment *eq); void equip_items(struct item **items, const struct equipment *eq);
void equip_unit_set(struct unit *u, const struct equipment *eq, int mask);
bool equip_unit_mask(struct unit *u, const char *eqname, int mask);
bool equip_unit(struct unit *u, const char *eqname);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -2,6 +2,7 @@
#include "magic.h" #include "magic.h"
#include <kernel/callbacks.h>
#include <kernel/equipment.h> #include <kernel/equipment.h>
#include <kernel/item.h> #include <kernel/item.h>
#include <kernel/unit.h> #include <kernel/unit.h>
@ -35,7 +36,7 @@ static void test_equipment(CuTest * tc)
equipment_addspell(eq, sp->sname, 1); equipment_addspell(eq, sp->sname, 1);
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
equip_unit_mask(u, eq, EQUIP_ALL); equip_unit_set(u, eq, EQUIP_ALL);
CuAssertIntEquals(tc, 1, i_get(u->items, it_horses)); CuAssertIntEquals(tc, 1, i_get(u->items, it_horses));
CuAssertIntEquals(tc, 5, get_level(u, SK_MAGIC)); CuAssertIntEquals(tc, 5, get_level(u, SK_MAGIC));
@ -69,10 +70,35 @@ static void test_get_equipment(CuTest * tc)
test_teardown(); test_teardown();
} }
static bool equip_test(unit *u, const char *name, int mask) {
if (mask & EQUIP_ITEMS) {
i_change(&u->items, it_find("horse"), 1);
return true;
}
return false;
}
static void test_equipment_callback(CuTest *tc) {
unit *u;
item_type *itype;
test_setup();
itype = test_create_horse();
u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
CuAssertTrue(tc, !equip_unit_mask(u, "horse", EQUIP_ITEMS));
CuAssertPtrEquals(tc, NULL, u->items);
callbacks.equip_unit = equip_test;
CuAssertTrue(tc, equip_unit(u, "horse"));
CuAssertIntEquals(tc, 1, i_get(u->items, itype));
CuAssertTrue(tc, !equip_unit_mask(u, "horse", EQUIP_SPELLS));
CuAssertIntEquals(tc, 1, i_get(u->items, itype));
test_teardown();
}
CuSuite *get_equipment_suite(void) CuSuite *get_equipment_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_equipment); SUITE_ADD_TEST(suite, test_equipment);
SUITE_ADD_TEST(suite, test_get_equipment); SUITE_ADD_TEST(suite, test_get_equipment);
SUITE_ADD_TEST(suite, test_equipment_callback);
return suite; return suite;
} }

View file

@ -1349,7 +1349,7 @@ static void fix_familiars(void) {
log_error("%s seems to be a familiar with no spells.", log_error("%s seems to be a familiar with no spells.",
unitname(u)); unitname(u));
/* magical familiar, no spells */ /* magical familiar, no spells */
equip_unit_mask(u, eq, EQUIP_SPELLS); equip_unit_set(u, eq, EQUIP_SPELLS);
} }
} }
} }

View file

@ -2181,18 +2181,13 @@ void remove_familiar(unit * mage)
void create_newfamiliar(unit * mage, unit * fam) void create_newfamiliar(unit * mage, unit * fam)
{ {
/* skills and spells: */ /* skills and spells: */
const struct equipment *eq;
char eqname[64]; char eqname[64];
const race *rc = u_race(fam); const race *rc = u_race(fam);
set_familiar(mage, fam); set_familiar(mage, fam);
snprintf(eqname, sizeof(eqname), "fam_%s", rc->_name); snprintf(eqname, sizeof(eqname), "fam_%s", rc->_name);
eq = get_equipment(eqname); if (!equip_unit(fam, eqname)) {
if (eq != NULL) {
equip_unit(fam, eq);
}
else {
log_info("could not perform initialization for familiar %s.\n", rc->_name); log_info("could not perform initialization for familiar %s.\n", rc->_name);
} }
/* TODO: Diese Attribute beim Tod des Familiars entfernen: */ /* TODO: Diese Attribute beim Tod des Familiars entfernen: */

View file

@ -612,7 +612,7 @@ static void recruit_dracoids(unit * dragon, int size)
name_unit(un); name_unit(un);
change_money(dragon, -un->number * 50); change_money(dragon, -un->number * 50);
equip_unit(un, get_equipment("new_dracoid")); equip_unit(un, "new_dracoid");
unit_setstatus(un, ST_FIGHT); unit_setstatus(un, ST_FIGHT);
for (weapon = un->items; weapon; weapon = weapon->next) { for (weapon = un->items; weapon; weapon = weapon->next) {
@ -864,7 +864,7 @@ static int nrand(int start, int sub)
unit *spawn_seaserpent(region *r, faction *f) { unit *spawn_seaserpent(region *r, faction *f) {
unit *u = create_unit(r, f, 1, get_race(RC_SEASERPENT), 0, NULL, NULL); unit *u = create_unit(r, f, 1, get_race(RC_SEASERPENT), 0, NULL, NULL);
fset(u, UFL_ISNEW | UFL_MOVED); fset(u, UFL_ISNEW | UFL_MOVED);
equip_unit(u, get_equipment("seed_seaserpent")); equip_unit(u, "seed_seaserpent");
return u; return u;
} }
@ -903,7 +903,7 @@ void spawn_dragons(void)
u = create_unit(r, monsters, nrand(30, 20) + 1, get_race(RC_DRAGON), 0, NULL, NULL); u = create_unit(r, monsters, nrand(30, 20) + 1, get_race(RC_DRAGON), 0, NULL, NULL);
} }
fset(u, UFL_ISNEW | UFL_MOVED); fset(u, UFL_ISNEW | UFL_MOVED);
equip_unit(u, get_equipment("seed_dragon")); equip_unit(u, "seed_dragon");
log_debug("spawning %d %s in %s.\n", u->number, log_debug("spawning %d %s in %s.\n", u->number,
LOC(default_locale, LOC(default_locale,
@ -965,7 +965,7 @@ void spawn_undead(void)
fset(u, UFL_ISNEW | UFL_MOVED); fset(u, UFL_ISNEW | UFL_MOVED);
if ((rc == get_race(RC_SKELETON) || rc == get_race(RC_ZOMBIE)) if ((rc == get_race(RC_SKELETON) || rc == get_race(RC_ZOMBIE))
&& rng_int() % 10 < 4) { && rng_int() % 10 < 4) {
equip_unit(u, get_equipment("rising_undead")); equip_unit(u, "rising_undead");
} }
for (i = 0; i < MAXSKILLS; i++) { for (i = 0; i < MAXSKILLS; i++) {

View file

@ -265,7 +265,7 @@ static void get_villagers(region * r, unit * u)
u); u);
leave(newunit, true); leave(newunit, true);
fset(newunit, UFL_ISNEW | UFL_MOVED); fset(newunit, UFL_ISNEW | UFL_MOVED);
equip_unit(newunit, get_equipment("rand_villagers")); equip_unit(newunit, "rand_villagers");
} }
static void get_allies(region * r, unit * u) static void get_allies(region * r, unit * u)
@ -352,7 +352,7 @@ static void get_allies(region * r, unit * u)
newunit = newunit =
create_unit(r, u->faction, number, u->faction->race, 0, create_unit(r, u->faction, number, u->faction->race, 0,
LOC(u->faction->locale, name), u); LOC(u->faction->locale, name), u);
equip_unit(newunit, get_equipment(equip)); equip_unit(newunit, equip);
u_setfaction(newunit, u->faction); u_setfaction(newunit, u->faction);
set_racename(&newunit->attribs, get_racename(u->attribs)); set_racename(&newunit->attribs, get_racename(u->attribs));

View file

@ -181,7 +181,7 @@ void spawn_braineaters(float chance)
if (next-- == 0) { if (next-- == 0) {
u = create_unit(r, f, 1 + rng_int() % 10 + rng_int() % 10, u = create_unit(r, f, 1 + rng_int() % 10 + rng_int() % 10,
rc_brain, 0, NULL, NULL); rc_brain, 0, NULL, NULL);
equip_unit(u, get_equipment("seed_braineater")); equip_unit(u, "seed_braineater");
next = rng_int() % (int)(chance * 100); next = rng_int() % (int)(chance * 100);
} }

View file

@ -875,8 +875,7 @@ static void add_callbacks(equipment * eq, xmlNodeSetPtr nsetItems)
if (propValue != NULL) { if (propValue != NULL) {
fun = get_function((const char *)propValue); fun = get_function((const char *)propValue);
if (fun) { if (fun) {
equipment_setcallback(eq, (void(*)(const struct equipment *, equipment_setcallback(eq, (equip_callback_fun)fun);
struct unit *))fun);
} }
xmlFree(propValue); xmlFree(propValue);
} }