diff --git a/src/kernel/build.c b/src/kernel/build.c index d2ca8c155..7a05f2def 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -1167,7 +1167,7 @@ static boolean mayenter(region * r, unit * u, building * b) return false; } -static int mayboard(const unit * u, const ship * sh) +static int mayboard(const unit * u, ship * sh) { unit *u2 = shipowner(sh); diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 0ab945981..cc15fc53c 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -2494,7 +2494,7 @@ unit *get_clone_mage(const unit * u) return NULL; } -static boolean is_moving_ship(const region * r, const ship * sh) +static boolean is_moving_ship(const region * r, ship * sh) { const unit *u = shipowner(sh); diff --git a/src/kernel/move.c b/src/kernel/move.c index bf62587d7..99b6c27af 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -633,7 +633,7 @@ static boolean is_freezing(const unit * u) #define SA_NO_INSECT -1 #define SA_NO_COAST -2 -static int ship_allowed(const struct ship *sh, const region * r) +static int is_ship_allowed(struct ship *sh, const region * r) { int c = 0; static const building_type *bt_harbour = NULL; @@ -752,7 +752,7 @@ static void drifting_ships(region * r) region *rn; dir = (direction_t) ((d + d_offset) % MAXDIRECTIONS); rn = rconnect(r, dir); - if (rn != NULL && fval(rn->terrain, SAIL_INTO) && ship_allowed(sh, rn) > 0) { + if (rn != NULL && fval(rn->terrain, SAIL_INTO) && is_ship_allowed(sh, rn) > 0) { rnext = rn; if (!fval(rnext->terrain, SEA_REGION)) break; @@ -1820,7 +1820,7 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) } } - reason = ship_allowed(sh, next_point); + reason = is_ship_allowed(sh, next_point); if (reason<0) { /* for some reason or another, we aren't allowed in there.. */ if (check_leuchtturm(current_point, NULL) || reason == SA_NO_INSECT) { diff --git a/src/kernel/ship.c b/src/kernel/ship.c index e6a529ee3..d8aecfb23 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -287,31 +287,37 @@ void getshipweight(const ship * sh, int *sweight, int *scabins) } } -unit *shipowner(const ship * sh) +unit *shipowner(ship * sh) { - unit *u; - unit *first = NULL; + unit *owner = sh->owner; + if (owner && owner->number<=0) { + unit *u, *first = NULL; - const region *r = sh->region; - - /* Prüfen ob Eigentümer am leben. */ - for (u = r->units; u; u = u->next) { - if (u->ship == sh) { - if (!first && u->number > 0) - first = u; - if (fval(u, UFL_OWNER) && u->number > 0) - return u; - if (u->number == 0) - freset(u, UFL_OWNER); + 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; + break; + } + else if (!first) { + first = u; /* you'll do in an emergency */ + } + } + } + } + owner = first; + if (owner) { + fset(owner, UFL_OWNER); + sh->owner = owner; } } - /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit * nehmen. */ - - if (first) - fset(first, UFL_OWNER); - return first; + return owner; } void write_ship_reference(const struct ship *sh, struct storage *store) diff --git a/src/kernel/ship.h b/src/kernel/ship.h index 4a33ac701..517303d99 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -96,7 +96,7 @@ extern "C" { extern void damage_ship(ship * sh, double percent); extern struct unit *captain(ship * sh); - extern struct unit *shipowner(const struct ship *sh); + extern struct unit *shipowner(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 33bbb3cd3..2fb172422 100644 --- a/src/kernel/ship_test.c +++ b/src/kernel/ship_test.c @@ -24,7 +24,7 @@ static void test_register_ship(CuTest * tc) CuAssertPtrNotNull(tc, st_find("herp")); } -static void test_shipowner_goes_to_next(CuTest * tc) +static void test_shipowner_goes_to_next_after_death(CuTest * tc) { struct region *r; struct ship *sh; @@ -58,6 +58,193 @@ static void test_shipowner_goes_to_next(CuTest * tc) CuAssertPtrEquals(tc, u2, shipowner(sh)); } +static void test_shipowner_goes_to_other_after_death(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u, *u2; + struct faction *f; + 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); + + f = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u2 = test_create_unit(f, r); + u = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + u_set_ship(u, sh); + u_set_ship(u2, sh); + CuAssertPtrEquals(tc, u, shipowner(sh)); + u->number = 0; + CuAssertPtrEquals(tc, u2, shipowner(sh)); +} + +static void test_shipowner_goes_to_same_faction_after_death(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u, *u2, *u3; + struct faction *f1, *f2; + 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); + f2 = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u2 = test_create_unit(f2, r); + u3 = test_create_unit(f1, r); + u = test_create_unit(f1, r); + CuAssertPtrNotNull(tc, u); + u_set_ship(u, sh); + u_set_ship(u2, sh); + u_set_ship(u3, sh); + CuAssertPtrEquals(tc, u, shipowner(sh)); + CuAssertTrue(tc, fval(u, UFL_OWNER)); + u->number = 0; + CuAssertPtrEquals(tc, u3, shipowner(sh)); + CuAssertTrue(tc, !fval(u, UFL_OWNER)); + CuAssertTrue(tc, fval(u3, UFL_OWNER)); + u3->number = 0; + CuAssertPtrEquals(tc, u2, shipowner(sh)); + CuAssertTrue(tc, !fval(u3, UFL_OWNER)); + CuAssertTrue(tc, fval(u2, UFL_OWNER)); +} + +static void test_shipowner_goes_to_next_after_leave(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u, *u2; + struct faction *f; + 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); + + f = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u = test_create_unit(f, r); + u2 = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + u_set_ship(u, sh); + u_set_ship(u2, sh); + CuAssertPtrEquals(tc, u, shipowner(sh)); + leave_ship(u); + CuAssertPtrEquals(tc, u2, shipowner(sh)); +} + +static void test_shipowner_goes_to_other_after_leave(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u, *u2; + struct faction *f; + 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); + + f = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u2 = test_create_unit(f, r); + u = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + u_set_ship(u, sh); + u_set_ship(u2, sh); + CuAssertPtrEquals(tc, u, shipowner(sh)); + leave_ship(u); + CuAssertPtrEquals(tc, u2, shipowner(sh)); +} + +static void test_shipowner_goes_to_same_faction_after_leave(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u, *u2, *u3; + struct faction *f1, *f2; + 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); + f2 = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u2 = test_create_unit(f2, r); + u3 = test_create_unit(f1, r); + u = test_create_unit(f1, r); + CuAssertPtrNotNull(tc, u); + u_set_ship(u, sh); + u_set_ship(u2, sh); + u_set_ship(u3, sh); + CuAssertPtrEquals(tc, u, shipowner(sh)); + leave_ship(u); + CuAssertPtrEquals(tc, u3, shipowner(sh)); + leave_ship(u3); + CuAssertPtrEquals(tc, u2, shipowner(sh)); + leave_ship(u2); + CuAssertPtrEquals(tc, 0, shipowner(sh)); +} + static void test_shipowner_resets_when_dead(CuTest * tc) { struct region *r; @@ -95,6 +282,11 @@ CuSuite *get_ship_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_register_ship); SUITE_ADD_TEST(suite, test_shipowner_resets_when_dead); - SUITE_ADD_TEST(suite, test_shipowner_goes_to_next); + 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_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); return suite; } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 2cc272539..58dba10df 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -807,8 +807,8 @@ void leave_ship(unit * u) } } } + sh->owner = owner; if (owner) { - sh->owner = owner; fset(owner, UFL_OWNER); } }