ship and building owners encapsulated in accessors

tests added
This commit is contained in:
Enno Rehling 2012-05-17 15:23:15 -07:00
parent 7789e0534e
commit ff33af3c65
17 changed files with 425 additions and 114 deletions

View file

@ -614,20 +614,20 @@ static int tolua_unit_get_building(lua_State * L)
return 1;
}
static void unit_setbuilding(unit * u, building * b)
{
leave(u, true);
if (b && u->region != b->region) {
move_unit(u, b->region, NULL);
}
u->building = b;
}
static int tolua_unit_set_building(lua_State * L)
{
unit *self = (unit *) tolua_tousertype(L, 1, 0);
if (self->faction) {
unit_setbuilding(self, (building *) tolua_tousertype(L, 2, 0));
unit *u = (unit *) tolua_tousertype(L, 1, 0);
if (u->faction) {
building * b = (building *) tolua_tousertype(L, 2, 0);
if (b!=u->building) {
leave(u, true);
if (b) {
if (u->region != b->region) {
move_unit(u, b->region, NULL);
}
u_set_building(u, b);
}
}
}
return 0;
}

View file

@ -639,10 +639,8 @@ static void give_control(unit * u, unit * u2)
}
}
if (u->ship) {
u->ship->owner = u2;
ship_set_owner(u->ship, u2);
}
freset(u, UFL_OWNER);
fset(u2, UFL_OWNER);
}
int give_control_cmd(unit * u, order * ord)

View file

@ -53,7 +53,7 @@ static void test_rename_building(CuTest * tc)
b = new_building(btype, r, default_locale);
f = test_create_faction(rc_find("human"));
u = test_create_unit(f, r);
u->building = b;
u_set_building(u, b);
fset(u, UFL_OWNER);
rename_building(u, NULL, b, "Villa Nagel");
@ -77,8 +77,7 @@ static void test_rename_building_twice(CuTest * tc)
b = new_building(btype, r, default_locale);
f = test_create_faction(rc_find("human"));
u = test_create_unit(f, r);
u->building = b;
fset(u, UFL_OWNER);
u_set_building(u, b);
rename_building(u, NULL, b, "Villa Nagel");
CuAssertStrEquals(tc, "Villa Nagel", b->name);

View file

@ -61,8 +61,7 @@ static void market_curse(CuTest * tc)
f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0);
u = create_unit(r, f, 1, f->race, 0, 0, 0);
u->building = b;
u->flags |= UFL_OWNER;
u_set_building(u, b);
do_markets();

View file

@ -911,8 +911,9 @@ static void move_iceberg(region * r)
while (rc->units) {
building *b = rc->units->building;
u = rc->units;
u->building = 0; /* prevent leaving in move_unit */
move_unit(rc->units, r, NULL);
u->building = b; /* move_unit macht ein leave() */
u_set_building(u, b); /* undo leave-prevention */
}
/* Beschädigte Schiffe können sinken */

View file

@ -94,6 +94,7 @@
<ClCompile Include="kernel\binarystore.c" />
<ClCompile Include="kernel\build.c" />
<ClCompile Include="kernel\building.c" />
<ClCompile Include="kernel\building_test.c" />
<ClCompile Include="kernel\calendar.c" />
<ClCompile Include="kernel\command.c" />
<ClCompile Include="kernel\config.c" />

View file

@ -304,6 +304,9 @@
<ClCompile Include="kernel\reports_test.c">
<Filter>kernel</Filter>
</ClCompile>
<ClCompile Include="kernel\building_test.c">
<Filter>kernel</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="kernel\alchemy.h">

View file

