server/src/kernel/item.c

1257 lines
30 KiB
C
Raw Normal View History

2010-08-08 10:06:34 +02:00
/*
Copyright (c) 1998-2010, Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
Christian Schlittchen <corwin@amber.kn-bremen.de>
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 <platform.h>
#include <kernel/config.h>
#include "item.h"
#include <attributes/key.h>
#include "alchemy.h"
#include "build.h"
#include "faction.h"
#include "message.h"
#include "pool.h"
#include "race.h"
#include "region.h"
#include "save.h"
#include "skill.h"
#include "terrain.h"
#include "unit.h"
/* triggers includes */
#include <triggers/changerace.h>
#include <triggers/timeout.h>
/* util includes */
#include <util/attrib.h>
#include <util/base36.h>
#include <util/critbit.h>
2010-08-08 10:06:34 +02:00
#include <util/event.h>
#include <util/functions.h>
#include <util/goodies.h>
2010-08-15 04:41:18 +02:00
#include <util/log.h>
2010-08-08 10:06:34 +02:00
#include <util/language.h>
#include <util/message.h>
#include <util/umlaut.h>
#include <util/rng.h>
/* libc includes */
#include <assert.h>
#include <stdlib.h>
#include <string.h>
static critbit_tree inames[MAXLOCALES];
static critbit_tree rnames[MAXLOCALES];
static critbit_tree cb_resources;
static critbit_tree cb_items;
2011-03-07 08:02:35 +01:00
luxury_type *luxurytypes;
potion_type *potiontypes;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
static int res_changeaura(unit * u, const resource_type * rtype, int delta)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
assert(rtype != NULL);
2010-08-08 10:06:34 +02:00
change_spellpoints(u, delta);
return 0;
}
2011-03-07 08:02:35 +01:00
static int res_changeperson(unit * u, const resource_type * rtype, int delta)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
assert(rtype != NULL || !"not implemented");
scale_number(u, u->number + delta);
2010-08-08 10:06:34 +02:00
return 0;
}
2011-03-07 08:02:35 +01:00
static int res_changepermaura(unit * u, const resource_type * rtype, int delta)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
assert(rtype != NULL);
2010-08-08 10:06:34 +02:00
change_maxspellpoints(u, delta);
return 0;
}
2011-03-07 08:02:35 +01:00
static int res_changehp(unit * u, const resource_type * rtype, int delta)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
assert(rtype != NULL);
u->hp += delta;
2010-08-08 10:06:34 +02:00
return 0;
}
2011-03-07 08:02:35 +01:00
static int res_changepeasants(unit * u, const resource_type * rtype, int delta)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
assert(rtype != NULL && u->region->land);
u->region->land->peasants += delta;
2010-08-08 10:06:34 +02:00
return 0;
}
2011-03-07 08:02:35 +01:00
int res_changeitem(unit * u, const resource_type * rtype, int delta)
2010-08-08 10:06:34 +02:00
{
int num;
2011-03-07 08:02:35 +01:00
if (rtype == oldresourcetype[R_STONE] && u->race == new_race[RC_STONEGOLEM]
&& delta <= 0) {
2010-08-08 10:06:34 +02:00
int reduce = delta / GOLEM_STONE;
2011-03-07 08:02:35 +01:00
if (delta % GOLEM_STONE != 0)
--reduce;
scale_number(u, u->number + reduce);
2010-08-08 10:06:34 +02:00
num = u->number;
2011-03-07 08:02:35 +01:00
} else if (rtype == oldresourcetype[R_IRON]
&& u->race == new_race[RC_IRONGOLEM] && delta <= 0) {
2010-08-08 10:06:34 +02:00
int reduce = delta / GOLEM_IRON;
2011-03-07 08:02:35 +01:00
if (delta % GOLEM_IRON != 0)
--reduce;
scale_number(u, u->number + reduce);
2010-08-08 10:06:34 +02:00
num = u->number;
} else {
2011-03-07 08:02:35 +01:00
const item_type *itype = resource2item(rtype);
item *i;
assert(itype != NULL);
2010-08-08 10:06:34 +02:00
i = i_change(&u->items, itype, delta);
2011-03-07 08:02:35 +01:00
if (i == NULL)
return 0;
2010-08-08 10:06:34 +02:00
num = i->number;
}
return num;
}
2011-03-07 08:02:35 +01:00
const char *resourcename(const resource_type * rtype, int flags)
2010-08-08 10:06:34 +02:00
{
int i = 0;
if (rtype) {
2011-03-07 08:02:35 +01:00
if (rtype->name)
return rtype->name(rtype, flags);
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
if (flags & NMF_PLURAL)
i = 1;
2010-08-08 10:06:34 +02:00
if (flags & NMF_APPEARANCE && rtype->_appearance[i]) {
return rtype->_appearance[i];
}
return rtype->_name[i];
}
return "none";
}
2011-03-07 08:02:35 +01:00
resource_type *new_resourcetype(const char **names, const char **appearances,
int flags)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
resource_type *rtype = rt_find(names[0]);
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
if (rtype == NULL) {
2010-08-08 10:06:34 +02:00
int i;
rtype = (resource_type *)calloc(sizeof(resource_type), 1);
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
for (i = 0; i != 2; ++i) {
2010-08-08 10:06:34 +02:00
rtype->_name[i] = strdup(names[i]);
2011-03-07 08:02:35 +01:00
if (appearances)
rtype->_appearance[i] = strdup(appearances[i]);
else
rtype->_appearance[i] = NULL;
2010-08-08 10:06:34 +02:00
}
}
#ifndef NDEBUG
else {
/* TODO: check that this is the same type */
}
#endif
rtype->flags |= flags;
return rtype;
}
2011-03-07 08:02:35 +01:00
void it_register(item_type * itype)
2010-08-08 10:06:34 +02:00
{
char buffer[64];
const char * name = itype->rtype->_name[0];
size_t len = strlen(name);
assert(len<sizeof(buffer)-sizeof(itype));
len = cb_new_kv(name, len, &itype, sizeof(itype), buffer);
if (cb_insert(&cb_items, buffer, len)) {
2010-08-08 10:06:34 +02:00
rt_register(itype->rtype);
}
}
2011-03-07 08:02:35 +01:00
item_type *new_itemtype(resource_type * rtype,
int iflags, int weight, int capacity)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
item_type *itype;
2010-08-08 10:06:34 +02:00
assert(resource2item(rtype) == NULL);
assert(rtype->flags & RTF_ITEM);
itype = calloc(sizeof(item_type), 1);
itype->rtype = rtype;
2012-05-20 01:55:03 +02:00
rtype->itype = itype;
2010-08-08 10:06:34 +02:00
itype->weight = weight;
itype->capacity = capacity;
itype->flags |= iflags;
it_register(itype);
rtype->uchange = res_changeitem;
return itype;
}
2011-03-07 08:02:35 +01:00
static void lt_register(luxury_type * ltype)
2010-08-08 10:06:34 +02:00
{
ltype->itype->rtype->ltype = ltype;
ltype->next = luxurytypes;
luxurytypes = ltype;
}
2011-03-07 08:02:35 +01:00
luxury_type *new_luxurytype(item_type * itype, int price)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
luxury_type *ltype;
2010-08-08 10:06:34 +02:00
assert(resource2luxury(itype->rtype) == NULL);
ltype = calloc(sizeof(luxury_type), 1);
ltype->itype = itype;
ltype->price = price;
lt_register(ltype);
return ltype;
}
2011-03-07 08:02:35 +01:00
weapon_type *new_weapontype(item_type * itype,
int wflags, double magres, const char *damage[], int offmod, int defmod,
int reload, skill_t sk, int minskill)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
weapon_type *wtype;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
assert(resource2weapon(itype->rtype) == NULL);
2010-08-08 10:06:34 +02:00
wtype = calloc(sizeof(weapon_type), 1);
if (damage) {
wtype->damage[0] = strdup(damage[0]);
wtype->damage[1] = strdup(damage[1]);
}
wtype->defmod = defmod;
wtype->flags |= wflags;
wtype->itype = itype;
wtype->magres = magres;
wtype->minskill = minskill;
wtype->offmod = offmod;
wtype->reload = reload;
wtype->skill = sk;
itype->rtype->wtype = wtype;
return wtype;
}
2011-03-07 08:02:35 +01:00
armor_type *new_armortype(item_type * itype, double penalty, double magres,
int prot, unsigned int flags)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
armor_type *atype;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
assert(itype->rtype->atype == NULL);
2010-08-08 10:06:34 +02:00
atype = calloc(sizeof(armor_type), 1);
atype->itype = itype;
atype->penalty = penalty;
atype->magres = magres;
atype->prot = prot;
atype->flags = flags;
itype->rtype->atype = atype;
return atype;
}
2011-03-07 08:02:35 +01:00
static void pt_register(potion_type * ptype)
2010-08-08 10:06:34 +02:00
{
ptype->itype->rtype->ptype = ptype;
ptype->next = potiontypes;
potiontypes = ptype;
}
2011-03-07 08:02:35 +01:00
potion_type *new_potiontype(item_type * itype, int level)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
potion_type *ptype;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
assert(resource2potion(itype->rtype) == NULL);
2010-08-08 10:06:34 +02:00
ptype = (potion_type *)calloc(sizeof(potion_type), 1);
2010-08-08 10:06:34 +02:00
ptype->itype = itype;
ptype->level = level;
pt_register(ptype);
return ptype;
}
2011-03-07 08:02:35 +01:00
void rt_register(resource_type * rtype)
2010-08-08 10:06:34 +02:00
{
char buffer[64];
const char * name = rtype->_name[0];
size_t len = strlen(name);
2010-08-08 10:06:34 +02:00
assert(len<sizeof(buffer)-sizeof(rtype));
len = cb_new_kv(name, len, &rtype, sizeof(rtype), buffer);
cb_insert(&cb_resources, buffer, len);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
const resource_type *item2resource(const item_type * itype)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
return itype ? itype->rtype : NULL;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
const item_type *resource2item(const resource_type * rtype)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
return rtype ? rtype->itype : NULL;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
const weapon_type *resource2weapon(const resource_type * rtype)
{
2010-08-08 10:06:34 +02:00
return rtype->wtype;
}
2011-03-07 08:02:35 +01:00
const luxury_type *resource2luxury(const resource_type * rtype)
2010-08-08 10:06:34 +02:00
{
#ifdef AT_LTYPE
2011-03-07 08:02:35 +01:00
attrib *a = a_find(rtype->attribs, &at_ltype);
if (a)
return (const luxury_type *)a->data.v;
2010-08-08 10:06:34 +02:00
return NULL;
#else
return rtype->ltype;
#endif
}
2011-03-07 08:02:35 +01:00
const potion_type *resource2potion(const resource_type * rtype)
2010-08-08 10:06:34 +02:00
{
#ifdef AT_PTYPE
2011-03-07 08:02:35 +01:00
attrib *a = a_find(rtype->attribs, &at_ptype);
if (a)
return (const potion_type *)a->data.v;
2010-08-08 10:06:34 +02:00
return NULL;
#else
return rtype->ptype;
#endif
}
2011-03-07 08:02:35 +01:00
resource_type *rt_find(const char *name)
2010-08-08 10:06:34 +02:00
{
const void * matches;
resource_type *result = 0;
2011-03-07 08:02:35 +01:00
if (cb_find_prefix(&cb_resources, name, strlen(name)+1, &matches, 1, 0)) {
cb_get_kv(matches, &result, sizeof(result));
2010-08-08 10:06:34 +02:00
}
return result;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static const char *it_aliases[][2] = {
{"Runenschwert", "runesword"},
{"p12", "truthpotion"},
{"p1", "goliathwater"},
{"p4", "ointment"},
{"p5", "peasantblood"},
{"p8", "nestwarmth"},
{"diamond", "adamantium"},
{"diamondaxe", "adamantiumaxe"},
{"diamondplate", "adamantiumplate"},
{"aoh", "ao_healing"},
{NULL, NULL},
2010-08-08 10:06:34 +02:00
};
2011-03-07 08:02:35 +01:00
static const char *it_alias(const char *zname)
2010-08-08 10:06:34 +02:00
{
int i;
2011-03-07 08:02:35 +01:00
for (i = 0; it_aliases[i][0]; ++i) {
if (strcmp(it_aliases[i][0], zname) == 0)
return it_aliases[i][1];
2010-08-08 10:06:34 +02:00
}
return zname;
}
2011-03-07 08:02:35 +01:00
item_type *it_find(const char *zname)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *name = it_alias(zname);
const void * matches;
item_type *result = 0;
2010-08-08 10:06:34 +02:00
if (cb_find_prefix(&cb_items, name, strlen(name)+1, &matches, 1, 0)) {
cb_get_kv(matches, &result, sizeof(result));
2010-08-08 10:06:34 +02:00
}
return result;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
item **i_find(item ** i, const item_type * it)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
while (*i && (*i)->type != it)
i = &(*i)->next;
2010-08-08 10:06:34 +02:00
return i;
}
2011-03-07 08:02:35 +01:00
item *const *i_findc(item * const *i, const item_type * it)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
while (*i && (*i)->type != it) {
2010-08-08 10:06:34 +02:00
i = &(*i)->next;
}
return i;
}
2011-03-07 08:02:35 +01:00
int i_get(const item * i, const item_type * it)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
i = *i_find((item **) & i, it);
if (i)
return i->number;
2010-08-08 10:06:34 +02:00
return 0;
}
2011-03-07 08:02:35 +01:00
item *i_add(item ** pi, item * i)
2010-08-08 10:06:34 +02:00
{
assert(i && i->type && !i->next);
while (*pi) {
int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]);
2011-03-07 08:02:35 +01:00
if (d >= 0)
break;
2010-08-08 10:06:34 +02:00
pi = &(*pi)->next;
}
2011-03-07 08:02:35 +01:00
if (*pi && (*pi)->type == i->type) {
2010-08-08 10:06:34 +02:00
(*pi)->number += i->number;
2011-03-07 08:02:35 +01:00
assert((*pi)->number >= 0);
2010-08-08 10:06:34 +02:00
i_free(i);
} else {
i->next = *pi;
*pi = i;
}
return *pi;
}
2011-03-07 08:02:35 +01:00
void i_merge(item ** pi, item ** si)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
item *i = *si;
2010-08-08 10:06:34 +02:00
while (i) {
2011-03-07 08:02:35 +01:00
item *itmp;
2010-08-08 10:06:34 +02:00
while (*pi) {
int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]);
2011-03-07 08:02:35 +01:00
if (d >= 0)
break;
pi = &(*pi)->next;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (*pi && (*pi)->type == i->type) {
2010-08-08 10:06:34 +02:00
(*pi)->number += i->number;
2011-03-07 08:02:35 +01:00
assert((*pi)->number >= 0);
2010-08-08 10:06:34 +02:00
i_free(i_remove(&i, i));
} else {
itmp = i->next;
2011-03-07 08:02:35 +01:00
i->next = *pi;
2010-08-08 10:06:34 +02:00
*pi = i;
i = itmp;
}
}
2011-03-07 08:02:35 +01:00
*si = NULL;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
item *i_change(item ** pi, const item_type * itype, int delta)
2010-08-08 10:06:34 +02:00
{
assert(itype);
while (*pi) {
int d = strcmp((*pi)->type->rtype->_name[0], itype->rtype->_name[0]);
2011-03-07 08:02:35 +01:00
if (d >= 0)
break;
pi = &(*pi)->next;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (!*pi || (*pi)->type != itype) {
item *i;
if (delta == 0)
return NULL;
2010-08-08 10:06:34 +02:00
i = i_new(itype, delta);
i->next = *pi;
*pi = i;
} else {
2011-03-07 08:02:35 +01:00
item *i = *pi;
i->number += delta;
if (i->number < 0) {
log_error("serious accounting error. number of items is %d.\n", i->number);
2011-03-07 17:26:50 +01:00
/* FIXME what's this supposed to mean??
2011-03-07 08:02:35 +01:00
assert(i >= 0);
2011-03-07 17:26:50 +01:00
*/
2010-08-08 10:06:34 +02:00
i->number = 0;
}
2011-03-07 08:02:35 +01:00
if (i->number == 0) {
2010-08-08 10:06:34 +02:00
*pi = i->next;
i_free(i);
return NULL;
}
}
return *pi;
}
2011-03-07 08:02:35 +01:00
item *i_remove(item ** pi, item * i)
2010-08-08 10:06:34 +02:00
{
assert(i);
2011-03-07 08:02:35 +01:00
while ((*pi)->type != i->type)
pi = &(*pi)->next;
2010-08-08 10:06:34 +02:00
assert(*pi);
*pi = i->next;
i->next = NULL;
return i;
}
2011-03-07 08:02:35 +01:00
static item *icache;
2010-08-08 10:06:34 +02:00
static int icache_size;
#define ICACHE_MAX 100
2011-03-07 08:02:35 +01:00
void i_free(item * i)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
if (icache_size >= ICACHE_MAX) {
2010-08-08 10:06:34 +02:00
free(i);
} else {
i->next = icache;
icache = i;
++icache_size;
}
}
2011-03-07 08:02:35 +01:00
void i_freeall(item ** i)
{
2010-08-08 10:06:34 +02:00
item *in;
2011-03-07 08:02:35 +01:00
while (*i) {
2010-08-08 10:06:34 +02:00
in = (*i)->next;
i_free(*i);
*i = in;
}
}
2011-03-07 08:02:35 +01:00
item *i_new(const item_type * itype, int size)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
item *i;
if (icache_size > 0) {
2010-08-08 10:06:34 +02:00
i = icache;
icache = i->next;
--icache_size;
} else {
i = malloc(sizeof(item));
}
assert(itype);
i->next = NULL;
i->type = itype;
i->number = size;
2011-03-07 08:02:35 +01:00
assert(i->number >= 0);
2010-08-08 10:06:34 +02:00
return i;
}
#include "region.h"
static int
2011-03-07 08:02:35 +01:00
give_horses(unit * s, unit * d, const item_type * itype, int n,
struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
if (d == NULL) {
2010-08-08 10:06:34 +02:00
int use = use_pooled(s, item2resource(itype), GET_SLACK, n);
2011-03-07 08:02:35 +01:00
if (use < n)
use +=
use_pooled(s, item2resource(itype), GET_RESERVE | GET_POOLED_SLACK,
n - use);
2010-08-08 10:06:34 +02:00
rsethorses(s->region, rhorses(s->region) + use);
return 0;
}
2011-03-07 08:02:35 +01:00
return -1; /* use the mechanism */
2010-08-08 10:06:34 +02:00
}
static int
2011-03-07 08:02:35 +01:00
give_money(unit * s, unit * d, const item_type * itype, int n,
struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
if (d == NULL) {
2010-08-08 10:06:34 +02:00
int use = use_pooled(s, item2resource(itype), GET_SLACK, n);
2011-03-07 08:02:35 +01:00
if (use < n)
use +=
use_pooled(s, item2resource(itype), GET_RESERVE | GET_POOLED_SLACK,
n - use);
2010-08-08 10:06:34 +02:00
rsetmoney(s->region, rmoney(s->region) + use);
return 0;
}
2011-03-07 08:02:35 +01:00
return -1; /* use the mechanism */
2010-08-08 10:06:34 +02:00
}
#define R_MINOTHER R_SILVER
#define R_MINHERB R_PLAIN_1
#define R_MINPOTION R_FAST
#define R_MINITEM R_IRON
#define MAXITEMS MAX_ITEMS
#define MAXRESOURCES MAX_RESOURCES
#define MAXHERBS MAX_HERBS
#define MAXPOTIONS MAX_POTIONS
#define MAXHERBSPERPOTION 6
#define FIRSTLUXURY (I_BALM)
#define LASTLUXURY (I_INCENSE +1)
#define MAXLUXURIES (LASTLUXURY - FIRSTLUXURY)
2011-03-07 08:02:35 +01:00
const item_type *olditemtype[MAXITEMS + 1];
const resource_type *oldresourcetype[MAXRESOURCES + 1];
const potion_type *oldpotiontype[MAXPOTIONS + 1];
2010-08-08 10:06:34 +02:00
/*** alte items ***/
2011-03-07 08:02:35 +01:00
int get_item(const unit * u, item_t it)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const item_type *type = olditemtype[it];
const item *i = *i_findc(&u->items, type);
if (i)
assert(i->number >= 0);
return i ? i->number : 0;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int set_item(unit * u, item_t it, int value)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const item_type *type = olditemtype[it];
item *i;
assert(type);
i = *i_find(&u->items, type);
2010-08-08 10:06:34 +02:00
if (!i) {
i = i_add(&u->items, i_new(type, value));
} else {
i->number = value;
2011-03-07 08:02:35 +01:00
assert(i->number >= 0);
2010-08-08 10:06:34 +02:00
}
return value;
}
static int
2011-03-07 08:02:35 +01:00
use_birthdayamulet(unit * u, const struct item_type *itype, int amount,
struct order *ord)
2010-08-08 10:06:34 +02:00
{
direction_t d;
2011-03-07 08:02:35 +01:00
message *msg = msg_message("meow", "");
2010-08-08 10:06:34 +02:00
unused(ord);
unused(amount);
unused(itype);
add_message(&u->region->msgs, msg);
2011-03-07 08:02:35 +01:00
for (d = 0; d < MAXDIRECTIONS; d++) {
region *tr = rconnect(u->region, d);
if (tr)
add_message(&tr->msgs, msg);
2010-08-08 10:06:34 +02:00
}
msg_release(msg);
return 0;
}
/* t_item::flags */
#define FL_ITEM_CURSED (1<<0)
#define FL_ITEM_NOTLOST (1<<1)
2011-03-07 08:02:35 +01:00
#define FL_ITEM_NOTINBAG (1<<2) /* nicht im Bag Of Holding */
2010-08-08 10:06:34 +02:00
#define FL_ITEM_ANIMAL (1<<3) /* ist ein Tier */
#define FL_ITEM_MOUNT ((1<<4) | FL_ITEM_ANIMAL) /* ist ein Reittier */
/* ------------------------------------------------------------- */
/* Kann auch von Nichtmagier benutzt werden, modifiziert Taktik f<>r diese
* Runde um -1 - 4 Punkte. */
static int
2011-03-07 08:02:35 +01:00
use_tacticcrystal(unit * u, const struct item_type *itype, int amount,
struct order *ord)
2010-08-08 10:06:34 +02:00
{
int i;
2011-03-07 08:02:35 +01:00
for (i = 0; i != amount; ++i) {
int duration = 1; /* wirkt nur eine Runde */
float power = 5; /* Widerstand gegen Antimagiespr<70>che, ist in diesem
Fall egal, da der curse f<EFBFBD>r den Kampf gelten soll,
der vor den Antimagiezaubern passiert */
curse *c;
2010-08-08 10:06:34 +02:00
double effect;
2011-03-07 08:02:35 +01:00
effect = rng_int() % 6 - 1;
2010-08-08 10:06:34 +02:00
c = create_curse(u, &u->attribs, ct_find("skillmod"), power,
duration, effect, u->number);
c->data.i = SK_TACTICS;
unused(ord);
}
use_pooled(u, itype->rtype, GET_DEFAULT, amount);
ADDMSG(&u->faction->msgs, msg_message("use_tacticcrystal",
2011-03-07 08:02:35 +01:00
"unit region", u, u->region));
2010-08-08 10:06:34 +02:00
return 0;
}
typedef struct t_item {
const char *name;
/* [0]: Einzahl f<>r eigene; [1]: Mehrzahl f<>r eigene;
2011-03-07 08:02:35 +01:00
* [2]: Einzahl f<EFBFBD>r Fremde; [3]: Mehrzahl f<EFBFBD>r Fremde */
2010-08-08 10:06:34 +02:00
boolean is_resource;
skill_t skill;
int minskill;
int gewicht;
int preis;
unsigned int flags;
2011-03-07 08:02:35 +01:00
void (*benutze_funktion) (struct region *, struct unit *, int amount,
struct order *);
2010-08-08 10:06:34 +02:00
} t_item;
2011-03-07 08:02:35 +01:00
const char *itemnames[MAXITEMS] = {
2010-08-08 10:06:34 +02:00
"iron", "stone", "horse", "ao_healing",
"aots", "roi", "rop", "ao_chastity",
"laen", "fairyboot", "aoc", "pegasus",
"elvenhorse", "dolphin", "roqf", "trollbelt",
"presspass", "aurafocus", "sphereofinv", "magicbag",
"magicherbbag", "dreameye"
};
#include "move.h"
static int
mod_elves_only(const unit * u, const region * r, skill_t sk, int value)
{
2011-03-07 08:02:35 +01:00
if (u->race == new_race[RC_ELF])
return value;
2010-08-08 10:06:34 +02:00
unused(r);
return -118;
}
static int
mod_dwarves_only(const unit * u, const region * r, skill_t sk, int value)
{
2011-03-07 08:02:35 +01:00
if (u->race == new_race[RC_DWARF])
return value;
2010-08-08 10:06:34 +02:00
unused(r);
return -118;
}
2011-03-07 08:02:35 +01:00
static void init_olditems(void)
2010-08-08 10:06:34 +02:00
{
item_t i;
2011-03-07 08:02:35 +01:00
for (i = 0; i != MAXITEMS; ++i) {
2010-08-08 10:06:34 +02:00
/* item is defined in XML file, but IT_XYZ enum still in use */
2011-03-07 08:02:35 +01:00
const item_type *itype = it_find(itemnames[i]);
2010-08-08 10:06:34 +02:00
if (itype) {
olditemtype[i] = itype;
oldresourcetype[i] = itype->rtype;
}
}
}
2011-03-07 08:02:35 +01:00
static int heal(unit * user, int effect)
2010-08-08 10:06:34 +02:00
{
int req = unit_max_hp(user) * user->number - user->hp;
2011-03-07 08:02:35 +01:00
if (req > 0) {
2010-08-08 10:06:34 +02:00
req = MIN(req, effect);
effect -= req;
user->hp += req;
}
return effect;
}
2011-03-07 08:02:35 +01:00
void
register_item_give(int (*foo) (struct unit *, struct unit *,
const struct item_type *, int, struct order *), const char *name)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
register_function((pf_generic) foo, name);
2010-08-08 10:06:34 +02:00
}
void
2011-03-07 08:02:35 +01:00
register_item_use(int (*foo) (struct unit *, const struct item_type *, int,
struct order *), const char *name)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
register_function((pf_generic) foo, name);
2010-08-08 10:06:34 +02:00
}
void
2011-03-07 08:02:35 +01:00
register_item_useonother(int (*foo) (struct unit *, int,
const struct item_type *, int, struct order *), const char *name)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
register_function((pf_generic) foo, name);
2010-08-08 10:06:34 +02:00
}
static int
2011-03-07 08:02:35 +01:00
use_healingpotion(struct unit *user, const struct item_type *itype, int amount,
struct order *ord)
2010-08-08 10:06:34 +02:00
{
int effect = amount * 400;
2011-03-07 08:02:35 +01:00
unit *u = user->region->units;
2010-08-08 10:06:34 +02:00
effect = heal(user, effect);
2011-03-07 08:02:35 +01:00
while (effect > 0 && u != NULL) {
if (u->faction == user->faction) {
2010-08-08 10:06:34 +02:00
effect = heal(u, effect);
}
u = u->next;
}
2011-03-07 08:02:35 +01:00
use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
amount);
2010-08-08 10:06:34 +02:00
usetpotionuse(user, itype->rtype->ptype);
ADDMSG(&user->faction->msgs, msg_message("usepotion",
2011-03-07 08:02:35 +01:00
"unit potion", user, itype->rtype));
2010-08-08 10:06:34 +02:00
return 0;
}
static int
2011-03-07 08:02:35 +01:00
use_warmthpotion(struct unit *u, const struct item_type *itype, int amount,
struct order *ord)
2010-08-08 10:06:34 +02:00
{
if (u->faction->race == new_race[RC_INSECT]) {
fset(u, UFL_WARMTH);
} else {
/* nur f<>r insekten: */
cmistake(u, ord, 163, MSG_EVENT);
return ECUSTOM;
}
2011-03-07 08:02:35 +01:00
use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
amount);
2010-08-08 10:06:34 +02:00
usetpotionuse(u, itype->rtype->ptype);
ADDMSG(&u->faction->msgs, msg_message("usepotion",
2011-03-07 08:02:35 +01:00
"unit potion", u, itype->rtype));
2010-08-08 10:06:34 +02:00
return 0;
}
static int
2011-03-07 08:02:35 +01:00
use_foolpotion(struct unit *u, int targetno, const struct item_type *itype,
int amount, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
unit *target = findunit(targetno);
if (target == NULL || u->region != target->region) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
""));
2010-08-08 10:06:34 +02:00
return ECUSTOM;
}
2011-03-07 08:02:35 +01:00
if (effskill(u, SK_STEALTH) <= effskill(target, SK_PERCEPTION)) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 64, MSG_EVENT);
return ECUSTOM;
}
ADDMSG(&u->faction->msgs, msg_message("givedumb",
2011-03-07 08:02:35 +01:00
"unit recipient amount", u, target, amount));
2010-08-08 10:06:34 +02:00
change_effect(target, itype->rtype->ptype, amount);
use_pooled(u, itype->rtype, GET_DEFAULT, amount);
return 0;
}
static int
2011-03-07 08:02:35 +01:00
use_bloodpotion(struct unit *u, const struct item_type *itype, int amount,
struct order *ord)
2010-08-08 10:06:34 +02:00
{
if (u->race == new_race[RC_DAEMON]) {
2011-03-07 08:02:35 +01:00
change_effect(u, itype->rtype->ptype, 100 * amount);
2010-08-08 10:06:34 +02:00
} else {
2011-03-07 08:02:35 +01:00
const race *irace = u_irace(u);
2010-08-08 10:06:34 +02:00
if (irace == u->race) {
2011-03-07 08:02:35 +01:00
static race *rcfailure;
2010-08-08 10:06:34 +02:00
if (!rcfailure) {
rcfailure = rc_find("smurf");
2011-03-07 08:02:35 +01:00
if (!rcfailure)
rcfailure = rc_find("toad");
2010-08-08 10:06:34 +02:00
}
if (rcfailure) {
2011-03-07 08:02:35 +01:00
trigger *trestore = trigger_changerace(u, u->race, irace);
2010-08-08 10:06:34 +02:00
if (trestore) {
int duration = 2 + rng_int() % 8;
2011-03-07 08:02:35 +01:00
add_trigger(&u->attribs, "timer", trigger_timeout(duration,
trestore));
2010-08-08 10:06:34 +02:00
u->irace = NULL;
u->race = rcfailure;
}
}
}
}
2011-03-07 08:02:35 +01:00
use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
amount);
2010-08-08 10:06:34 +02:00
usetpotionuse(u, itype->rtype->ptype);
ADDMSG(&u->faction->msgs, msg_message("usepotion",
2011-03-07 08:02:35 +01:00
"unit potion", u, itype->rtype));
2010-08-08 10:06:34 +02:00
return 0;
}
#include <attributes/fleechance.h>
static int
2011-03-07 08:02:35 +01:00
use_mistletoe(struct unit *user, const struct item_type *itype, int amount,
struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
int mtoes =
get_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
user->number);
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
if (user->number > mtoes) {
2010-08-08 10:06:34 +02:00
ADDMSG(&user->faction->msgs, msg_message("use_singleperson",
2011-03-07 08:02:35 +01:00
"unit item region command", user, itype->rtype, user->region, ord));
2010-08-08 10:06:34 +02:00
return -1;
}
2011-03-07 08:02:35 +01:00
use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
user->number);
2010-08-08 10:06:34 +02:00
a_add(&user->attribs, make_fleechance((float)1.0));
ADDMSG(&user->faction->msgs,
2011-03-07 08:02:35 +01:00
msg_message("use_item", "unit item", user, itype->rtype));
2010-08-08 10:06:34 +02:00
return 0;
}
static int
2011-03-07 08:02:35 +01:00
use_magicboost(struct unit *user, const struct item_type *itype, int amount,
struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
int mtoes =
get_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
user->number);
faction *f = user->faction;
if (user->number > mtoes) {
2010-08-08 10:06:34 +02:00
ADDMSG(&user->faction->msgs, msg_message("use_singleperson",
2011-03-07 08:02:35 +01:00
"unit item region command", user, itype->rtype, user->region, ord));
2010-08-08 10:06:34 +02:00
return -1;
}
2011-03-07 08:02:35 +01:00
if (!is_mage(user) || find_key(f->attribs, atoi36("mbst")) != NULL) {
2010-08-08 10:06:34 +02:00
cmistake(user, user->thisorder, 214, MSG_EVENT);
return -1;
}
2011-03-07 08:02:35 +01:00
use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
user->number);
2010-08-08 10:06:34 +02:00
a_add(&f->attribs, make_key(atoi36("mbst")));
set_level(user, sk_find("magic"), 3);
ADDMSG(&user->faction->msgs, msg_message("use_item",
2011-03-07 08:02:35 +01:00
"unit item", user, itype->rtype));
2010-08-08 10:06:34 +02:00
return 0;
}
static int
2011-03-07 08:02:35 +01:00
use_snowball(struct unit *user, const struct item_type *itype, int amount,
struct order *ord)
2010-08-08 10:06:34 +02:00
{
return 0;
}
2011-03-07 08:02:35 +01:00
static void init_oldpotions(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *potionnames[MAX_POTIONS] = {
2010-08-08 10:06:34 +02:00
"p0", "goliathwater", "p2", "p3", "ointment", "peasantblood", "p6",
2011-03-07 08:02:35 +01:00
"p7", "nestwarmth", "p9", "p10", "p11", "truthpotion", "p13", "p14"
2010-08-08 10:06:34 +02:00
};
int p;
2011-03-07 08:02:35 +01:00
for (p = 0; p != MAXPOTIONS; ++p) {
item_type *itype = it_find(potionnames[p]);
if (itype != NULL) {
2010-08-08 10:06:34 +02:00
oldpotiontype[p] = itype->rtype->ptype;
}
}
}
2011-03-07 08:02:35 +01:00
resource_type *r_silver;
resource_type *r_aura;
resource_type *r_permaura;
resource_type *r_unit;
static resource_type *r_hp;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
item_type *i_silver;
static const char *names[] = {
2010-08-08 10:06:34 +02:00
"money", "money_p",
"person", "person_p",
"permaura", "permaura_p",
"hp", "hp_p",
"peasant", "peasant_p",
"aura", "aura_p",
"unit", "unit_p"
};
2011-03-07 08:02:35 +01:00
void init_resources(void)
2010-08-08 10:06:34 +02:00
{
resource_type *rtype;
if (r_hp) {
2011-03-07 08:02:35 +01:00
return;
}
2010-08-08 10:06:34 +02:00
rtype = new_resourcetype(names + 8, NULL, RTF_NONE);
rtype->uchange = res_changepeasants;
rt_register(rtype);
2010-08-08 10:06:34 +02:00
/* silver was never an item: */
2011-03-07 08:02:35 +01:00
r_silver = new_resourcetype(&names[0], NULL, RTF_ITEM | RTF_POOLED);
i_silver = new_itemtype(r_silver, ITF_NONE, 1 /*weight */ , 0);
2010-08-08 10:06:34 +02:00
r_silver->uchange = res_changeitem;
i_silver->give = give_money;
2012-05-20 01:55:03 +02:00
oldresourcetype[R_SILVER] = r_silver;
2010-08-08 10:06:34 +02:00
r_permaura = new_resourcetype(&names[4], NULL, RTF_NONE);
r_permaura->uchange = res_changepermaura;
2012-05-20 01:55:03 +02:00
rt_register(r_permaura);
oldresourcetype[R_PERMAURA] = r_permaura;
2010-08-08 10:06:34 +02:00
r_hp = new_resourcetype(&names[6], NULL, RTF_NONE);
r_hp->uchange = res_changehp;
2012-05-20 01:55:03 +02:00
rt_register(r_hp);
2010-08-08 10:06:34 +02:00
r_aura = new_resourcetype(&names[10], NULL, RTF_NONE);
r_aura->uchange = res_changeaura;
2012-05-20 01:55:03 +02:00
rt_register(r_aura);
oldresourcetype[R_AURA] = r_aura;
2010-08-08 10:06:34 +02:00
r_unit = new_resourcetype(&names[12], NULL, RTF_NONE);
r_unit->uchange = res_changeperson;
2012-05-20 01:55:03 +02:00
rt_register(r_unit);
2010-08-08 10:06:34 +02:00
/* alte typen registrieren: */
init_olditems();
init_oldpotions();
}
2011-03-07 08:02:35 +01:00
int get_money(const unit * u)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const item *i = u->items;
while (i && i->type != i_silver)
i = i->next;
if (i == NULL)
return 0;
2010-08-08 10:06:34 +02:00
return i->number;
}
2011-03-07 08:02:35 +01:00
int set_money(unit * u, int v)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
item **ip = &u->items;
while (*ip && (*ip)->type != i_silver)
ip = &(*ip)->next;
if ((*ip) == NULL && v) {
2010-08-08 10:06:34 +02:00
i_add(&u->items, i_new(i_silver, v));
return v;
}
2011-03-07 08:02:35 +01:00
if ((*ip) != NULL) {
2010-08-08 10:06:34 +02:00
if (v) {
(*ip)->number = v;
2011-03-07 08:02:35 +01:00
assert((*ip)->number >= 0);
} else
i_remove(ip, *ip);
2010-08-08 10:06:34 +02:00
}
return v;
}
2011-03-07 08:02:35 +01:00
int change_money(unit * u, int v)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
item **ip = &u->items;
while (*ip && (*ip)->type != i_silver)
ip = &(*ip)->next;
if ((*ip) == NULL && v) {
2010-08-08 10:06:34 +02:00
i_add(&u->items, i_new(i_silver, v));
return v;
}
2011-03-07 08:02:35 +01:00
if ((*ip) != NULL) {
item *i = *ip;
2010-08-08 10:06:34 +02:00
if (i->number + v != 0) {
i->number += v;
2011-03-07 08:02:35 +01:00
assert(i->number >= 0);
2010-08-08 10:06:34 +02:00
return i->number;
2011-03-07 08:02:35 +01:00
} else
i_free(i_remove(ip, *ip));
2010-08-08 10:06:34 +02:00
}
return 0;
}
static int add_resourcename_cb(const void * match, const void * key, size_t keylen, void *data)
2010-08-08 10:06:34 +02:00
{
struct locale * lang = (struct locale *)data;
int i = locale_index(lang);
critbit_tree * cb = rnames+i;
resource_type *rtype;
2010-08-08 10:06:34 +02:00
cb_get_kv(match, &rtype, sizeof(rtype));
for (i = 0; i!=2;++i) {
char buffer[128];
const char * name = locale_string(lang, rtype->_name[i]);
if (name && transliterate(buffer, sizeof(buffer), name)) {
size_t len = strlen(buffer);
assert(len+sizeof(rtype)<sizeof(buffer));
cb_new_kv(buffer, &rtype, sizeof(rtype), buffer);
cb_insert(cb, buffer, len+1+sizeof(rtype));
}
2010-08-08 10:06:34 +02:00
}
return 0;
}
2010-08-08 10:06:34 +02:00
const resource_type *findresourcetype(const char *name, const struct locale *lang)
{
int i = locale_index(lang);
critbit_tree * cb = rnames+i;
char buffer[128];
if (transliterate(buffer, sizeof(buffer), name)) {
const void * match;
if (!cb->root) {
/* first-time initialization of resource names for this locale */
cb_foreach(&cb_resources, "", 0, add_resourcename_cb, (void *)lang);
}
if (cb_find_prefix(cb, buffer, strlen(buffer), &match, 1, 0)) {
const resource_type * rtype = 0;
cb_get_kv(match, (void*)&rtype, sizeof(rtype));
return rtype;
}
} else {
log_debug("findresourcetype: transliterate failed for '%s'\n", name);
}
return 0;
2010-08-08 10:06:34 +02:00
}
attrib_type at_showitem = {
"showitem"
};
static int add_itemname_cb(const void * match, const void * key, size_t keylen, void *data)
2010-08-08 10:06:34 +02:00
{
struct locale * lang = (struct locale *)data;
int i = locale_index(lang);
critbit_tree * cb = inames+i;
item_type *itype;
2010-08-08 10:06:34 +02:00
cb_get_kv(match, &itype, sizeof(itype));
for (i = 0; i!=2;++i) {
char buffer[128];
const char * name = locale_string(lang, itype->rtype->_name[i]);
if (name && transliterate(buffer, sizeof(buffer), name)) {
size_t len = strlen(buffer);
assert(len+sizeof(itype)<sizeof(buffer));
len = cb_new_kv(buffer, len, &itype, sizeof(itype), buffer);
cb_insert(cb, buffer, len);
}
2010-08-08 10:06:34 +02:00
}
return 0;
}
const item_type *finditemtype(const char *name, const struct locale *lang)
{
int i = locale_index(lang);
critbit_tree * cb = inames+i;
char buffer[128];
if (transliterate(buffer, sizeof(buffer), name)) {
const void * match;
if (!cb->root) {
/* first-time initialization of item names for this locale */
cb_foreach(&cb_items, "", 0, add_itemname_cb, (void *)lang);
}
if (cb_find_prefix(cb, buffer, strlen(buffer), &match, 1, 0)) {
const item_type * itype = 0;
cb_get_kv(match, (void*)&itype, sizeof(itype));
return itype;
}
} else {
log_debug("finditemtype: transliterate failed for '%s'\n", name);
}
return 0;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static void init_resourcelimit(attrib * a)
2010-08-08 10:06:34 +02:00
{
a->data.v = calloc(sizeof(resource_limit), 1);
}
2011-03-07 08:02:35 +01:00
static void finalize_resourcelimit(attrib * a)
2010-08-08 10:06:34 +02:00
{
free(a->data.v);
}
attrib_type at_resourcelimit = {
"resourcelimit",
init_resourcelimit,
finalize_resourcelimit,
};
2011-03-07 08:02:35 +01:00
static item *default_spoil(const struct race *rc, int size)
{
2011-03-07 08:02:35 +01:00
item *itm = NULL;
2011-03-07 08:02:35 +01:00
if (rng_int() % 100 < RACESPOILCHANCE) {
char spoilname[32];
2011-03-07 08:02:35 +01:00
const item_type *itype;
sprintf(spoilname, "%sspoil", rc->_name[0]);
itype = it_find(spoilname);
2011-03-07 08:02:35 +01:00
if (itype != NULL) {
i_add(&itm, i_new(itype, size));
}
}
return itm;
}
#ifndef DISABLE_TESTS
int free_itype_cb(const void * match, const void * key, size_t keylen, void *cbdata) {
item_type *itype;
cb_get_kv(match, &itype, sizeof(itype));
free(itype->construction);
free(itype);
return 0;
}
int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbdata) {
resource_type *rtype;
cb_get_kv(match, &rtype, sizeof(rtype));
free(rtype->_name[0]);
free(rtype->_name[1]);
free(rtype->_appearance[0]);
free(rtype->_appearance[1]);
free(rtype);
return 0;
}
void test_clear_resources(void)
{
int i;
memset((void *)olditemtype, 0, sizeof(olditemtype));
memset((void *)oldresourcetype, 0, sizeof(oldresourcetype));
memset((void *)oldpotiontype, 0, sizeof(oldpotiontype));
cb_foreach(&cb_items, "", 0, free_itype_cb, 0);
cb_clear(&cb_items);
cb_foreach(&cb_resources, "", 0, free_rtype_cb, 0);
cb_clear(&cb_resources);
r_hp = r_silver = r_aura = r_permaura = r_unit = 0;
i_silver = 0;
for (i=0; i!=MAXLOCALES; ++i) {
cb_clear(inames+i);
}
}
#endif
2011-03-07 08:02:35 +01:00
void register_resources(void)
{
register_function((pf_generic) mod_elves_only, "mod_elves_only");
register_function((pf_generic) mod_dwarves_only, "mod_dwarves_only");
register_function((pf_generic) res_changeitem, "changeitem");
register_function((pf_generic) res_changeperson, "changeperson");
register_function((pf_generic) res_changepeasants, "changepeasants");
register_function((pf_generic) res_changepermaura, "changepermaura");
register_function((pf_generic) res_changehp, "changehp");
register_function((pf_generic) res_changeaura, "changeaura");
register_function((pf_generic) default_spoil, "defaultdrops");
2010-08-08 10:06:34 +02:00
register_item_use(use_potion, "usepotion");
register_item_use(use_potion_delayed, "usepotion_delayed");
register_item_use(use_tacticcrystal, "use_tacticcrystal");
register_item_use(use_birthdayamulet, "use_birthdayamulet");
register_item_use(use_warmthpotion, "usewarmthpotion");
register_item_use(use_bloodpotion, "usebloodpotion");
register_item_use(use_healingpotion, "usehealingpotion");
register_item_useonother(use_foolpotion, "usefoolpotion");
register_item_use(use_mistletoe, "usemistletoe");
register_item_use(use_magicboost, "usemagicboost");
register_item_use(use_snowball, "usesnowball");
register_item_give(give_horses, "givehorses");
/* make sure noone has deleted an I_ tpe without deleting the R_ type that goes with it! */
assert((int)I_TACTICCRYSTAL == (int)R_TACTICCRYSTAL);
}