forked from github/server
Merge pull request #84 from badgerman/master
added tests: region owners can set PAY NOT <id> for empty buildings if ...
This commit is contained in:
commit
e51811df3b
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
Copyright (c) 1998-2010, Enno Rehling <enno@eressea.de>
|
Copyright (c) 1998-2010, Enno Rehling <enno@eressea.de>
|
||||||
Katja Zedel <katze@felidae.kn-bremen.de
|
Katja Zedel <katze@felidae.kn-bremen.de
|
||||||
Christian Schlittchen <corwin@amber.kn-bremen.de>
|
Christian Schlittchen <corwin@amber.kn-bremen.de>
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -57,8 +57,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include <attributes/matmod.h>
|
#include <attributes/matmod.h>
|
||||||
|
|
||||||
typedef struct building_typelist {
|
typedef struct building_typelist {
|
||||||
struct building_typelist *next;
|
struct building_typelist *next;
|
||||||
building_type *type;
|
building_type *type;
|
||||||
} building_typelist;
|
} building_typelist;
|
||||||
|
|
||||||
quicklist *buildingtypes = NULL;
|
quicklist *buildingtypes = NULL;
|
||||||
|
@ -66,17 +66,17 @@ quicklist *buildingtypes = NULL;
|
||||||
/* Returns a building type for the (internal) name */
|
/* Returns a building type for the (internal) name */
|
||||||
static building_type *bt_find_i(const char *name)
|
static building_type *bt_find_i(const char *name)
|
||||||
{
|
{
|
||||||
quicklist *ql;
|
quicklist *ql;
|
||||||
int qi;
|
int qi;
|
||||||
|
|
||||||
assert(name);
|
assert(name);
|
||||||
|
|
||||||
for (qi = 0, ql = buildingtypes; ql; ql_advance(&ql, &qi, 1)) {
|
for (qi = 0, ql = buildingtypes; ql; ql_advance(&ql, &qi, 1)) {
|
||||||
building_type *btype = (building_type *) ql_get(ql, qi);
|
building_type *btype = (building_type *)ql_get(ql, qi);
|
||||||
if (strcmp(btype->_name, name) == 0)
|
if (strcmp(btype->_name, name) == 0)
|
||||||
return btype;
|
return btype;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const building_type *bt_find(const char *name)
|
const building_type *bt_find(const char *name)
|
||||||
|
@ -86,10 +86,10 @@ const building_type *bt_find(const char *name)
|
||||||
|
|
||||||
void bt_register(building_type * type)
|
void bt_register(building_type * type)
|
||||||
{
|
{
|
||||||
if (type->init) {
|
if (type->init) {
|
||||||
type->init(type);
|
type->init(type);
|
||||||
}
|
}
|
||||||
ql_push(&buildingtypes, (void *)type);
|
ql_push(&buildingtypes, (void *)type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_buildingtypes(void) {
|
void free_buildingtypes(void) {
|
||||||
|
@ -100,36 +100,36 @@ void free_buildingtypes(void) {
|
||||||
|
|
||||||
building_type *bt_get_or_create(const char *name)
|
building_type *bt_get_or_create(const char *name)
|
||||||
{
|
{
|
||||||
if (name != NULL) {
|
if (name != NULL) {
|
||||||
building_type *btype = bt_find_i(name);
|
building_type *btype = bt_find_i(name);
|
||||||
if (btype == NULL) {
|
if (btype == NULL) {
|
||||||
btype = calloc(sizeof(building_type), 1);
|
btype = calloc(sizeof(building_type), 1);
|
||||||
btype->_name = _strdup(name);
|
btype->_name = _strdup(name);
|
||||||
bt_register(btype);
|
bt_register(btype);
|
||||||
|
}
|
||||||
|
return btype;
|
||||||
}
|
}
|
||||||
return btype;
|
return NULL;
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int buildingcapacity(const building * b)
|
int buildingcapacity(const building * b)
|
||||||
{
|
{
|
||||||
if (b->type->capacity >= 0) {
|
if (b->type->capacity >= 0) {
|
||||||
if (b->type->maxcapacity >= 0) {
|
if (b->type->maxcapacity >= 0) {
|
||||||
return _min(b->type->maxcapacity, b->size * b->type->capacity);
|
return _min(b->type->maxcapacity, b->size * b->type->capacity);
|
||||||
|
}
|
||||||
|
return b->size * b->type->capacity;
|
||||||
}
|
}
|
||||||
return b->size * b->type->capacity;
|
if (b->size >= b->type->maxsize) {
|
||||||
}
|
if (b->type->maxcapacity >= 0) {
|
||||||
if (b->size >= b->type->maxsize) {
|
return b->type->maxcapacity;
|
||||||
if (b->type->maxcapacity >= 0) {
|
}
|
||||||
return b->type->maxcapacity;
|
|
||||||
}
|
}
|
||||||
}
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attrib_type at_building_generic_type = {
|
attrib_type at_building_generic_type = {
|
||||||
"building_generic_type", NULL, NULL, NULL, a_writestring, a_readstring,
|
"building_generic_type", NULL, NULL, NULL, a_writestring, a_readstring,
|
||||||
ATF_UNIQUE
|
ATF_UNIQUE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -162,113 +162,113 @@ const char *buildingtype(const building_type * btype, const building * b, int bs
|
||||||
static building *buildhash[BMAXHASH];
|
static building *buildhash[BMAXHASH];
|
||||||
void bhash(building * b)
|
void bhash(building * b)
|
||||||
{
|
{
|
||||||
building *old = buildhash[b->no % BMAXHASH];
|
building *old = buildhash[b->no % BMAXHASH];
|
||||||
|
|
||||||
buildhash[b->no % BMAXHASH] = b;
|
buildhash[b->no % BMAXHASH] = b;
|
||||||
b->nexthash = old;
|
b->nexthash = old;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bunhash(building * b)
|
void bunhash(building * b)
|
||||||
{
|
{
|
||||||
building **show;
|
building **show;
|
||||||
|
|
||||||
for (show = &buildhash[b->no % BMAXHASH]; *show; show = &(*show)->nexthash) {
|
for (show = &buildhash[b->no % BMAXHASH]; *show; show = &(*show)->nexthash) {
|
||||||
if ((*show)->no == b->no)
|
if ((*show)->no == b->no)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (*show) {
|
if (*show) {
|
||||||
assert(*show == b);
|
assert(*show == b);
|
||||||
*show = (*show)->nexthash;
|
*show = (*show)->nexthash;
|
||||||
b->nexthash = 0;
|
b->nexthash = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static building *bfindhash(int i)
|
static building *bfindhash(int i)
|
||||||
{
|
{
|
||||||
building *old;
|
building *old;
|
||||||
|
|
||||||
for (old = buildhash[i % BMAXHASH]; old; old = old->nexthash)
|
for (old = buildhash[i % BMAXHASH]; old; old = old->nexthash)
|
||||||
if (old->no == i)
|
if (old->no == i)
|
||||||
return old;
|
return old;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
building *findbuilding(int i)
|
building *findbuilding(int i)
|
||||||
{
|
{
|
||||||
return bfindhash(i);
|
return bfindhash(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ** old building types ** */
|
/* ** old building types ** */
|
||||||
|
|
||||||
static int sm_smithy(const unit * u, const region * r, skill_t sk, int value)
|
static int sm_smithy(const unit * u, const region * r, skill_t sk, int value)
|
||||||
{ /* skillmod */
|
{ /* skillmod */
|
||||||
if (sk == SK_WEAPONSMITH || sk == SK_ARMORER) {
|
if (sk == SK_WEAPONSMITH || sk == SK_ARMORER) {
|
||||||
if (u->region == r)
|
if (u->region == r)
|
||||||
return value + 1;
|
return value + 1;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mm_smithy(const unit * u, const resource_type * rtype, int value)
|
static int mm_smithy(const unit * u, const resource_type * rtype, int value)
|
||||||
{ /* material-mod */
|
{ /* material-mod */
|
||||||
if (rtype == get_resourcetype(R_IRON))
|
if (rtype == get_resourcetype(R_IRON))
|
||||||
return value * 2;
|
return value * 2;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_smithy(struct building_type *bt)
|
static void init_smithy(struct building_type *bt)
|
||||||
{
|
{
|
||||||
a_add(&bt->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, sm_smithy, 1.0,
|
a_add(&bt->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, sm_smithy, 1.0,
|
||||||
0));
|
0));
|
||||||
a_add(&bt->attribs, make_matmod(mm_smithy));
|
a_add(&bt->attribs, make_matmod(mm_smithy));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *castle_name_i(const struct building_type *btype,
|
static const char *castle_name_i(const struct building_type *btype,
|
||||||
const struct building *b, int bsize, const char *fname[])
|
const struct building *b, int bsize, const char *fname[])
|
||||||
{
|
{
|
||||||
int i = bt_effsize(btype, b, bsize);
|
int i = bt_effsize(btype, b, bsize);
|
||||||
|
|
||||||
return fname[i];
|
return fname[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *castle_name_2(const struct building_type *btype,
|
static const char *castle_name_2(const struct building_type *btype,
|
||||||
const struct building *b, int bsize)
|
const struct building *b, int bsize)
|
||||||
{
|
{
|
||||||
const char *fname[] = {
|
const char *fname[] = {
|
||||||
"site",
|
"site",
|
||||||
"fortification",
|
"fortification",
|
||||||
"tower",
|
"tower",
|
||||||
"castle",
|
"castle",
|
||||||
"fortress",
|
"fortress",
|
||||||
"citadel"
|
"citadel"
|
||||||
};
|
};
|
||||||
return castle_name_i(btype, b, bsize, fname);
|
return castle_name_i(btype, b, bsize, fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *castle_name(const struct building_type *btype,
|
static const char *castle_name(const struct building_type *btype,
|
||||||
const struct building *b, int bsize)
|
const struct building *b, int bsize)
|
||||||
{
|
{
|
||||||
const char *fname[] = {
|
const char *fname[] = {
|
||||||
"site",
|
"site",
|
||||||
"tradepost",
|
"tradepost",
|
||||||
"fortification",
|
"fortification",
|
||||||
"tower",
|
"tower",
|
||||||
"castle",
|
"castle",
|
||||||
"fortress",
|
"fortress",
|
||||||
"citadel"
|
"citadel"
|
||||||
};
|
};
|
||||||
return castle_name_i(btype, b, bsize, fname);
|
return castle_name_i(btype, b, bsize, fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *fort_name(const struct building_type *btype,
|
static const char *fort_name(const struct building_type *btype,
|
||||||
const struct building *b, int bsize)
|
const struct building *b, int bsize)
|
||||||
{
|
{
|
||||||
const char *fname[] = {
|
const char *fname[] = {
|
||||||
"scaffolding",
|
"scaffolding",
|
||||||
"guardhouse",
|
"guardhouse",
|
||||||
"guardtower",
|
"guardtower",
|
||||||
};
|
};
|
||||||
return castle_name_i(btype, b, bsize, fname);
|
return castle_name_i(btype, b, bsize, fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for finding out what was meant by a particular building string */
|
/* for finding out what was meant by a particular building string */
|
||||||
|
@ -278,132 +278,132 @@ static local_names *bnames;
|
||||||
/* Find the building type for a given localized name (as seen by the user). Useful for parsing
|
/* Find the building type for a given localized name (as seen by the user). Useful for parsing
|
||||||
* orders. The inverse of locale_string(lang, btype->_name), sort of. */
|
* orders. The inverse of locale_string(lang, btype->_name), sort of. */
|
||||||
const building_type *findbuildingtype(const char *name,
|
const building_type *findbuildingtype(const char *name,
|
||||||
const struct locale *lang)
|
const struct locale *lang)
|
||||||
{
|
{
|
||||||
variant type;
|
variant type;
|
||||||
local_names *bn = bnames;
|
local_names *bn = bnames;
|
||||||
|
|
||||||
while (bn) {
|
while (bn) {
|
||||||
if (bn->lang == lang)
|
if (bn->lang == lang)
|
||||||
break;
|
break;
|
||||||
bn = bn->next;
|
bn = bn->next;
|
||||||
}
|
|
||||||
if (!bn) {
|
|
||||||
quicklist *ql = buildingtypes;
|
|
||||||
int qi;
|
|
||||||
|
|
||||||
bn = (local_names *)calloc(sizeof(local_names), 1);
|
|
||||||
bn->next = bnames;
|
|
||||||
bn->lang = lang;
|
|
||||||
|
|
||||||
for (qi = 0, ql = buildingtypes; ql; ql_advance(&ql, &qi, 1)) {
|
|
||||||
building_type *btype = (building_type *) ql_get(ql, qi);
|
|
||||||
|
|
||||||
const char *n = locale_string(lang, btype->_name);
|
|
||||||
type.v = (void *)btype;
|
|
||||||
addtoken(&bn->names, n, type);
|
|
||||||
}
|
}
|
||||||
bnames = bn;
|
if (!bn) {
|
||||||
}
|
quicklist *ql = buildingtypes;
|
||||||
if (findtoken(bn->names, name, &type) == E_TOK_NOMATCH)
|
int qi;
|
||||||
return NULL;
|
|
||||||
return (const building_type *)type.v;
|
bn = (local_names *)calloc(sizeof(local_names), 1);
|
||||||
|
bn->next = bnames;
|
||||||
|
bn->lang = lang;
|
||||||
|
|
||||||
|
for (qi = 0, ql = buildingtypes; ql; ql_advance(&ql, &qi, 1)) {
|
||||||
|
building_type *btype = (building_type *)ql_get(ql, qi);
|
||||||
|
|
||||||
|
const char *n = locale_string(lang, btype->_name);
|
||||||
|
type.v = (void *)btype;
|
||||||
|
addtoken(&bn->names, n, type);
|
||||||
|
}
|
||||||
|
bnames = bn;
|
||||||
|
}
|
||||||
|
if (findtoken(bn->names, name, &type) == E_TOK_NOMATCH)
|
||||||
|
return NULL;
|
||||||
|
return (const building_type *)type.v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int eressea_building_protection(building * b, unit * u)
|
static int eressea_building_protection(building * b, unit * u)
|
||||||
{
|
{
|
||||||
int beff = buildingeffsize(b, false) - 1;
|
int beff = buildingeffsize(b, false) - 1;
|
||||||
/* -1 because the tradepost has no protection value */
|
/* -1 because the tradepost has no protection value */
|
||||||
|
|
||||||
return beff;
|
return beff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int meropis_building_protection(building * b, unit * u)
|
static int meropis_building_protection(building * b, unit * u)
|
||||||
{
|
{
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void register_buildings(void)
|
void register_buildings(void)
|
||||||
{
|
{
|
||||||
register_function((pf_generic) & eressea_building_protection,
|
register_function((pf_generic)& eressea_building_protection,
|
||||||
"eressea_building_protection");
|
"eressea_building_protection");
|
||||||
register_function((pf_generic) & meropis_building_protection,
|
register_function((pf_generic)& meropis_building_protection,
|
||||||
"meropis_building_protection");
|
"meropis_building_protection");
|
||||||
register_function((pf_generic) & init_smithy, "init_smithy");
|
register_function((pf_generic)& init_smithy, "init_smithy");
|
||||||
register_function((pf_generic) & castle_name, "castle_name");
|
register_function((pf_generic)& castle_name, "castle_name");
|
||||||
register_function((pf_generic) & castle_name_2, "castle_name_2");
|
register_function((pf_generic)& castle_name_2, "castle_name_2");
|
||||||
register_function((pf_generic) & fort_name, "fort_name");
|
register_function((pf_generic)& fort_name, "fort_name");
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_building_reference(const struct building *b, struct storage *store)
|
void write_building_reference(const struct building *b, struct storage *store)
|
||||||
{
|
{
|
||||||
WRITE_INT(store, (b && b->region) ? b->no : 0);
|
WRITE_INT(store, (b && b->region) ? b->no : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int resolve_building(variant id, void *address)
|
int resolve_building(variant id, void *address)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
building *b = NULL;
|
building *b = NULL;
|
||||||
if (id.i != 0) {
|
if (id.i != 0) {
|
||||||
b = findbuilding(id.i);
|
b = findbuilding(id.i);
|
||||||
if (b == NULL) {
|
if (b == NULL) {
|
||||||
result = -1;
|
result = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
*(building **)address = b;
|
||||||
*(building **) address = b;
|
return result;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variant read_building_reference(struct storage * store)
|
variant read_building_reference(struct storage * store)
|
||||||
{
|
{
|
||||||
variant result;
|
variant result;
|
||||||
READ_INT(store, &result.i);
|
READ_INT(store, &result.i);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
building *new_building(const struct building_type * btype, region * r,
|
building *new_building(const struct building_type * btype, region * r,
|
||||||
const struct locale * lang)
|
const struct locale * lang)
|
||||||
{
|
{
|
||||||
building **bptr = &r->buildings;
|
building **bptr = &r->buildings;
|
||||||
building *b = (building *) calloc(1, sizeof(building));
|
building *b = (building *)calloc(1, sizeof(building));
|
||||||
static bool init_lighthouse = false;
|
static bool init_lighthouse = false;
|
||||||
static const struct building_type *bt_lighthouse = 0;
|
static const struct building_type *bt_lighthouse = 0;
|
||||||
const char *bname = 0;
|
const char *bname = 0;
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
|
|
||||||
if (!init_lighthouse) {
|
if (!init_lighthouse) {
|
||||||
bt_lighthouse = bt_find("lighthouse");
|
bt_lighthouse = bt_find("lighthouse");
|
||||||
init_lighthouse = true;
|
init_lighthouse = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
b->no = newcontainerid();
|
b->no = newcontainerid();
|
||||||
bhash(b);
|
bhash(b);
|
||||||
|
|
||||||
b->type = btype;
|
b->type = btype;
|
||||||
b->region = r;
|
b->region = r;
|
||||||
while (*bptr)
|
while (*bptr)
|
||||||
bptr = &(*bptr)->next;
|
bptr = &(*bptr)->next;
|
||||||
*bptr = b;
|
*bptr = b;
|
||||||
|
|
||||||
if (b->type == bt_lighthouse) {
|
if (b->type == bt_lighthouse) {
|
||||||
r->flags |= RF_LIGHTHOUSE;
|
r->flags |= RF_LIGHTHOUSE;
|
||||||
}
|
}
|
||||||
if (b->type->name) {
|
if (b->type->name) {
|
||||||
bname = LOC(lang, buildingtype(btype, b, 0));
|
bname = LOC(lang, buildingtype(btype, b, 0));
|
||||||
}
|
}
|
||||||
if (!bname) {
|
if (!bname) {
|
||||||
bname = LOC(lang, btype->_name);
|
bname = LOC(lang, btype->_name);
|
||||||
}
|
}
|
||||||
if (!bname) {
|
if (!bname) {
|
||||||
bname = LOC(lang, parameters[P_GEBAEUDE]);
|
bname = LOC(lang, parameters[P_GEBAEUDE]);
|
||||||
}
|
}
|
||||||
if (!bname) {
|
if (!bname) {
|
||||||
bname = parameters[P_GEBAEUDE];
|
bname = parameters[P_GEBAEUDE];
|
||||||
}
|
}
|
||||||
assert(bname);
|
assert(bname);
|
||||||
slprintf(buffer, sizeof(buffer), "%s %s", bname, buildingid(b));
|
slprintf(buffer, sizeof(buffer), "%s %s", bname, buildingid(b));
|
||||||
b->name = _strdup(bname);
|
b->name = _strdup(bname);
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static building *deleted_buildings;
|
static building *deleted_buildings;
|
||||||
|
@ -431,8 +431,8 @@ void remove_building(building ** blist, building * b)
|
||||||
update_lighthouse(b);
|
update_lighthouse(b);
|
||||||
bunhash(b);
|
bunhash(b);
|
||||||
|
|
||||||
/* Falls Karawanserei, Damm oder Tunnel einstürzen, wird die schon
|
/* Falls Karawanserei, Damm oder Tunnel einstürzen, wird die schon
|
||||||
* gebaute Straße zur Hälfte vernichtet */
|
* gebaute Straße zur Hälfte vernichtet */
|
||||||
if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) {
|
if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) {
|
||||||
region *r = b->region;
|
region *r = b->region;
|
||||||
int d;
|
int d;
|
||||||
|
@ -456,19 +456,19 @@ void remove_building(building ** blist, building * b)
|
||||||
|
|
||||||
void free_building(building * b)
|
void free_building(building * b)
|
||||||
{
|
{
|
||||||
while (b->attribs)
|
while (b->attribs)
|
||||||
a_remove(&b->attribs, b->attribs);
|
a_remove(&b->attribs, b->attribs);
|
||||||
free(b->name);
|
free(b->name);
|
||||||
free(b->display);
|
free(b->display);
|
||||||
free(b);
|
free(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_buildings(void)
|
void free_buildings(void)
|
||||||
{
|
{
|
||||||
while (deleted_buildings) {
|
while (deleted_buildings) {
|
||||||
building *b = deleted_buildings;
|
building *b = deleted_buildings;
|
||||||
deleted_buildings = b->next;
|
deleted_buildings = b->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern struct attrib_type at_icastle;
|
extern struct attrib_type at_icastle;
|
||||||
|
@ -478,87 +478,87 @@ extern struct attrib_type at_icastle;
|
||||||
* stages */
|
* stages */
|
||||||
int buildingeffsize(const building * b, int img)
|
int buildingeffsize(const building * b, int img)
|
||||||
{
|
{
|
||||||
const struct building_type *btype = NULL;
|
const struct building_type *btype = NULL;
|
||||||
|
|
||||||
if (b == NULL)
|
if (b == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
btype = b->type;
|
btype = b->type;
|
||||||
if (img) {
|
if (img) {
|
||||||
const attrib *a = a_find(b->attribs, &at_icastle);
|
const attrib *a = a_find(b->attribs, &at_icastle);
|
||||||
if (a) {
|
if (a) {
|
||||||
btype = (const struct building_type *)a->data.v;
|
btype = (const struct building_type *)a->data.v;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return bt_effsize(btype, b, b->size);
|
||||||
return bt_effsize(btype, b, b->size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bt_effsize(const building_type * btype, const building * b, int bsize)
|
int bt_effsize(const building_type * btype, const building * b, int bsize)
|
||||||
{
|
{
|
||||||
int i = bsize, n = 0;
|
int i = bsize, n = 0;
|
||||||
const construction *cons = btype->construction;
|
const construction *cons = btype->construction;
|
||||||
|
|
||||||
/* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */
|
/* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */
|
||||||
if (b && get_param_int(global.parameters, "rules.dwarf_castles", 0)
|
if (b && get_param_int(global.parameters, "rules.dwarf_castles", 0)
|
||||||
&& strcmp(btype->_name, "castle") == 0) {
|
&& strcmp(btype->_name, "castle") == 0) {
|
||||||
unit *u = building_owner(b);
|
unit *u = building_owner(b);
|
||||||
if (u && u->faction->race == get_race(RC_HALFLING)) {
|
if (u && u->faction->race == get_race(RC_HALFLING)) {
|
||||||
i = bsize * 10 / 8;
|
i = bsize * 10 / 8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!cons || !cons->improvement) {
|
if (!cons || !cons->improvement) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (cons && cons->maxsize != -1 && i >= cons->maxsize) {
|
while (cons && cons->maxsize != -1 && i >= cons->maxsize) {
|
||||||
i -= cons->maxsize;
|
i -= cons->maxsize;
|
||||||
cons = cons->improvement;
|
cons = cons->improvement;
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *write_buildingname(const building * b, char *ibuf, size_t size)
|
const char *write_buildingname(const building * b, char *ibuf, size_t size)
|
||||||
{
|
{
|
||||||
slprintf(ibuf, size, "%s (%s)", b->name, itoa36(b->no));
|
slprintf(ibuf, size, "%s (%s)", b->name, itoa36(b->no));
|
||||||
return ibuf;
|
return ibuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *buildingname(const building * b)
|
const char *buildingname(const building * b)
|
||||||
{
|
{
|
||||||
typedef char name[OBJECTIDSIZE + 1];
|
typedef char name[OBJECTIDSIZE + 1];
|
||||||
static name idbuf[8];
|
static name idbuf[8];
|
||||||
static int nextbuf = 0;
|
static int nextbuf = 0;
|
||||||
char *ibuf = idbuf[(++nextbuf) % 8];
|
char *ibuf = idbuf[(++nextbuf) % 8];
|
||||||
return write_buildingname(b, ibuf, sizeof(name));
|
return write_buildingname(b, ibuf, sizeof(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
void building_set_owner(struct unit * owner)
|
void building_set_owner(struct unit * owner)
|
||||||
{
|
{
|
||||||
assert(owner && owner->building);
|
assert(owner && owner->building);
|
||||||
owner->building->_owner = owner;
|
owner->building->_owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unit *building_owner_ex(const building * bld, const struct faction * last_owner)
|
static unit *building_owner_ex(const building * bld, const struct faction * last_owner)
|
||||||
{
|
{
|
||||||
unit *u, *heir = 0;
|
unit *u, *heir = 0;
|
||||||
/* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit
|
/* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit
|
||||||
* nehmen. */
|
* nehmen. */
|
||||||
for (u = bld->region->units; u; u = u->next) {
|
for (u = bld->region->units; u; u = u->next) {
|
||||||
if (u->building == bld) {
|
if (u->building == bld) {
|
||||||
if (u->number > 0) {
|
if (u->number > 0) {
|
||||||
if (heir && last_owner && heir->faction!=last_owner && u->faction==last_owner) {
|
if (heir && last_owner && heir->faction != last_owner && u->faction == last_owner) {
|
||||||
heir = u;
|
heir = u;
|
||||||
break; /* we found someone from the same faction who is not dead. let's take this guy */
|
break; /* we found someone from the same faction who is not dead. let's take this guy */
|
||||||
|
}
|
||||||
|
else if (!heir) {
|
||||||
|
heir = u; /* you'll do in an emergency */
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!heir) {
|
|
||||||
heir = u; /* you'll do in an emergency */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!heir && check_param(global.parameters, "rules.region_owner_pay_building", bld->type->_name)) {
|
if (!heir && check_param(global.parameters, "rules.region_owner_pay_building", bld->type->_name)) {
|
||||||
if (rule_region_owners()) {
|
if (rule_region_owners()) {
|
||||||
u = building_owner(largestbuilding(bld->region, &cmp_taxes, false));
|
u = building_owner(largestbuilding(bld->region, &cmp_taxes, false));
|
||||||
|
@ -575,54 +575,54 @@ static unit *building_owner_ex(const building * bld, const struct faction * last
|
||||||
|
|
||||||
unit *building_owner(const building * bld)
|
unit *building_owner(const building * bld)
|
||||||
{
|
{
|
||||||
if (!bld) {
|
if (!bld) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
unit *owner = bld->_owner;
|
unit *owner = bld->_owner;
|
||||||
if (!owner || (owner->building!=bld || owner->number<=0)) {
|
if (!owner || (owner->building != bld || owner->number <= 0)) {
|
||||||
unit * heir = building_owner_ex(bld, owner?owner->faction:0);
|
unit * heir = building_owner_ex(bld, owner ? owner->faction : 0);
|
||||||
return (heir && heir->number>0) ? heir : 0;
|
return (heir && heir->number > 0) ? heir : 0;
|
||||||
}
|
}
|
||||||
return owner;
|
return owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
void building_update_owner(building * bld) {
|
void building_update_owner(building * bld) {
|
||||||
unit * owner = bld->_owner;
|
unit * owner = bld->_owner;
|
||||||
bld->_owner = building_owner_ex(bld, owner?owner->faction:0);
|
bld->_owner = building_owner_ex(bld, owner ? owner->faction : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *building_getname(const building * self)
|
const char *building_getname(const building * self)
|
||||||
{
|
{
|
||||||
return self->name;
|
return self->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void building_setname(building * self, const char *name)
|
void building_setname(building * self, const char *name)
|
||||||
{
|
{
|
||||||
free(self->name);
|
free(self->name);
|
||||||
if (name)
|
if (name)
|
||||||
self->name = _strdup(name);
|
self->name = _strdup(name);
|
||||||
else
|
else
|
||||||
self->name = NULL;
|
self->name = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
region *building_getregion(const building * b)
|
region *building_getregion(const building * b)
|
||||||
{
|
{
|
||||||
return b->region;
|
return b->region;
|
||||||
}
|
}
|
||||||
|
|
||||||
void building_setregion(building * b, region * r)
|
void building_setregion(building * b, region * r)
|
||||||
{
|
{
|
||||||
building **blist = &b->region->buildings;
|
building **blist = &b->region->buildings;
|
||||||
while (*blist && *blist != b) {
|
while (*blist && *blist != b) {
|
||||||
blist = &(*blist)->next;
|
blist = &(*blist)->next;
|
||||||
}
|
}
|
||||||
*blist = b->next;
|
*blist = b->next;
|
||||||
b->next = NULL;
|
b->next = NULL;
|
||||||
|
|
||||||
blist = &r->buildings;
|
blist = &r->buildings;
|
||||||
while (*blist && *blist != b)
|
while (*blist && *blist != b)
|
||||||
blist = &(*blist)->next;
|
blist = &(*blist)->next;
|
||||||
*blist = b;
|
*blist = b;
|
||||||
|
|
||||||
b->region = r;
|
b->region = r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,14 @@
|
||||||
#include <kernel/terrain.h>
|
#include <kernel/terrain.h>
|
||||||
#include <kernel/unit.h>
|
#include <kernel/unit.h>
|
||||||
|
|
||||||
|
#include <util/base36.h>
|
||||||
#include <util/language.h>
|
#include <util/language.h>
|
||||||
|
|
||||||
#include <CuTest.h>
|
#include <CuTest.h>
|
||||||
#include <tests.h>
|
#include <tests.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
static void test_new_building_can_be_renamed(CuTest * tc)
|
static void test_new_building_can_be_renamed(CuTest * tc)
|
||||||
{
|
{
|
||||||
|
@ -356,16 +358,23 @@ struct pay_fixture {
|
||||||
unit *u2;
|
unit *u2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static double level_taxes(const building * b, int level) {
|
||||||
|
return b->size*level*2.0;
|
||||||
|
}
|
||||||
|
|
||||||
static void setup_pay_cmd(struct pay_fixture *fix) {
|
static void setup_pay_cmd(struct pay_fixture *fix) {
|
||||||
faction *f;
|
faction *f;
|
||||||
region *r;
|
region *r;
|
||||||
building *b;
|
building *b;
|
||||||
|
building_type *btcastle;
|
||||||
|
|
||||||
test_create_world();
|
test_create_world();
|
||||||
f = test_create_faction(NULL);
|
f = test_create_faction(NULL);
|
||||||
r = findregion(0, 0);
|
r = findregion(0, 0);
|
||||||
assert(r && f);
|
assert(r && f);
|
||||||
b = test_create_building(r, bt_get_or_create("lighthouse"));
|
btcastle = bt_get_or_create("castle");
|
||||||
|
btcastle->taxes = level_taxes;
|
||||||
|
b = test_create_building(r, btcastle);
|
||||||
assert(b);
|
assert(b);
|
||||||
fix->u1 = test_create_unit(f, r);
|
fix->u1 = test_create_unit(f, r);
|
||||||
fix->u2 = test_create_unit(f, r);
|
fix->u2 = test_create_unit(f, r);
|
||||||
|
@ -394,6 +403,30 @@ static void test_pay_cmd(CuTest *tc) {
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_pay_cmd_other_building(CuTest *tc) {
|
||||||
|
struct pay_fixture fix;
|
||||||
|
order *ord;
|
||||||
|
faction *f;
|
||||||
|
building *b;
|
||||||
|
char cmd[32];
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
setup_pay_cmd(&fix);
|
||||||
|
f = fix.u1->faction;
|
||||||
|
b = test_create_building(fix.u1->region, bt_get_or_create("lighthouse"));
|
||||||
|
set_param(&global.parameters, "rules.region_owners", "1");
|
||||||
|
set_param(&global.parameters, "rules.region_owner_pay_building", "lighthouse");
|
||||||
|
update_owners(b->region);
|
||||||
|
|
||||||
|
_snprintf(cmd, sizeof(cmd), "NOT %s", itoa36(b->no));
|
||||||
|
ord = create_order(K_PAY, f->locale, cmd);
|
||||||
|
assert(ord);
|
||||||
|
CuAssertPtrEquals(tc, fix.u1, building_owner(b));
|
||||||
|
CuAssertIntEquals(tc, 0, pay_cmd(fix.u1, ord));
|
||||||
|
CuAssertIntEquals(tc, BLD_DONTPAY, b->flags&BLD_DONTPAY);
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
static void test_pay_cmd_must_be_owner(CuTest *tc) {
|
static void test_pay_cmd_must_be_owner(CuTest *tc) {
|
||||||
struct pay_fixture fix;
|
struct pay_fixture fix;
|
||||||
order *ord;
|
order *ord;
|
||||||
|
@ -412,7 +445,6 @@ static void test_pay_cmd_must_be_owner(CuTest *tc) {
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void test_new_units(CuTest *tc) {
|
static void test_new_units(CuTest *tc) {
|
||||||
unit *u;
|
unit *u;
|
||||||
faction *f;
|
faction *f;
|
||||||
|
@ -581,6 +613,7 @@ CuSuite *get_laws_suite(void)
|
||||||
SUITE_ADD_TEST(suite, test_reserve_self);
|
SUITE_ADD_TEST(suite, test_reserve_self);
|
||||||
SUITE_ADD_TEST(suite, test_reserve_cmd);
|
SUITE_ADD_TEST(suite, test_reserve_cmd);
|
||||||
SUITE_ADD_TEST(suite, test_pay_cmd);
|
SUITE_ADD_TEST(suite, test_pay_cmd);
|
||||||
|
SUITE_ADD_TEST(suite, test_pay_cmd_other_building);
|
||||||
SUITE_ADD_TEST(suite, test_pay_cmd_must_be_owner);
|
SUITE_ADD_TEST(suite, test_pay_cmd_must_be_owner);
|
||||||
SUITE_ADD_TEST(suite, test_new_units);
|
SUITE_ADD_TEST(suite, test_new_units);
|
||||||
SUITE_ADD_TEST(suite, test_cannot_create_unit_above_limit);
|
SUITE_ADD_TEST(suite, test_cannot_create_unit_above_limit);
|
||||||
|
|
Loading…
Reference in New Issue