From 5f6e27ff801cae398020cdff3a7b7547e72df439 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sun, 14 Sep 2008 15:13:16 -0400 Subject: [PATCH] Refactor and fix takeover.c Factor new takeover_unit() out of takeover_ship(), takeover_plane(), takeover_land(). This fixes the following bugs in assault, attack, board, lboard, paradrop and pboard: * When the "land unit loaded on land unit" relation had a cycle, takeover_land() went into an infinite recursion. Such cycles exist only in a corrupt game state. * Nukes armed on planes weren't taken over along with their plane. Broken in commit 2e40a4bb, v4.3.3. * Taking over land units with negative mobility increased mobility to zero. Ditto planes embarked on ships or land units. * Taking over planes embarked on ships or land units didn't clear their wing. * Taking over planes and land units updated their MOB_ACCESS timestamp (pln_access, lnd_access), except for planes not embarked on anything. This had no effect. --- src/lib/subs/takeover.c | 129 +++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 76 deletions(-) diff --git a/src/lib/subs/takeover.c b/src/lib/subs/takeover.c index 2c23a077..6037e4bf 100644 --- a/src/lib/subs/takeover.c +++ b/src/lib/subs/takeover.c @@ -35,6 +35,7 @@ #include #include "file.h" +#include "empobj.h" #include "game.h" #include "land.h" #include "lost.h" @@ -48,6 +49,8 @@ #include "ship.h" #include "xy.h" +static void takeover_unit(struct empobj *, natid); + void takeover(struct sctstr *sp, natid newown) { @@ -200,96 +203,70 @@ takeover_plane(struct plnstr *pp, natid newown) prplane(pp), cname(newown), xyas(pp->pln_x, pp->pln_y, pp->pln_own)); } - if (opt_MARKET) - trdswitchown(EF_PLANE, pp, newown); - if (pp->pln_mobil > 0) - pp->pln_mobil = 0; - pp->pln_own = newown; - pp->pln_mission = 0; - pp->pln_wing = 0; - putplane(pp->pln_uid, pp); + takeover_unit((struct empobj *)pp, newown); } void takeover_ship(struct shpstr *sp, natid newown) { - struct plnstr *pp; - struct lndstr *lp; - struct nstr_item ni; - struct plnstr p; - struct lndstr llp; - - if (opt_MARKET) - trdswitchown(EF_SHIP, sp, newown); - sp->shp_own = newown; - sp->shp_mission = 0; - sp->shp_fleet = 0; - sp->shp_rflags = 0; - memset(sp->shp_rpath, 0, sizeof(sp->shp_rpath)); - pp = &p; - lp = &llp; - /* Take over planes */ - snxtitem_cargo(&ni, EF_PLANE, EF_SHIP, sp->shp_uid); - while (nxtitem(&ni, pp)) { - if (pp->pln_effic > PLANE_MINEFF) - pp->pln_effic = PLANE_MINEFF; - pp->pln_mobil = 0; - if (opt_MOB_ACCESS) - game_tick_to_now(&pp->pln_access); - if (opt_MARKET) - trdswitchown(EF_PLANE, pp, newown); - pp->pln_mission = 0; - pp->pln_own = newown; - putplane(pp->pln_uid, pp); - } - /* Take over land units */ - snxtitem_cargo(&ni, EF_LAND, EF_SHIP, sp->shp_uid); - while (nxtitem(&ni, lp)) - takeover_land(lp, newown); - putship(sp->shp_uid, sp); + takeover_unit((struct empobj *)sp, newown); } void takeover_land(struct lndstr *landp, natid newown) { + takeover_unit((struct empobj *)landp, newown); +} + +static void +takeover_unit(struct empobj *unit, natid newown) +{ + struct shpstr *sp; struct plnstr *pp; struct lndstr *lp; + int type; struct nstr_item ni; - struct plnstr p; - struct lndstr llp; + union empobj_storage cargo; - if (landp->lnd_effic < LAND_MINEFF) { - putland(landp->lnd_uid, landp); - return; - } - landp->lnd_army = 0; - landp->lnd_mobil = 0; - if (opt_MOB_ACCESS) - game_tick_to_now(&landp->lnd_access); - landp->lnd_harden = 0; + unit->own = newown; if (opt_MARKET) - trdswitchown(EF_LAND, landp, newown); - landp->lnd_mission = 0; - landp->lnd_own = newown; - pp = &p; - lp = &llp; - /* Take over planes */ - snxtitem_cargo(&ni, EF_PLANE, EF_LAND, landp->lnd_uid); - while (nxtitem(&ni, pp)) { - if (pp->pln_effic > PLANE_MINEFF) - pp->pln_effic = PLANE_MINEFF; - pp->pln_mobil = 0; - if (opt_MOB_ACCESS) - game_tick_to_now(&pp->pln_access); - if (opt_MARKET) - trdswitchown(EF_PLANE, pp, newown); - pp->pln_mission = 0; - pp->pln_own = newown; - putplane(pp->pln_uid, pp); + trdswitchown(unit->ef_type, unit, newown); + unit->group = 0; + unit->mission = 0; + + switch (unit->ef_type) { + case EF_SHIP: + sp = (struct shpstr *)unit; + sp->shp_rflags = 0; + memset(sp->shp_rpath, 0, sizeof(sp->shp_rpath)); + break; + case EF_PLANE: + pp = (struct plnstr *)unit; + if (pp->pln_mobil > 0) + pp->pln_mobil = 0; + break; + case EF_LAND: + lp = (struct lndstr *)unit; + if (lp->lnd_mobil > 0) + lp->lnd_mobil = 0; + lp->lnd_harden = 0; + break; + case EF_NUKE: + break; + default: + CANT_REACH(); + } + + put_empobj(unit->ef_type, unit->uid, unit); + + for (type = EF_PLANE; type <= EF_NUKE; type++) { + snxtitem_cargo(&ni, type, unit->ef_type, unit->uid); + while (nxtitem(&ni, &cargo)) { + if (cargo.gen.own == newown) + continue; + if (type == EF_PLANE) + cargo.plane.pln_effic = PLANE_MINEFF; + takeover_unit(&cargo.gen, newown); + } } - /* Take over land units */ - snxtitem_cargo(&ni, EF_LAND, EF_LAND, landp->lnd_uid); - while (nxtitem(&ni, lp)) - takeover_land(lp, newown); - putland(landp->lnd_uid, landp); }