From b95f7ec139ab282d733e9a916dbcfcfafa5edcfb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 18 May 2012 23:20:38 -0700 Subject: [PATCH] more strictly define what it means to be the owner of the show, and when it is transferred. mostly copied from building_owner. test coverage is a wonderful thing. --- src/kernel/building.c | 15 ++++++----- src/kernel/ship.c | 47 ++++++++++++++++++++------------- src/kernel/ship.h | 2 ++ src/kernel/ship_test.c | 60 ++++++++++++++++++++++++++++++++++++------ src/kernel/unit.c | 1 + 5 files changed, 92 insertions(+), 33 deletions(-) diff --git a/src/kernel/building.c b/src/kernel/building.c index 43dff12ef..77af096cb 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -500,7 +500,6 @@ static building *deleted_buildings; void remove_building(building ** blist, building * b) { unit *u; - direction_t d; static const struct building_type *bt_caravan, *bt_dam, *bt_tunnel; static boolean init = false; @@ -527,15 +526,19 @@ void remove_building(building ** blist, building * b) * gebaute Straße zur Hälfte vernichtet */ if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) { region *r = b->region; - for (d = 0; d != MAXDIRECTIONS; ++d) - if (rroad(r, d) > 0) { - rsetroad(r, d, rroad(r, d) / 2); + int d; + for (d = 0; d != MAXDIRECTIONS; ++d) { + direction_t dir = (direction_t)d; + if (rroad(r, dir) > 0) { + rsetroad(r, dir, rroad(r, dir) / 2); } + } } /* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */ - while (*blist && *blist != b) + while (*blist && *blist != b) { blist = &(*blist)->next; + } *blist = b->next; b->region = NULL; b->next = deleted_buildings; @@ -630,7 +633,7 @@ void building_set_owner(struct building *b, struct unit * owner) b->_owner = owner; } -static unit *building_owner_ex(const building * bld, const faction * last_owner) +static unit *building_owner_ex(const building * bld, const struct faction * last_owner) { unit *u, *heir = 0; diff --git a/src/kernel/ship.c b/src/kernel/ship.c index d596e1873..46f75689d 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -291,31 +291,40 @@ void ship_set_owner(ship * sh, unit * u) { sh->_owner = u; } -unit *ship_owner(const ship * sh) +static unit * ship_owner_ex(const ship * sh, const struct faction * last_owner) { - unit *owner = sh->_owner; - if (owner && (owner->ship!=sh || owner->number<=0)) { - unit *u, *heir = 0; + unit *u, *heir = 0; - owner->ship = 0; - /* 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) { - heir = u; - break; - } - else if (!heir) { - heir = u; /* you'll do in an emergency */ - } + /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit + * nehmen. */ + for (u = sh->region->units; u; u = u->next) { + if (u->ship == sh) { + if (u->number > 0) { + if (heir && last_owner && heir->faction!=last_owner && u->faction==last_owner) { + heir = u; + 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 */ } } } - owner = heir; } - /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit - * nehmen. */ + return heir; +} + +void ship_update_owner(ship * sh) { + unit * owner = sh->_owner; + sh->_owner = ship_owner_ex(sh, owner?owner->faction:0); +} + +unit *ship_owner(const ship * sh) +{ + unit *owner = sh->_owner; + if (!owner || (owner->ship!=sh || owner->number<=0)) { + unit * heir = ship_owner_ex(sh, owner?owner->faction:0); + return (heir && heir->number>0) ? heir : 0; + } return owner; } diff --git a/src/kernel/ship.h b/src/kernel/ship.h index b4e95a302..fe1322f47 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -97,6 +97,8 @@ 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(const struct ship *sh); + extern void ship_update_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); diff --git a/src/kernel/ship_test.c b/src/kernel/ship_test.c index fc7c1be1f..6b1d2e136 100644 --- a/src/kernel/ship_test.c +++ b/src/kernel/ship_test.c @@ -54,7 +54,7 @@ static void test_ship_set_owner(CuTest * tc) CuAssertPtrEquals(tc, u2, ship_owner(sh)); } -static void test_shipowner_goes_to_next_after_death(CuTest * tc) +static void test_shipowner_goes_to_next_when_empty(CuTest * tc) { struct region *r; struct ship *sh; @@ -88,7 +88,7 @@ static void test_shipowner_goes_to_next_after_death(CuTest * tc) CuAssertPtrEquals(tc, u2, ship_owner(sh)); } -static void test_shipowner_goes_to_other_after_death(CuTest * tc) +static void test_shipowner_goes_to_other_when_empty(CuTest * tc) { struct region *r; struct ship *sh; @@ -122,7 +122,7 @@ static void test_shipowner_goes_to_other_after_death(CuTest * tc) CuAssertPtrEquals(tc, u2, ship_owner(sh)); } -static void test_shipowner_goes_to_same_faction_after_death(CuTest * tc) +static void test_shipowner_goes_to_same_faction_when_empty(CuTest * tc) { struct region *r; struct ship *sh; @@ -270,7 +270,7 @@ static void test_shipowner_goes_to_same_faction_after_leave(CuTest * tc) CuAssertPtrEquals(tc, 0, ship_owner(sh)); } -static void test_shipowner_resets_when_dead(CuTest * tc) +static void test_shipowner_resets_when_empty(CuTest * tc) { struct region *r; struct ship *sh; @@ -300,6 +300,49 @@ static void test_shipowner_resets_when_dead(CuTest * tc) CuAssertPtrEquals(tc, u, ship_owner(sh)); u->number = 0; CuAssertPtrEquals(tc, 0, ship_owner(sh)); + u->number = 1; + CuAssertPtrEquals(tc, u, ship_owner(sh)); +} + +void test_shipowner_goes_to_empty_unit_after_leave(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u1, *u2, *u3; + struct faction *f1; + const struct ship_type *stype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + stype = st_find("boat"); + CuAssertPtrNotNull(tc, stype); + + f1 = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u1 = test_create_unit(f1, r); + u2 = test_create_unit(f1, r); + u3 = test_create_unit(f1, r); + u_set_ship(u1, sh); + u_set_ship(u2, sh); + u_set_ship(u3, sh); + + CuAssertPtrEquals(tc, u1, ship_owner(sh)); + u2->number = 0; + leave_ship(u1); + CuAssertPtrEquals(tc, u3, ship_owner(sh)); + leave_ship(u3); + CuAssertPtrEquals(tc, 0, ship_owner(sh)); + u2->number = 1; + CuAssertPtrEquals(tc, u2, ship_owner(sh)); } CuSuite *get_ship_suite(void) @@ -307,12 +350,13 @@ 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); - SUITE_ADD_TEST(suite, test_shipowner_goes_to_same_faction_after_death); + SUITE_ADD_TEST(suite, test_shipowner_resets_when_empty); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_next_when_empty); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_other_when_empty); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_same_faction_when_empty); SUITE_ADD_TEST(suite, test_shipowner_goes_to_next_after_leave); SUITE_ADD_TEST(suite, test_shipowner_goes_to_other_after_leave); SUITE_ADD_TEST(suite, test_shipowner_goes_to_same_faction_after_leave); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_empty_unit_after_leave); return suite; } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 2e150ef37..cbda7e261 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -798,6 +798,7 @@ void leave_ship(unit * u) u->ship = 0; if (sh->_owner==u) { + ship_update_owner(sh); sh->_owner = ship_owner(sh); } set_leftship(u, sh);