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);
int mask = (int)tolua_tonumber(L, 3, EQUIP_ALL);
assert(u && mask > 0);
equip_unit_mask(u, get_equipment(eqname), mask);
equip_unit_mask(u, eqname, mask);
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);
if (len > 0 && (size_t)len < sizeof(equipment)) {
equip_unit(unew, get_equipment(equipment));
equip_unit(unew, equipment);
}
if (unew != u) {
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
#define H_KRNL_CALLBACKS_H
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
@ -31,6 +33,7 @@ extern "C" {
struct resource_type;
struct callback_struct {
bool (*equip_unit)(struct unit *u, const char *eqname, int mask);
int (*cast_spell)(struct castorder *co, const char *fname);
int (*use_item)(struct unit *u, const struct item_type *itype,
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"
/* kernel includes */
#include "item.h"
#include "unit.h"
#include "callbacks.h"
#include "faction.h"
#include "item.h"
#include "race.h"
#include "spell.h"
#include "unit.h"
/* util includes */
#include <selist.h>
@ -88,80 +89,90 @@ equipment_setitem(equipment * eq, const item_type * itype, const char *value)
}
void
equipment_setcallback(struct equipment *eq,
void(*callback) (const struct equipment *, struct unit *))
equipment_setcallback(struct equipment *eq, equip_callback_fun 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) {
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) {
int sk;
for (sk = 0; sk != MAXSKILLS; ++sk) {
if (eq->skills[sk] != NULL) {
int i = dice_rand(eq->skills[sk]);
if (i > 0) {
set_level(u, (skill_t)sk, i);
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);
void equip_unit_set(struct unit *u, const equipment *eq, int mask)
{
if (mask & EQUIP_SKILLS) {
int sk;
for (sk = 0; sk != MAXSKILLS; ++sk) {
if (eq->skills[sk] != NULL) {
int i = dice_rand(eq->skills[sk]);
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_mask(u, eq->subsets[i].sets[k].set, mask);
break;
}
rnd -= eq->subsets[i].sets[k].chance;
set_level(u, (skill_t)sk, i);
if (sk == SK_STAMINA) {
u->hp = unit_max_hp(u) * u->number;
}
}
}
}
}
if (mask & EQUIP_SPECIAL) {
if (eq->callback)
eq->callback(eq, u);
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 (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 <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
@ -44,12 +46,14 @@ extern "C" {
subsetitem *sets;
} subset;
typedef void(*equip_callback_fun) (const struct equipment *, struct unit *);
typedef struct equipment {
struct itemdata *items;
char *skills[MAXSKILLS];
struct selist *spells;
struct subset *subsets;
void(*callback) (const struct equipment *, struct unit *);
equip_callback_fun callback;
} equipment;
void equipment_done(void);
@ -64,18 +68,17 @@ extern "C" {
void equipment_setskill(struct equipment *eq, skill_t sk,
const char *value);
void equipment_addspell(struct equipment *eq, const char *name, int level);
void equipment_setcallback(struct equipment *eq,
void(*callback) (const struct equipment *, struct unit *));
void equipment_setcallback(struct equipment *eq, equip_callback_fun callback);
void equip_unit(struct unit *u, const struct equipment *eq);
#define EQUIP_SKILLS (1<<1)
#define EQUIP_SPELLS (1<<2)
#define EQUIP_ITEMS (1<<3)
#define EQUIP_SPECIAL (1<<4)
#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_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
}

View File

@ -2,6 +2,7 @@
#include "magic.h"
#include <kernel/callbacks.h>
#include <kernel/equipment.h>
#include <kernel/item.h>
#include <kernel/unit.h>
@ -35,7 +36,7 @@ static void test_equipment(CuTest * tc)
equipment_addspell(eq, sp->sname, 1);
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, 5, get_level(u, SK_MAGIC));
@ -69,10 +70,35 @@ static void test_get_equipment(CuTest * tc)
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 *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_equipment);
SUITE_ADD_TEST(suite, test_get_equipment);
SUITE_ADD_TEST(suite, test_equipment_callback);
return suite;
}

View File

@ -1349,7 +1349,7 @@ static void fix_familiars(void) {
log_error("%s seems to be a familiar with no spells.",
unitname(u));
/* 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)
{
/* skills and spells: */
const struct equipment *eq;
char eqname[64];
const race *rc = u_race(fam);
set_familiar(mage, fam);
snprintf(eqname, sizeof(eqname), "fam_%s", rc->_name);
eq = get_equipment(eqname);
if (eq != NULL) {
equip_unit(fam, eq);
}
else {
if (!equip_unit(fam, eqname)) {
log_info("could not perform initialization for familiar %s.\n", rc->_name);
}
/* 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);
change_money(dragon, -un->number * 50);
equip_unit(un, get_equipment("new_dracoid"));
equip_unit(un, "new_dracoid");
unit_setstatus(un, ST_FIGHT);
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 *u = create_unit(r, f, 1, get_race(RC_SEASERPENT), 0, NULL, NULL);
fset(u, UFL_ISNEW | UFL_MOVED);
equip_unit(u, get_equipment("seed_seaserpent"));
equip_unit(u, "seed_seaserpent");
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);
}
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,
LOC(default_locale,
@ -965,7 +965,7 @@ void spawn_undead(void)
fset(u, UFL_ISNEW | UFL_MOVED);
if ((rc == get_race(RC_SKELETON) || rc == get_race(RC_ZOMBIE))
&& rng_int() % 10 < 4) {
equip_unit(u, get_equipment("rising_undead"));
equip_unit(u, "rising_undead");
}
for (i = 0; i < MAXSKILLS; i++) {

View File

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

View File

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

View File

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