added a test: region owners can set PAY NOT <id> for empty buildings if they are in region_owner_pay_building.

This commit is contained in:
Enno Rehling 2014-12-17 21:31:02 +01:00
parent d7899a392a
commit 484e52d491
2 changed files with 314 additions and 281 deletions

View File

@ -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;
@ -443,7 +443,7 @@ void remove_building(building ** blist, building * b)
} }
} }
} }
/* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */ /* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */
while (*blist && *blist != b) { while (*blist && *blist != b) {
blist = &(*blist)->next; blist = &(*blist)->next;
@ -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;
} }

View File

@ -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);