implement ship-ownership transfer as a function

test the reorder_units function
This commit is contained in:
Enno Rehling 2012-05-17 12:23:25 -07:00
parent 43f5770694
commit 7789e0534e
26 changed files with 284 additions and 155 deletions

View File

@ -187,7 +187,7 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, objtype_t ty
* bei jedem curse gesondert behandelt. */
if (typ == TYP_SHIP) {
ship *sh = (ship *) obj;
unit *owner = shipowner(sh);
unit *owner = ship_owner(sh);
a = sh->attribs;
r = sh->region;
if (owner != NULL) {
@ -1392,7 +1392,7 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr)
/* ships */
for (sh = r->ships; sh; sh = sh->next) {
int fno = -1;
u = shipowner(sh);
u = ship_owner(sh);
if (u && !fval(u, UFL_ANON_FACTION)) {
const faction *sf = visible_faction(f, u);
fno = sf->no;

View File

@ -1798,7 +1798,7 @@ static int name_cmd(unit * u, struct order *ord)
break;
}
}
uo = shipowner(sh);
uo = ship_owner(sh);
if (uo) {
if (cansee(uo->faction, r, u, 0)) {
ADDMSG(&uo->faction->msgs,
@ -2768,7 +2768,7 @@ static void sinkships(region * r)
0.30F);
damage_ship(sh, dmg);
}
if (shipowner(sh) == NULL) {
if (ship_owner(sh) == NULL) {
float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrew",
0.05F);
damage_ship(sh, dmg);

View File

@ -920,7 +920,7 @@ static void move_iceberg(region * r)
for (sh = r->ships; sh;) {
shn = sh->next;
if (fval(sh, SF_SELECT)) {
u = captain(sh);
u = ship_owner(sh);
if (sh->damage >= sh->size * DAMAGE_SCALE) {
if (u != NULL) {
ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des",
@ -1036,7 +1036,7 @@ static void godcurse(void)
0.10F);
damage_ship(sh, dmg);
if (sh->damage >= sh->size * DAMAGE_SCALE) {
unit *u = shipowner(sh);
unit *u = ship_owner(sh);
if (u)
ADDMSG(&u->faction->msgs,
msg_message("godcurse_destroy_ship", "ship", sh));

View File

@ -590,7 +590,7 @@ nr_curses(FILE * F, const faction * viewer, const void *obj, objtype_t typ,
* bei jedem curse gesondert behandelt. */
if (typ == TYP_SHIP) {
ship *sh = (ship *) obj;
unit *owner = shipowner(sh);
unit *owner = ship_owner(sh);
a = sh->attribs;
r = sh->region;
if (owner) {

View File

@ -493,7 +493,7 @@ int sabotage_cmd(unit * u, struct order *ord)
cmistake(u, u->thisorder, 144, MSG_EVENT);
return 0;
}
u2 = shipowner(sh);
u2 = ship_owner(sh);
skdiff =
eff_skill(u, SK_SPY, r) - crew_skill(r, u2->faction, sh, SK_PERCEPTION);
if (try_destruction(u, u2, sh, skdiff)) {

View File

@ -116,6 +116,7 @@
<ClCompile Include="kernel\race.c" />
<ClCompile Include="kernel\region.c" />
<ClCompile Include="kernel\reports.c" />
<ClCompile Include="kernel\reports_test.c" />
<ClCompile Include="kernel\resources.c" />
<ClCompile Include="kernel\save.c" />
<ClCompile Include="kernel\ship.c" />

View File

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

View File

@ -1169,7 +1169,7 @@ static boolean mayenter(region * r, unit * u, building * b)
static int mayboard(const unit * u, ship * sh)
{
unit *u2 = shipowner(sh);
unit *u2 = ship_owner(sh);
return (!u2 || ucontact(u2, u) || alliedunit(u2, u->faction, HELP_GUARD));
}

View File

@ -614,6 +614,20 @@ const char *buildingname(const building * b)
return write_buildingname(b, ibuf, sizeof(name));
}
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);
}
}
fset(owner, UFL_OWNER);
}
unit *building_owner(const building * b)
{
unit *u = NULL;

View File

@ -151,6 +151,7 @@ extern "C" {
extern struct building *findbuilding(int n);
extern struct unit *building_owner(const struct building *b);
extern void building_set_owner(struct building *b, struct unit * u);
extern struct attrib_type at_building_action;
void building_addaction(struct building *b, const char *fname,

View File

@ -3040,107 +3040,6 @@ void add_income(unit * u, int type, int want, int qty)
"unit region mode wanted amount", u, u->region, type, want, qty));
}
void reorder_units(region * r)
{
unit **unext = &r->units;
if (r->buildings) {
building *b = r->buildings;
while (*unext && b) {
unit **ufirst = unext; /* where the first unit in the building should go */
unit **umove = unext; /* a unit we consider moving */
unit *owner = NULL;
while (*umove) {
unit *u = *umove;
if (u->number && u->building == b) {
unit **uinsert = unext;
if (fval(u, UFL_OWNER)) {
uinsert = ufirst;
owner = u;
}
if (umove != uinsert) {
*umove = u->next;
u->next = *uinsert;
*uinsert = u;
} else {
/* no need to move, skip ahead */
umove = &u->next;
}
if (unext == uinsert) {
/* we have a new well-placed unit. jump over it */
unext = &u->next;
}
} else {
umove = &u->next;
}
}
if (!owner && ufirst != unext) {
owner = *ufirst;
fset(owner, UFL_OWNER);
}
b = b->next;
}
}
if (r->ships) {
ship *sh = r->ships;
/* first, move all units up that are not on ships */
unit **umove = unext; /* a unit we consider moving */
while (*umove) {
unit *u = *umove;
if (u->number && !u->ship) {
if (umove != unext) {
*umove = u->next;
u->next = *unext;
*unext = u;
} else {
/* no need to move, skip ahead */
umove = &u->next;
}
/* we have a new well-placed unit. jump over it */
unext = &u->next;
} else {
umove = &u->next;
}
}
while (*unext && sh) {
unit **ufirst = unext; /* where the first unit in the building should go */
unit **umove = unext; /* a unit we consider moving */
unit *owner = NULL;
while (*umove) {
unit *u = *umove;
if (u->number && u->ship == sh) {
unit **uinsert = unext;
if (fval(u, UFL_OWNER)) {
uinsert = ufirst;
owner = u;
}
if (umove != uinsert) {
*umove = u->next;
u->next = *uinsert;
*uinsert = u;
} else {
/* no need to move, skip ahead */
umove = &u->next;
}
if (unext == uinsert) {
/* we have a new well-placed unit. jump over it */
unext = &u->next;
}
} else {
umove = &u->next;
}
}
if (!owner && ufirst != unext) {
owner = *ufirst;
fset(owner, UFL_OWNER);
}
sh = sh->next;
}
}
}
int produceexp(struct unit *u, skill_t sk, int n)
{
if (global.producexpchance > 0.0F) {

View File

@ -388,8 +388,6 @@ extern "C" {
extern void kernel_init(void);
extern void kernel_done(void);
extern void reorder_units(struct region *r);
extern const char *localenames[];
/** compatibility: **/

View File

@ -2496,7 +2496,7 @@ unit *get_clone_mage(const unit * u)
static boolean is_moving_ship(const region * r, ship * sh)
{
const unit *u = shipowner(sh);
const unit *u = ship_owner(sh);
if (u)
switch (get_keyword(u->thisorder)) {

View File

@ -650,7 +650,7 @@ static int is_ship_allowed(struct ship *sh, const region * r)
continue;
if (is_freezing(u)) {
unit *captain = shipowner(sh);
unit *captain = ship_owner(sh);
if (captain) {
ADDMSG(&captain->faction->msgs, msg_message("detectforbidden",
"unit region", u, r));
@ -2274,7 +2274,7 @@ static void piracy_cmd(unit * u, struct order *ord)
&& check_takeoff(sh, r, rc) == true) {
for (sh2 = rc->ships; sh2; sh2 = sh2->next) {
unit *cap = shipowner(sh2);
unit *cap = ship_owner(sh2);
if (cap) {
faction *f = visible_faction(cap->faction, cap);
if (alliedunit(u, f, HELP_FIGHT))

View File

@ -10,7 +10,7 @@
#include <cutest/CuTest.h>
#include <tests.h>
static void building_type_exists(CuTest * tc)
static void test_building_type_exists(CuTest * tc)
{
region *r;
building *b;
@ -33,6 +33,6 @@ static void building_type_exists(CuTest * tc)
CuSuite *get_move_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, building_type_exists);
SUITE_ADD_TEST(suite, test_building_type_exists);
return suite;
}

View File

@ -1405,6 +1405,107 @@ static void prepare_lighthouse(building * b, faction * f)
ql_free(rlist);
}
void reorder_units(region * r)
{
unit **unext = &r->units;
if (r->buildings) {
building *b = r->buildings;
while (*unext && b) {
unit **ufirst = unext; /* where the first unit in the building should go */
unit **umove = unext; /* a unit we consider moving */
unit *owner = NULL;
while (*umove) {
unit *u = *umove;
if (u->number && u->building == b) {
unit **uinsert = unext;
if (fval(u, UFL_OWNER)) {
uinsert = ufirst;
owner = u;
}
if (umove != uinsert) {
*umove = u->next;
u->next = *uinsert;
*uinsert = u;
} else {
/* no need to move, skip ahead */
umove = &u->next;
}
if (unext == uinsert) {
/* we have a new well-placed unit. jump over it */
unext = &u->next;
}
} else {
umove = &u->next;
}
}
if (!owner && ufirst != unext) {
owner = *ufirst;
fset(owner, UFL_OWNER);
}
b = b->next;
}
}
if (r->ships) {
ship *sh = r->ships;
/* first, move all units up that are not on ships */
unit **umove = unext; /* a unit we consider moving */
while (*umove) {
unit *u = *umove;
if (u->number && !u->ship) {
if (umove != unext) {
*umove = u->next;
u->next = *unext;
*unext = u;
} else {
/* no need to move, skip ahead */
umove = &u->next;
}
/* we have a new well-placed unit. jump over it */
unext = &u->next;
} else {
umove = &u->next;
}
}
while (*unext && sh) {
unit **ufirst = unext; /* where the first unit in the building should go */
unit **umove = unext; /* a unit we consider moving */
unit *owner = NULL;
while (*umove) {
unit *u = *umove;
if (u->number && u->ship == sh) {
unit **uinsert = unext;
if (fval(u, UFL_OWNER)) {
uinsert = ufirst;
owner = u;
}
if (umove != uinsert) {
*umove = u->next;
u->next = *uinsert;
*uinsert = u;
} else {
/* no need to move, skip ahead */
umove = &u->next;
}
if (unext == uinsert) {
/* we have a new well-placed unit. jump over it */
unext = &u->next;
}
} else {
umove = &u->next;
}
}
if (!owner && ufirst != unext) {
owner = *ufirst;
fset(owner, UFL_OWNER);
}
sh = sh->next;
}
}
}
static void prepare_reports(void)
{
region *r;

View File

@ -52,6 +52,7 @@ extern "C" {
extern int reports(void);
extern int write_reports(struct faction *f, time_t ltime);
extern int init_reports(void);
extern void reorder_units(struct region * r);
extern const struct unit *ucansee(const struct faction *f,
const struct unit *u, const struct unit *x);

60
src/kernel/reports_test.c Normal file
View File

@ -0,0 +1,60 @@
#include <platform.h>
#include <kernel/building.h>
#include <kernel/reports.h>
#include <kernel/region.h>
#include <kernel/ship.h>
#include <kernel/unit.h>
#include <cutest/CuTest.h>
#include <tests.h>
static void test_reorder_units(CuTest * tc)
{
region *r;
building *b;
ship * s;
unit *u0, *u1, *u2, *u3, *u4;
struct faction * f;
const building_type *btype;
const ship_type *stype;
test_cleanup();
test_create_world();
btype = bt_find("castle");
stype = st_find("boat");
r = findregion(-1, 0);
b = test_create_building(r, btype);
s = test_create_ship(r, stype);
f = test_create_faction(0);
u0 = test_create_unit(f, r);
u_set_ship(u0, s);
u1 = test_create_unit(f, r);
u_set_ship(u1, s);
ship_set_owner(s, u1);
u2 = test_create_unit(f, r);
u3 = test_create_unit(f, r);
u_set_building(u3, b);
u4 = test_create_unit(f, r);
u_set_building(u4, b);
building_set_owner(b, u4);
reorder_units(r);
CuAssertPtrEquals(tc, u4, r->units);
CuAssertPtrEquals(tc, u3, u4->next);
CuAssertPtrEquals(tc, u2, u3->next);
CuAssertPtrEquals(tc, u1, u2->next);
CuAssertPtrEquals(tc, u0, u1->next);
CuAssertPtrEquals(tc, 0, u0->next);
}
CuSuite *get_reports_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_reorder_units);
return suite;
}

View File

@ -792,16 +792,25 @@ unit *read_unit(struct storage *store)
set_number(u, number);
n = store->r_id(store);
if (n > 0)
u->building = findbuilding(n);
if (n > 0) {
building * b = findbuilding(n);
if (b) {
u_set_building(u, b);
} else {
log_error("read_unit: unit in unkown building '%s'\n", itoa36(n));
}
}
n = store->r_id(store);
if (n > 0) {
ship * sh = findship(n);
if (sh) {
u_set_ship(u, sh);
} else {
log_error("read_unit: unit in unkown ship '%s'\n", itoa36(n));
}
}
setstatus(u, store->r_int(store));
u->flags = store->r_int(store);
u->flags &= UFL_SAVEMASK;

View File

@ -160,17 +160,6 @@ void damage_ship(ship * sh, double percent)
sh->damage = (int)damage;
}
unit *captain(ship * sh)
{
unit *u;
for (u = sh->region->units; u; u = u->next)
if (u->ship == sh && fval(u, UFL_OWNER))
return u;
return NULL;
}
/* Alte Schiffstypen: */
static ship *deleted_ships;
@ -287,7 +276,16 @@ void getshipweight(const ship * sh, int *sweight, int *scabins)
}
}
unit *shipowner(ship * sh)
void ship_set_owner(ship * sh, unit * u) {
assert(u->ship==sh);
if (sh->owner && sh->owner!=u) {
freset(sh->owner, UFL_OWNER);
}
sh->owner = u;
fset(u, UFL_OWNER);
}
unit *ship_owner(ship * sh)
{
unit *owner = sh->owner;
if (owner && owner->number<=0) {

View File

@ -94,9 +94,9 @@ extern "C" {
direction_t coast;
} ship;
extern void damage_ship(ship * sh, double percent);
extern struct unit *captain(ship * sh);
extern struct unit *shipowner(struct ship *sh);
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 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

@ -24,6 +24,33 @@ static void test_register_ship(CuTest * tc)
CuAssertPtrNotNull(tc, st_find("herp"));
}
static void test_ship_set_owner(CuTest * tc)
{
struct region *r;
struct ship *sh;
struct unit *u1, *u2;
struct faction *f;
const struct ship_type *stype;
const struct race *human;
test_cleanup();
test_create_world();
human = rc_find("human");
stype = st_find("boat");
f = test_create_faction(human);
r = findregion(0, 0);
sh = test_create_ship(r, stype);
u1 = test_create_unit(f, r);
u2 = test_create_unit(f, r);
u_set_ship(u1, sh);
u_set_ship(u2, sh);
CuAssertPtrEquals(tc, u1, ship_owner(sh));
ship_set_owner(sh, u2);
CuAssertPtrEquals(tc, u2, ship_owner(sh));
}
static void test_shipowner_goes_to_next_after_death(CuTest * tc)
{
struct region *r;
@ -53,9 +80,9 @@ static void test_shipowner_goes_to_next_after_death(CuTest * tc)
CuAssertPtrNotNull(tc, u);
u_set_ship(u, sh);
u_set_ship(u2, sh);
CuAssertPtrEquals(tc, u, shipowner(sh));
CuAssertPtrEquals(tc, u, ship_owner(sh));
u->number = 0;
CuAssertPtrEquals(tc, u2, shipowner(sh));
CuAssertPtrEquals(tc, u2, ship_owner(sh));
}
static void test_shipowner_goes_to_other_after_death(CuTest * tc)
@ -87,9 +114,9 @@ static void test_shipowner_goes_to_other_after_death(CuTest * tc)
CuAssertPtrNotNull(tc, u);
u_set_ship(u, sh);
u_set_ship(u2, sh);
CuAssertPtrEquals(tc, u, shipowner(sh));
CuAssertPtrEquals(tc, u, ship_owner(sh));
u->number = 0;
CuAssertPtrEquals(tc, u2, shipowner(sh));
CuAssertPtrEquals(tc, u2, ship_owner(sh));
}
static void test_shipowner_goes_to_same_faction_after_death(CuTest * tc)
@ -124,14 +151,14 @@ static void test_shipowner_goes_to_same_faction_after_death(CuTest * tc)
u_set_ship(u, sh);
u_set_ship(u2, sh);
u_set_ship(u3, sh);
CuAssertPtrEquals(tc, u, shipowner(sh));
CuAssertPtrEquals(tc, u, ship_owner(sh));
CuAssertTrue(tc, fval(u, UFL_OWNER));
u->number = 0;
CuAssertPtrEquals(tc, u3, shipowner(sh));
CuAssertPtrEquals(tc, u3, ship_owner(sh));
CuAssertTrue(tc, !fval(u, UFL_OWNER));
CuAssertTrue(tc, fval(u3, UFL_OWNER));
u3->number = 0;
CuAssertPtrEquals(tc, u2, shipowner(sh));
CuAssertPtrEquals(tc, u2, ship_owner(sh));
CuAssertTrue(tc, !fval(u3, UFL_OWNER));
CuAssertTrue(tc, fval(u2, UFL_OWNER));
}
@ -165,9 +192,9 @@ static void test_shipowner_goes_to_next_after_leave(CuTest * tc)
CuAssertPtrNotNull(tc, u);
u_set_ship(u, sh);
u_set_ship(u2, sh);
CuAssertPtrEquals(tc, u, shipowner(sh));
CuAssertPtrEquals(tc, u, ship_owner(sh));
leave_ship(u);
CuAssertPtrEquals(tc, u2, shipowner(sh));
CuAssertPtrEquals(tc, u2, ship_owner(sh));
}
static void test_shipowner_goes_to_other_after_leave(CuTest * tc)
@ -199,9 +226,9 @@ static void test_shipowner_goes_to_other_after_leave(CuTest * tc)
CuAssertPtrNotNull(tc, u);
u_set_ship(u, sh);
u_set_ship(u2, sh);
CuAssertPtrEquals(tc, u, shipowner(sh));
CuAssertPtrEquals(tc, u, ship_owner(sh));
leave_ship(u);
CuAssertPtrEquals(tc, u2, shipowner(sh));
CuAssertPtrEquals(tc, u2, ship_owner(sh));
}
static void test_shipowner_goes_to_same_faction_after_leave(CuTest * tc)
@ -236,13 +263,13 @@ static void test_shipowner_goes_to_same_faction_after_leave(CuTest * tc)
u_set_ship(u, sh);
u_set_ship(u2, sh);
u_set_ship(u3, sh);
CuAssertPtrEquals(tc, u, shipowner(sh));
CuAssertPtrEquals(tc, u, ship_owner(sh));
leave_ship(u);
CuAssertPtrEquals(tc, u3, shipowner(sh));
CuAssertPtrEquals(tc, u3, ship_owner(sh));
leave_ship(u3);
CuAssertPtrEquals(tc, u2, shipowner(sh));
CuAssertPtrEquals(tc, u2, ship_owner(sh));
leave_ship(u2);
CuAssertPtrEquals(tc, 0, shipowner(sh));
CuAssertPtrEquals(tc, 0, ship_owner(sh));
}
static void test_shipowner_resets_when_dead(CuTest * tc)
@ -272,15 +299,16 @@ static void test_shipowner_resets_when_dead(CuTest * tc)
u = test_create_unit(f, r);
CuAssertPtrNotNull(tc, u);
u_set_ship(u, sh);
CuAssertPtrEquals(tc, u, shipowner(sh));
CuAssertPtrEquals(tc, u, ship_owner(sh));
u->number = 0;
CuAssertPtrEquals(tc, 0, shipowner(sh));
CuAssertPtrEquals(tc, 0, ship_owner(sh));
}
CuSuite *get_ship_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_register_ship);
SUITE_ADD_TEST(suite, test_ship_set_owner);
SUITE_ADD_TEST(suite, test_shipowner_resets_when_dead);
SUITE_ADD_TEST(suite, test_shipowner_goes_to_next_after_death);
SUITE_ADD_TEST(suite, test_shipowner_goes_to_other_after_death);

View File

@ -774,6 +774,12 @@ ship *leftship(const unit * u)
return NULL;
}
void u_set_building(unit * u, building * b)
{
assert(b && !u->building); /* you must leave first */
u->building = b;
}
void u_set_ship(unit * u, ship * sh)
{
assert(!u->ship); /* you must leave_ship */
@ -1446,8 +1452,15 @@ void name_unit(unit * u)
}
} else {
char name[32];
snprintf(name, sizeof(name), "%s %s", LOC(u->faction->locale,
"unitdefault"), itoa36(u->no));
static const char * prefix[MAXLOCALES];
int i = locale_index(u->faction->locale);
if (!prefix[i]) {
prefix[i] = LOC(u->faction->locale, "unitdefault");
if (!prefix[i]) {
prefix[i] = parameters[P_UNIT];
}
}
snprintf(name, sizeof(name), "%s %s", prefix[i], itoa36(u->no));
unit_setname(u, name);
}
}