@ -77,7 +77,7 @@ static void test_defenders_get_building_bonus(CuTest * tc)
du = test_create_unit(test_create_faction(rc_find("human")), r);
au = test_create_unit(test_create_faction(rc_find("human")), r);
du->building = bld;
u_set_building(du, bld);
b = make_battle(r);
ds = make_side(b, du->faction, 0, 0, 0);
@ -119,8 +119,7 @@ static void test_attackers_get_no_building_bonus(CuTest * tc)
bld->size = 10;
au = test_create_unit(test_create_faction(rc_find("human")), r);
au->building = bld;
u_set_building(au, bld);
b = make_battle(r);
as = make_side(b, au->faction, 0, 0, 0);
@ -151,9 +150,9 @@ static void test_building_bonus_respects_size(CuTest * tc)
f = test_create_faction(rc_find("human"));
au = test_create_unit(f, r);
scale_number(au, 9);
au->building = bld;
u_set_building(au, bld);
du = test_create_unit(f, r);
du->building = bld;
u_set_building(du, bld);
scale_number(du, 2);
b = make_battle(r);

View file

@ -360,14 +360,13 @@ int destroy_cmd(unit * u, struct order *ord)
return 0;
}
if (!fval(u, UFL_OWNER)) {
cmistake(u, ord, 138, MSG_PRODUCE);
return 0;
}
if (u->building) {
building *b = u->building;
if (u!=building_owner(b)) {
cmistake(u, ord, 138, MSG_PRODUCE);
return 0;
}
if (fval(b->type, BTF_INDESTRUCTIBLE)) {
cmistake(u, ord, 138, MSG_PRODUCE);
return 0;
@ -377,8 +376,8 @@ int destroy_cmd(unit * u, struct order *ord)
/* all units leave the building */
for (u2 = r->units; u2; u2 = u2->next) {
if (u2->building == b) {
u2->building = 0;
freset(u2, UFL_OWNER);
leave_building(u2);
}
}
ADDMSG(&u->faction->msgs, msg_message("destroy", "building unit", b, u));
@ -393,6 +392,10 @@ int destroy_cmd(unit * u, struct order *ord)
} else if (u->ship) {
sh = u->ship;
if (u!=ship_owner(sh)) {
cmistake(u, ord, 138, MSG_PRODUCE);
return 0;
}
if (fval(r->terrain, SEA_REGION)) {
cmistake(u, ord, 14, MSG_EVENT);
return 0;
@ -970,8 +973,8 @@ build_building(unit * u, const building_type * btype, int want, order * ord)
/* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */
if (leave(u, false)) {
u->building = b;
fset(u, UFL_OWNER);
u_set_building(u, b);
assert(building_owner(b)==u);
}
#ifdef WDW_PYRAMID
if (b->type == bt_find("pyramid") && f_get_alliance(u->faction) != NULL) {
@ -1297,11 +1300,8 @@ static boolean enter_building(unit * u, order * ord, int id, boolean report)
}
if (leave(u, false)) {
if (building_owner(b) == 0) {
fset(u, UFL_OWNER);
}
fset(u, UFL_ENTER);
u->building = b;
u_set_building(u, b);
return true;
}
return false;

View file

@ -145,8 +145,9 @@ building_type *bt_find(const char *name)
void bt_register(building_type * type)
{
if (type->init)
if (type->init) {
type->init(type);
}
ql_push(&buildingtypes, (void *)type);
}
@ -616,43 +617,44 @@ const char *buildingname(const building * b)
void building_set_owner(struct building *b, struct unit * owner)
{
unit * u;
assert(b && owner && owner->building==b);
for (u = b->region->units; u; u = u->next) {
if (u->building == b) {
freset(owner, UFL_OWNER);
}
if (b->_owner && b->_owner!=owner) {
freset(b->_owner, UFL_OWNER);
}
b->_owner = owner;
fset(owner, UFL_OWNER);
}
unit *building_owner(const building * b)
unit *building_owner(const building * bld)
{
unit *u = NULL;
unit *first = NULL;
region *r = b->region;
/* Prüfen ob Eigentümer am leben. */
unit *owner = bld->_owner;
if (owner && (owner->building!=bld || owner->number<=0)) {
unit *u, *heir = 0;
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)
/* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit
* nehmen. */
for (u = bld->region->units; u; u = u->next) {
if (u->building == bld) {
if (u->number > 0) {
if (u->faction==owner->faction) {
heir = u;
break;
}
else if (!heir) {
heir = u; /* you'll do in an emergency */
}
}
freset(u, UFL_OWNER);
}
}
freset(owner, UFL_OWNER);
owner->building = 0;
owner = heir;
if (owner) {
fset(owner, UFL_OWNER);
}
}
/* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit
* nehmen. */
if (first) {
fset(first, UFL_OWNER);
}
return first;
return owner;
}
const char *building_getname(const building * self)

View file

@ -104,6 +104,7 @@ extern "C" {
const struct building_type *type;
struct region *region;
struct unit *_owner; /* you should always use building_owner(), never this naked pointer */
char *name;
char *display;
struct attrib *attribs;

324
src/kernel/building_test.c Normal file
View file

@ -0,0 +1,324 @@
#include <platform.h>
#include <kernel/config.h>
#include <kernel/types.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/building.h>
#include <kernel/unit.h>
#include <cutest/CuTest.h>
#include <tests.h>
#include <stdlib.h>
#include <string.h>
static void test_register_building(CuTest * tc)
{
building_type *btype;
test_cleanup();
btype = (building_type *)calloc(sizeof(building_type), 1);
btype->_name = strdup("herp");
bt_register(btype);
CuAssertPtrNotNull(tc, bt_find("herp"));
}
static void test_building_set_owner(CuTest * tc)
{
struct region *r;
struct building *bld;
struct unit *u1, *u2;
struct faction *f;
const struct building_type *btype;
const struct race *human;
test_cleanup();
test_create_world();
human = rc_find("human");
btype = bt_find("castle");
f = test_create_faction(human);
r = findregion(0, 0);
bld = test_create_building(r, btype);
u1 = test_create_unit(f, r);
u_set_building(u1, bld);
CuAssertPtrEquals(tc, u1, building_owner(bld));
u2 = test_create_unit(f, r);
u_set_building(u2, bld);
CuAssertPtrEquals(tc, u1, building_owner(bld));
building_set_owner(bld, u2);
CuAssertPtrEquals(tc, u2, building_owner(bld));
}
static void test_buildingowner_goes_to_next_after_death(CuTest * tc)
{
struct region *r;
struct building *bld;
struct unit *u, *u2;
struct faction *f;
const struct building_type *btype;
const struct race *human;
test_cleanup();
test_create_world();
human = rc_find("human");
CuAssertPtrNotNull(tc, human);
btype = bt_find("castle");
CuAssertPtrNotNull(tc, btype);
f = test_create_faction(human);
r = findregion(0, 0);
bld = test_create_building(r, btype);
CuAssertPtrNotNull(tc, bld);
u = test_create_unit(f, r);
u2 = test_create_unit(f, r);
CuAssertPtrNotNull(tc, u);
u_set_building(u, bld);
u_set_building(u2, bld);
CuAssertPtrEquals(tc, u, building_owner(bld));
u->number = 0;
CuAssertPtrEquals(tc, u2, building_owner(bld));
}
static void test_buildingowner_goes_to_other_after_death(CuTest * tc)
{
struct region *r;
struct building *bld;
struct unit *u, *u2;
struct faction *f;
const struct building_type *btype;
const struct race *human;
test_cleanup();
test_create_world();
human = rc_find("human");
CuAssertPtrNotNull(tc, human);
btype = bt_find("castle");
CuAssertPtrNotNull(tc, btype);
f = test_create_faction(human);
r = findregion(0, 0);
bld = test_create_building(r, btype);
CuAssertPtrNotNull(tc, bld);
u2 = test_create_unit(f, r);
u = test_create_unit(f, r);
CuAssertPtrNotNull(tc, u);
u_set_building(u, bld);
CuAssertPtrEquals(tc, u, building_owner(bld));
u_set_building(u2, bld);
CuAssertPtrEquals(tc, u, building_owner(bld));
u->number = 0;
CuAssertPtrEquals(tc, u2, building_owner(bld));
}
static void test_buildingowner_goes_to_same_faction_after_death(CuTest * tc)
{
struct region *r;
struct building *bld;
struct unit *u, *u2, *u3;
struct faction *f1, *f2;
const struct building_type *btype;
const struct race *human;
test_cleanup();
test_create_world();
human = rc_find("human");
CuAssertPtrNotNull(tc, human);
btype = bt_find("castle");
CuAssertPtrNotNull(tc, btype);
f1 = test_create_faction(human);
f2 = test_create_faction(human);
r = findregion(0, 0);
bld = test_create_building(r, btype);
CuAssertPtrNotNull(tc, bld);
u2 = test_create_unit(f2, r);
u3 = test_create_unit(f1, r);
u = test_create_unit(f1, r);
CuAssertPtrNotNull(tc, u);
u_set_building(u, bld);
u_set_building(u2, bld);
u_set_building(u3, bld);
CuAssertPtrEquals(tc, u, building_owner(bld));
CuAssertTrue(tc, fval(u, UFL_OWNER));
u->number = 0;
CuAssertPtrEquals(tc, u3, building_owner(bld));
CuAssertTrue(tc, !fval(u, UFL_OWNER));
CuAssertTrue(tc, fval(u3, UFL_OWNER));
u3->number = 0;
CuAssertPtrEquals(tc, u2, building_owner(bld));
CuAssertTrue(tc, !fval(u3, UFL_OWNER));
CuAssertTrue(tc, fval(u2, UFL_OWNER));
}
static void test_buildingowner_goes_to_next_after_leave(CuTest * tc)
{
struct region *r;
struct building *bld;
struct unit *u, *u2;
struct faction *f;
const struct building_type *btype;
const struct race *human;
test_cleanup();
test_create_world();
human = rc_find("human");
CuAssertPtrNotNull(tc, human);
btype = bt_find("castle");
CuAssertPtrNotNull(tc, btype);
f = test_create_faction(human);
r = findregion(0, 0);
bld = test_create_building(r, btype);
CuAssertPtrNotNull(tc, bld);
u = test_create_unit(f, r);
u2 = test_create_unit(f, r);
CuAssertPtrNotNull(tc, u);
u_set_building(u, bld);
u_set_building(u2, bld);
CuAssertPtrEquals(tc, u, building_owner(bld));
leave_building(u);
CuAssertPtrEquals(tc, u2, building_owner(bld));
}
static void test_buildingowner_goes_to_other_after_leave(CuTest * tc)
{
struct region *r;
struct building *bld;
struct unit *u, *u2;
struct faction *f;
const struct building_type *btype;
const struct race *human;
test_cleanup();
test_create_world();
human = rc_find("human");
CuAssertPtrNotNull(tc, human);
btype = bt_find("castle");
CuAssertPtrNotNull(tc, btype);
f = test_create_faction(human);
r = findregion(0, 0);
bld = test_create_building(r, btype);
CuAssertPtrNotNull(tc, bld);
u2 = test_create_unit(f, r);
u = test_create_unit(f, r);
CuAssertPtrNotNull(tc, u);
u_set_building(u, bld);
u_set_building(u2, bld);
CuAssertPtrEquals(tc, u, building_owner(bld));
leave_building(u);
CuAssertPtrEquals(tc, u2, building_owner(bld));
}
static void test_buildingowner_goes_to_same_faction_after_leave(CuTest * tc)
{
struct region *r;
struct building *bld;
struct unit *u, *u2, *u3;
struct faction *f1, *f2;
const struct building_type *btype;
const struct race *human;
test_cleanup();
test_create_world();
human = rc_find("human");
CuAssertPtrNotNull(tc, human);
btype = bt_find("castle");
CuAssertPtrNotNull(tc, btype);
f1 = test_create_faction(human);
f2 = test_create_faction(human);
r = findregion(0, 0);
bld = test_create_building(r, btype);
CuAssertPtrNotNull(tc, bld);
u2 = test_create_unit(f2, r);
u3 = test_create_unit(f1, r);
u = test_create_unit(f1, r);
CuAssertPtrNotNull(tc, u);
u_set_building(u, bld);
u_set_building(u2, bld);
u_set_building(u3, bld);
CuAssertPtrEquals(tc, u, building_owner(bld));
leave_building(u);
CuAssertPtrEquals(tc, u3, building_owner(bld));
leave_building(u3);
CuAssertPtrEquals(tc, u2, building_owner(bld));
leave_building(u2);
CuAssertPtrEquals(tc, 0, building_owner(bld));
}
static void test_buildingowner_resets_when_dead(CuTest * tc)
{
struct region *r;
struct building *bld;
struct unit *u;
struct faction *f;
const struct building_type *btype;
const struct race *human;
test_cleanup();
test_create_world();
human = rc_find("human");
CuAssertPtrNotNull(tc, human);
btype = bt_find("castle");
CuAssertPtrNotNull(tc, btype);
f = test_create_faction(human);
r = findregion(0, 0);
bld = test_create_building(r, btype);
CuAssertPtrNotNull(tc, bld);
u = test_create_unit(f, r);
CuAssertPtrNotNull(tc, u);
u_set_building(u, bld);
CuAssertPtrEquals(tc, u, building_owner(bld));
u->number = 0;
CuAssertPtrEquals(tc, 0, building_owner(bld));
}
CuSuite *get_building_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_register_building);
SUITE_ADD_TEST(suite, test_building_set_owner);
SUITE_ADD_TEST(suite, test_buildingowner_resets_when_dead);
SUITE_ADD_TEST(suite, test_buildingowner_goes_to_next_after_death);
SUITE_ADD_TEST(suite, test_buildingowner_goes_to_other_after_death);
SUITE_ADD_TEST(suite, test_buildingowner_goes_to_same_faction_after_death);
SUITE_ADD_TEST(suite, test_buildingowner_goes_to_next_after_leave);
SUITE_ADD_TEST(suite, test_buildingowner_goes_to_other_after_leave);
SUITE_ADD_TEST(suite, test_buildingowner_goes_to_same_faction_after_leave);
return suite;
}

View file

@ -278,39 +278,39 @@ void getshipweight(const ship * sh, int *sweight, int *scabins)
void ship_set_owner(ship * sh, unit * u) {
assert(u->ship==sh);
if (sh->owner && sh->owner!=u) {
freset(sh->owner, UFL_OWNER);
if (sh->_owner && sh->_owner!=u) {
freset(sh->_owner, UFL_OWNER);
}
sh->owner = u;
sh->_owner = u;
fset(u, UFL_OWNER);
}
unit *ship_owner(ship * sh)
unit *ship_owner(const ship * sh)
{
unit *owner = sh->owner;
if (owner && owner->number<=0) {
unit *u, *first = NULL;
unit *owner = sh->_owner;
if (owner && (owner->ship!=sh || owner->number<=0)) {
unit *u, *heir = 0;
owner->ship = 0;
freset(owner, UFL_OWNER);
/* Prüfen ob Eigentümer am leben. */
for (u = sh->region->units; u; u = u->next) {
if (u->ship == sh) {
if (u->number > 0) {
if (u->faction==owner->faction) {
first = u;
heir = u;
break;
}
else if (!first) {
first = u; /* you'll do in an emergency */
else if (!heir) {
heir = u; /* you'll do in an emergency */
}
}
freset(u, UFL_OWNER);
}
}
owner = first;
freset(owner, UFL_OWNER);
owner = heir;
if (owner) {
fset(owner, UFL_OWNER);
sh->owner = owner;
}
}
/* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit

View file

@ -81,7 +81,7 @@ extern "C" {
typedef struct ship {
struct ship *next;
struct ship *nexthash;
struct unit * owner;
struct unit * _owner; /* never use directly, always use ship_owner() */
int no;
struct region *region;
char *name;
@ -96,7 +96,7 @@ extern "C" {
extern void damage_ship(struct ship * sh, double percent);
extern void ship_set_owner(struct ship * sh, struct unit * u);
extern struct unit *ship_owner(struct ship *sh);
extern struct unit *ship_owner(const struct ship *sh);
extern const char *shipname(const struct ship *self);
extern int shipcapacity(const struct ship *sh);
extern void getshipweight(const struct ship *sh, int *weight, int *cabins);

View file

@ -1,5 +1,6 @@
#include <platform.h>
#include <kernel/config.h>
#include <kernel/types.h>
#include <kernel/race.h>
#include <kernel/region.h>
@ -43,8 +44,10 @@ static void test_ship_set_owner(CuTest * tc)
sh = test_create_ship(r, stype);
u1 = test_create_unit(f, r);
u2 = test_create_unit(f, r);
u_set_ship(u1, sh);
CuAssertPtrEquals(tc, u1, ship_owner(sh));
u2 = test_create_unit(f, r);
u_set_ship(u2, sh);
CuAssertPtrEquals(tc, u1, ship_owner(sh));
ship_set_owner(sh, u2);

View file

@ -778,17 +778,17 @@ void u_set_building(unit * u, building * b)
{
assert(b && !u->building); /* you must leave first */
u->building = b;
if (b && !b->_owner) {
building_set_owner(b, u);
}
}
void u_set_ship(unit * u, ship * sh)
{
assert(!u->ship); /* you must leave_ship */
if (sh) {
u->ship = sh;
if (!sh->owner) {
sh->owner = u;
fset(u, UFL_OWNER);
}
u->ship = sh;
if (sh && !sh->_owner) {
ship_set_owner(sh, u);
}
}
@ -798,37 +798,14 @@ void leave_ship(unit * u)
if (!sh) return;
u->ship = 0;
set_leftship(u, sh);
if (fval(u, UFL_OWNER)) {
unit *u2, *owner = NULL;
freset(u, UFL_OWNER);
for (u2 = u->region->units; u2; u2 = u2->next) {
if (u2->ship == sh) {
if (u2->faction == u->faction) {
owner = u2;
break;
} else if (!owner) {
owner = u2;
}
}
}
sh->owner = owner;
if (owner) {
fset(owner, UFL_OWNER);
}
}
assert(sh->owner!=u);
}
void leave_building(unit * u)
{
struct building *b = u->building;
if (!b)
return;
u->building = NULL;
if (fval(u, UFL_OWNER)) {
u->building = NULL;
if (b && fval(u, UFL_OWNER)) {
unit *u2, *owner = NULL;
freset(u, UFL_OWNER);
@ -1521,7 +1498,9 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace,
/* erbt Gebäude/Schiff */
if (creator->region == r) {
u->building = creator->building;
if (creator->building) {
u_set_building(u, creator->building);
}
if (creator->ship && fval(u->race, RCF_CANSAIL)) {
u_set_ship(u, creator->ship);
}

View file

@ -10,6 +10,7 @@
#include <util/umlaut_test.c>
#include <kernel/move_test.c>
#include <kernel/ship_test.c>
#include <kernel/building_test.c>
#include <kernel/spell_test.c>
#include <kernel/curse_test.c>
#include <kernel/battle_test.c>
@ -47,6 +48,7 @@ int RunAllTests(void)
CuSuiteAddSuite(suite, get_move_suite());
CuSuiteAddSuite(suite, get_reports_suite());
CuSuiteAddSuite(suite, get_ship_suite());
CuSuiteAddSuite(suite, get_building_suite());
CuSuiteAddSuite(suite, get_spell_suite());
CuSuiteAddSuite(suite, get_laws_suite());
CuSuiteAddSuite(suite, get_battle_suite());