server/src/kernel/building.c

672 lines
15 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 "building.h"
/* kernel includes */
#include "item.h"
2011-03-07 08:02:35 +01:00
#include "curse.h" /* f<>r C_NOCOST */
2010-08-08 10:06:34 +02:00
#include "unit.h"
#include "faction.h"
#include "region.h"
#include "skill.h"
#include "magic.h"
#include "save.h"
#include "version.h"
/* util includes */
#include <util/attrib.h>
#include <util/base36.h>
#include <util/event.h>
#include <util/functions.h>
#include <util/language.h>
#include <util/log.h>
#include <util/resolve.h>
#include <util/storage.h>
#include <util/umlaut.h>
/* libc includes */
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
/* attributes includes */
#include <attributes/matmod.h>
2011-03-07 08:02:35 +01:00
static const char *NULLSTRING = "(null)";
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
static void lc_init(struct attrib *a)
2010-08-08 10:06:34 +02:00
{
a->data.v = calloc(1, sizeof(building_action));
}
2011-03-07 08:02:35 +01:00
static void lc_done(struct attrib *a)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
building_action *data = (building_action *) a->data.v;
if (data->fname)
free(data->fname);
if (data->param)
free(data->param);
2010-08-08 10:06:34 +02:00
free(data);
}
2011-03-07 08:02:35 +01:00
static void
lc_write(const struct attrib *a, const void *owner, struct storage *store)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
building_action *data = (building_action *) a->data.v;
const char *fname = data->fname;
const char *fparam = data->param;
building *b = data->b;
2010-08-08 10:06:34 +02:00
write_building_reference(b, store);
store->w_tok(store, fname);
2011-03-07 08:02:35 +01:00
store->w_tok(store, fparam ? fparam : NULLSTRING);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static int lc_read(struct attrib *a, void *owner, struct storage *store)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
building_action *data = (building_action *) a->data.v;
int result =
read_reference(&data->b, store, read_building_reference, resolve_building);
if (store->version < UNICODE_VERSION) {
2010-08-08 10:06:34 +02:00
data->fname = store->r_str(store);
} else {
data->fname = store->r_tok(store);
}
2011-03-07 08:02:35 +01:00
if (store->version >= BACTION_VERSION) {
2010-08-08 10:06:34 +02:00
char lbuf[256];
2011-03-07 08:02:35 +01:00
if (store->version < UNICODE_VERSION) {
2010-08-08 10:06:34 +02:00
store->r_str_buf(store, lbuf, sizeof(lbuf));
} else {
store->r_tok_buf(store, lbuf, sizeof(lbuf));
}
2011-03-07 08:02:35 +01:00
if (strcmp(lbuf, NULLSTRING) == 0)
data->param = NULL;
else
data->param = strdup(lbuf);
2010-08-08 10:06:34 +02:00
} else {
data->param = strdup(NULLSTRING);
}
2011-03-07 08:02:35 +01:00
if (result == 0 && !data->b) {
2010-08-08 10:06:34 +02:00
return AT_READ_FAIL;
}
return AT_READ_OK;
}
attrib_type at_building_action = {
2011-03-07 08:02:35 +01:00
"lcbuilding",
lc_init, lc_done,
NULL,
2010-08-08 10:06:34 +02:00
lc_write, lc_read
};
typedef struct building_typelist {
2011-03-07 08:02:35 +01:00
struct building_typelist *next;
building_type *type;
2010-08-08 10:06:34 +02:00
} building_typelist;
static building_typelist *buildingtypes;
2011-03-07 08:02:35 +01:00
building_type *bt_find(const char *name)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const struct building_typelist *btl = buildingtypes;
2010-08-08 10:06:34 +02:00
assert(name);
2011-03-07 08:02:35 +01:00
while (btl && strcmp(btl->type->_name, name))
btl = btl->next;
if (btl == NULL) {
2010-08-08 10:06:34 +02:00
return NULL;
}
return btl->type;
}
2011-03-07 08:02:35 +01:00
void bt_register(building_type * type)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
struct building_typelist *btl = malloc(sizeof(building_type));
if (type->init)
type->init(type);
btl->type = type;
btl->next = buildingtypes;
buildingtypes = btl;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int buildingcapacity(const building * b)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
if (b->type->capacity >= 0) {
if (b->type->maxcapacity >= 0) {
2010-08-08 10:06:34 +02:00
return MIN(b->type->maxcapacity, b->size * b->type->capacity);
}
return b->size * b->type->capacity;
}
2011-03-07 08:02:35 +01:00
if (b->size >= b->type->maxsize) {
if (b->type->maxcapacity >= 0) {
2010-08-08 10:06:34 +02:00
return b->type->maxcapacity;
}
}
return 0;
}
attrib_type at_building_generic_type = {
2011-03-07 08:02:35 +01:00
"building_generic_type", NULL, NULL, NULL, a_writestring, a_readstring,
ATF_UNIQUE
2010-08-08 10:06:34 +02:00
};
2011-03-07 08:02:35 +01:00
const char *buildingtype(const building_type * btype, const building * b,
int bsize)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *s = NULL;
2010-08-08 10:06:34 +02:00
static boolean init_generic = false;
2011-03-07 08:02:35 +01:00
static const struct building_type *bt_generic;
2010-08-08 10:06:34 +02:00
if (!init_generic) {
init_generic = true;
bt_generic = bt_find("generic");
}
if (btype == bt_generic) {
const attrib *a = a_find(b->attribs, &at_building_generic_type);
2011-03-07 08:02:35 +01:00
if (a)
s = (const char *)a->data.v;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (btype->name)
s = btype->name(btype, b, bsize);
if (s == NULL)
s = btype->_name;
2010-08-08 10:06:34 +02:00
return s;
}
#define BMAXHASH 7919
static building *buildhash[BMAXHASH];
2011-03-07 08:02:35 +01:00
void bhash(building * b)
2010-08-08 10:06:34 +02:00
{
building *old = buildhash[b->no % BMAXHASH];
buildhash[b->no % BMAXHASH] = b;
b->nexthash = old;
}
2011-03-07 08:02:35 +01:00
void bunhash(building * b)
2010-08-08 10:06:34 +02:00
{
building **show;
for (show = &buildhash[b->no % BMAXHASH]; *show; show = &(*show)->nexthash) {
if ((*show)->no == b->no)
break;
}
if (*show) {
assert(*show == b);
*show = (*show)->nexthash;
b->nexthash = 0;
}
}
2011-03-07 08:02:35 +01:00
static building *bfindhash(int i)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
building *old;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
for (old = buildhash[i % BMAXHASH]; old; old = old->nexthash)
if (old->no == i)
return old;
return 0;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
building *findbuilding(int i)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
return bfindhash(i);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
2010-08-08 10:06:34 +02:00
/* ** old building types ** */
2011-03-07 08:02:35 +01:00
static int sm_smithy(const unit * u, const region * r, skill_t sk, int value)
{ /* skillmod */
if (sk == SK_WEAPONSMITH || sk == SK_ARMORER) {
if (u->region == r)
return value + 1;
}
return value;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static int mm_smithy(const unit * u, const resource_type * rtype, int value)
{ /* material-mod */
if (rtype == oldresourcetype[R_IRON])
return value * 2;
return value;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static void init_smithy(struct building_type *bt)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
a_add(&bt->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, sm_smithy, 1.0,
0));
a_add(&bt->attribs, make_matmod(mm_smithy));
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static const char *castle_name_i(const struct building_type *btype,
const struct building *b, int bsize, const char *fname[])
2010-08-08 10:06:34 +02:00
{
int i = bt_effsize(btype, b, bsize);
return fname[i];
}
2011-03-07 08:02:35 +01:00
static const char *castle_name_2(const struct building_type *btype,
const struct building *b, int bsize)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *fname[] = {
2010-08-08 10:06:34 +02:00
"site",
"fortification",
"tower",
"castle",
"fortress",
"citadel"
};
return castle_name_i(btype, b, bsize, fname);
}
2011-03-07 08:02:35 +01:00
static const char *castle_name(const struct building_type *btype,
const struct building *b, int bsize)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *fname[] = {
2010-08-08 10:06:34 +02:00
"site",
"tradepost",
"fortification",
"tower",
"castle",
"fortress",
"citadel"
};
return castle_name_i(btype, b, bsize, fname);
}
2011-03-07 08:02:35 +01:00
static const char *fort_name(const struct building_type *btype,
const struct building *b, int bsize)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *fname[] = {
2010-08-08 10:06:34 +02:00
"scaffolding",
"guardhouse",
"guardtower",
};
return castle_name_i(btype, b, bsize, fname);
}
#ifdef WDW_PYRAMID
2011-03-07 08:02:35 +01:00
static const char *pyramid_name(const struct building_type *btype, int bsize)
2010-08-08 10:06:34 +02:00
{
static char p_name_buf[32];
2011-03-07 08:02:35 +01:00
int level = 0;
const construction *ctype;
2010-08-08 10:06:34 +02:00
ctype = btype->construction;
2011-03-07 08:02:35 +01:00
while (ctype && ctype->maxsize != -1 && ctype->maxsize <= bsize) {
bsize -= ctype->maxsize;
ctype = ctype->improvement;
2010-08-08 10:06:34 +02:00
++level;
}
sprintf(p_name_buf, "pyramid%d", level);
return p_name_buf;
}
2011-03-07 08:02:35 +01:00
int wdw_pyramid_level(const struct building *b)
2010-08-08 10:06:34 +02:00
{
const construction *ctype = b->type->construction;
int completed = b->size;
int level = 0;
2011-03-07 08:02:35 +01:00
while (ctype->improvement != NULL &&
ctype->improvement != ctype &&
ctype->maxsize > 0 && ctype->maxsize <= completed) {
2010-08-08 10:06:34 +02:00
++level;
2011-03-07 08:02:35 +01:00
completed -= ctype->maxsize;
2010-08-08 10:06:34 +02:00
ctype = ctype->improvement;
}
return level;
}
#endif
/* for finding out what was meant by a particular building string */
2011-03-07 08:02:35 +01:00
static local_names *bnames;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
const building_type *findbuildingtype(const char *name,
const struct locale *lang)
2010-08-08 10:06:34 +02:00
{
variant type;
2011-03-07 08:02:35 +01:00
local_names *bn = bnames;
while (bn) {
if (bn->lang == lang)
break;
bn = bn->next;
}
if (!bn) {
struct building_typelist *btl = buildingtypes;
bn = calloc(sizeof(local_names), 1);
bn->next = bnames;
bn->lang = lang;
while (btl) {
const char *n = locale_string(lang, btl->type->_name);
type.v = (void *)btl->type;
addtoken(&bn->names, n, type);
btl = btl->next;
}
bnames = bn;
}
if (findtoken(&bn->names, name, &type) == E_TOK_NOMATCH)
return NULL;
return (const building_type *)type.v;
2010-08-08 10:06:34 +02:00
}
static int eressea_building_protection(building * b, unit * u)
{
2011-03-07 08:02:35 +01:00
int beff = buildingeffsize(b, false) - 1;
2010-08-08 10:06:34 +02:00
/* -1 because the tradepost has no protection value */
return beff;
}
2011-03-07 08:02:35 +01:00
void register_buildings(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
register_function((pf_generic) & eressea_building_protection,
"eressea_building_protection");
register_function((pf_generic) & init_smithy, "init_smithy");
register_function((pf_generic) & castle_name, "castle_name");
register_function((pf_generic) & castle_name_2, "castle_name_2");
register_function((pf_generic) & fort_name, "fort_name");
2010-08-08 10:06:34 +02:00
#ifdef WDW_PYRAMID
2011-03-07 08:02:35 +01:00
register_function((pf_generic) & pyramid_name, "pyramid_name");
2010-08-08 10:06:34 +02:00
#endif
}
2011-03-07 08:02:35 +01:00
void write_building_reference(const struct building *b, struct storage *store)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
store->w_id(store, (b && b->region) ? b->no : 0);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int resolve_building(variant id, void *address)
2010-08-08 10:06:34 +02:00
{
int result = 0;
2011-03-07 08:02:35 +01:00
building *b = NULL;
if (id.i != 0) {
2010-08-08 10:06:34 +02:00
b = findbuilding(id.i);
2011-03-07 08:02:35 +01:00
if (b == NULL) {
2010-08-08 10:06:34 +02:00
result = -1;
}
}
2011-03-07 08:02:35 +01:00
*(building **) address = b;
2010-08-08 10:06:34 +02:00
return result;
}
2011-03-07 08:02:35 +01:00
variant read_building_reference(struct storage * store)
2010-08-08 10:06:34 +02:00
{
variant result;
result.i = store->r_id(store);
return result;
}
2011-03-07 08:02:35 +01:00
building *new_building(const struct building_type * btype, region * r,
const struct locale * lang)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
building **bptr = &r->buildings;
2010-08-08 10:06:34 +02:00
building *b = (building *) calloc(1, sizeof(building));
static boolean init_lighthouse = false;
2011-03-07 08:02:35 +01:00
static const struct building_type *bt_lighthouse = 0;
2010-08-08 10:06:34 +02:00
if (!init_lighthouse) {
bt_lighthouse = bt_find("lighthouse");
init_lighthouse = true;
}
2011-03-07 08:02:35 +01:00
b->flags = BLD_WORKING | BLD_MAINTAINED;
b->no = newcontainerid();
2010-08-08 10:06:34 +02:00
bhash(b);
2011-03-07 08:02:35 +01:00
2010-08-08 10:06:34 +02:00
b->type = btype;
b->region = r;
2011-03-07 08:02:35 +01:00
while (*bptr)
bptr = &(*bptr)->next;
*bptr = b;
2011-03-07 08:02:35 +01:00
if (b->type == bt_lighthouse) {
2010-08-08 10:06:34 +02:00
r->flags |= RF_LIGHTHOUSE;
}
{
2011-03-07 08:02:35 +01:00
const char *bname;
if (b->type->name == NULL) {
2010-08-08 10:06:34 +02:00
bname = LOC(lang, btype->_name);
} else {
bname = LOC(lang, buildingtype(btype, b, 0));
}
b->name = strdup(bname);
}
return b;
}
2011-03-07 08:02:35 +01:00
static building *deleted_buildings;
2010-08-08 10:06:34 +02:00
/** remove a building from the region.
* remove_building lets units leave the building
*/
2011-03-07 08:02:35 +01:00
void remove_building(building ** blist, building * b)
2010-08-08 10:06:34 +02:00
{
unit *u;
direction_t d;
2011-03-07 08:02:35 +01:00
static const struct building_type *bt_caravan, *bt_dam, *bt_tunnel;
2010-08-08 10:06:34 +02:00
static boolean init = false;
if (!init) {
init = true;
bt_caravan = bt_find("caravan");
bt_dam = bt_find("dam");
bt_tunnel = bt_find("tunnel");
}
assert(bfindhash(b->no));
handle_event(b->attribs, "destroy", b);
2011-03-07 08:02:35 +01:00
for (u = b->region->units; u; u = u->next) {
if (u->building == b)
leave(u, true);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
2010-08-08 10:06:34 +02:00
b->size = 0;
update_lighthouse(b);
bunhash(b);
2011-03-07 08:02:35 +01:00
2010-08-08 10:06:34 +02:00
/* Falls Karawanserei, Damm oder Tunnel einst<73>rzen, wird die schon
* gebaute Stra<EFBFBD>e zur H<EFBFBD>lfte vernichtet */
if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) {
2011-03-07 08:02:35 +01:00
region *r = b->region;
for (d = 0; d != MAXDIRECTIONS; ++d)
if (rroad(r, d) > 0) {
rsetroad(r, d, rroad(r, d) / 2);
}
2010-08-08 10:06:34 +02:00
}
/* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */
2011-03-07 08:02:35 +01:00
while (*blist && *blist != b)
blist = &(*blist)->next;
2010-08-08 10:06:34 +02:00
*blist = b->next;
b->region = NULL;
b->next = deleted_buildings;
deleted_buildings = b;
}
2011-03-07 08:02:35 +01:00
void free_building(building * b)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
while (b->attribs)
a_remove(&b->attribs, b->attribs);
2010-08-08 10:06:34 +02:00
free(b->name);
free(b->display);
free(b);
}
2011-03-07 08:02:35 +01:00
void free_buildings(void)
2010-08-08 10:06:34 +02:00
{
while (deleted_buildings) {
2011-03-07 08:02:35 +01:00
building *b = deleted_buildings;
2010-08-08 10:06:34 +02:00
deleted_buildings = b->next;
}
}
extern struct attrib_type at_icastle;
/** returns the building's build stage (NOT size in people).
* only makes sense for castles or similar buildings with multiple
* stages */
2011-03-07 08:02:35 +01:00
int buildingeffsize(const building * b, boolean img)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const struct building_type *btype = NULL;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
if (b == NULL)
return 0;
2010-08-08 10:06:34 +02:00
btype = b->type;
if (img) {
2011-03-07 08:02:35 +01:00
const attrib *a = a_find(b->attribs, &at_icastle);
2010-08-08 10:06:34 +02:00
if (a) {
btype = (const struct building_type *)a->data.v;
}
}
return bt_effsize(btype, b, b->size);
}
int bt_effsize(const building_type * btype, const building * b, int bsize)
{
int i = bsize, n = 0;
2011-03-07 08:02:35 +01:00
const construction *cons = btype->construction;
2010-08-08 10:06:34 +02:00
/* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */
2011-03-07 08:02:35 +01:00
if (b && get_param_int(global.parameters, "rules.dwarf_castles", 1)
&& strcmp(btype->_name, "castle") == 0) {
unit *u = building_owner(b);
2010-08-08 10:06:34 +02:00
if (u && u->faction->race == new_race[RC_HALFLING]) {
i = bsize * 10 / 8;
}
}
if (!cons || !cons->improvement) {
return 0;
}
2011-03-07 08:02:35 +01:00
while (cons && cons->maxsize != -1 && i >= cons->maxsize) {
2010-08-08 10:06:34 +02:00
i -= cons->maxsize;
cons = cons->improvement;
++n;
}
return n;
}
2011-03-07 08:02:35 +01:00
const char *write_buildingname(const building * b, char *ibuf, size_t size)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
snprintf((char *)ibuf, size, "%s (%s)", b->name, itoa36(b->no));
ibuf[size - 1] = 0;
2010-08-08 10:06:34 +02:00
return ibuf;
}
2011-03-07 08:02:35 +01:00
const char *buildingname(const building * b)
2010-08-08 10:06:34 +02:00
{
typedef char name[OBJECTIDSIZE + 1];
static name idbuf[8];
static int nextbuf = 0;
char *ibuf = idbuf[(++nextbuf) % 8];
return write_buildingname(b, ibuf, sizeof(name));
}
2011-03-07 08:02:35 +01:00
unit *building_owner(const building * b)
2010-08-08 10:06:34 +02:00
{
unit *u = NULL;
unit *first = NULL;
2011-03-07 08:02:35 +01:00
region *r = b->region;
2010-08-08 10:06:34 +02:00
/* Pr<50>fen ob Eigent<6E>mer am leben. */
for (u = r->units; u; u = u->next) {
if (u->building == b) {
if (!first && u->number > 0)
first = u;
if (fval(u, UFL_OWNER) && u->number > 0)
return u;
if (u->number == 0)
freset(u, UFL_OWNER);
}
}
/* Eigent<6E>mer tot oder kein Eigent<6E>mer vorhanden. Erste lebende Einheit
2011-03-07 08:02:35 +01:00
* nehmen. */
2010-08-08 10:06:34 +02:00
if (first) {
fset(first, UFL_OWNER);
}
return first;
}
2011-03-07 08:02:35 +01:00
const char *building_getname(const building * self)
2010-08-08 10:06:34 +02:00
{
return self->name;
}
2011-03-07 08:02:35 +01:00
void building_setname(building * self, const char *name)
2010-08-08 10:06:34 +02:00
{
free(self->name);
2011-03-07 08:02:35 +01:00
if (name)
self->name = strdup(name);
else
self->name = NULL;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void building_addaction(building * b, const char *fname, const char *param)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
attrib *a = a_add(&b->attribs, a_new(&at_building_action));
building_action *data = (building_action *) a->data.v;
2010-08-08 10:06:34 +02:00
data->b = b;
data->fname = strdup(fname);
if (param) {
data->param = strdup(param);
}
}
2011-03-07 08:02:35 +01:00
region *building_getregion(const building * b)
2010-08-08 10:06:34 +02:00
{
return b->region;
}
2011-03-07 08:02:35 +01:00
void building_setregion(building * b, region * r)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
building **blist = &b->region->buildings;
while (*blist && *blist != b) {
2010-08-08 10:06:34 +02:00
blist = &(*blist)->next;
}
*blist = b->next;
b->next = NULL;
blist = &r->buildings;
2011-03-07 08:02:35 +01:00
while (*blist && *blist != b)
blist = &(*blist)->next;
2010-08-08 10:06:34 +02:00
*blist = b;
b->region = r;
}