View File

@ -182,6 +182,7 @@ extern "C" {
extern boolean leave(struct unit *u, boolean force);
extern boolean can_leave(struct unit *u);
extern void u_set_building(struct unit * u, struct building * b);
extern void u_set_ship(struct unit * u, struct ship * sh);
extern void leave_ship(struct unit * u);
extern void leave_building(struct unit * u);

View File

@ -94,7 +94,7 @@ void score(void)
}
for (s = r->ships; s; s = s->next) {
unit *cap = shipowner(s);
unit *cap = ship_owner(s);
if (cap && cap->faction) {
cap->faction->score += s->size * 2;
}

View File

@ -13,6 +13,7 @@
#include <kernel/spell_test.c>
#include <kernel/curse_test.c>
#include <kernel/battle_test.c>
#include <kernel/reports_test.c>
#include <gamecode/laws_test.c>
#include <gamecode/market_test.c>
@ -44,6 +45,7 @@ int RunAllTests(void)
CuSuiteAddSuite(suite, get_curse_suite());
CuSuiteAddSuite(suite, get_market_suite());
CuSuiteAddSuite(suite, get_move_suite());
CuSuiteAddSuite(suite, get_reports_suite());
CuSuiteAddSuite(suite, get_ship_suite());
CuSuiteAddSuite(suite, get_spell_suite());
CuSuiteAddSuite(suite, get_laws_suite());
@ -80,7 +82,7 @@ struct region *test_create_region(int x, int y, const terrain_type *terrain)
struct faction *test_create_faction(const struct race *rc)
{
faction *f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0);
faction *f = addfaction("nobody@eressea.de", NULL, rc?rc:rc_find("human"), default_locale, 0);
return f;
}