From 5ad86bc7ceaa0e8c78bfddf42ceb1015c91a906d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sun, 4 Jun 2006 17:41:12 +0000 Subject: [PATCH] 4.0.2 made land unit mobility costs differ significantly from normal move costs, but failed to make A* use these costs. This broke land unit path finding. Fix: (MOB_ROAD, MOB_MOVE, MOB_MARCH): Split MOB_ROAD into MOB_MOVE and MOB_MARCH. Users changed. (lnd_mobcost, sector_mcost): Move minimum mobcost logic to sector_mcost(), where it is visible to A*. Also fixes unit reaction path cost. (lnd_path): Fix confusing message: don't claim there's no path when all we really know is that there's no railway. --- include/sect.h | 5 ++-- src/lib/commands/sinf.c | 2 +- src/lib/common/move.c | 17 +++++++------ src/lib/common/path.c | 2 +- src/lib/subs/attsub.c | 8 +++--- src/lib/subs/lndsub.c | 53 ++++++++++++++-------------------------- src/lib/subs/move.c | 6 ++--- src/lib/subs/retreat.c | 2 +- src/lib/subs/supply.c | 6 ++--- src/lib/update/deliver.c | 2 +- src/lib/update/finish.c | 2 +- 11 files changed, 46 insertions(+), 59 deletions(-) diff --git a/include/sect.h b/include/sect.h index d75b7c68..ec577043 100644 --- a/include/sect.h +++ b/include/sect.h @@ -179,8 +179,9 @@ extern struct dchrstr bigcity_dchr; #define FORTEFF 5 /* forts must be 5% efficient to fire. */ #define MOB_NONE 0 -#define MOB_ROAD 1 -#define MOB_RAIL 2 +#define MOB_MOVE 1 +#define MOB_MARCH 2 +#define MOB_RAIL 3 #define INT_ROAD 0 #define INT_RAIL 1 diff --git a/src/lib/commands/sinf.c b/src/lib/commands/sinf.c index 23c09bf6..77219c61 100644 --- a/src/lib/commands/sinf.c +++ b/src/lib/commands/sinf.c @@ -76,7 +76,7 @@ sinfra(void) pr(" "); pr("%4d%% ", sect.sct_effic); pr("%4d%% ", sect.sct_road); - pr("%4.3f ", sector_mcost(§, MOB_ROAD)); + pr("%4.3f ", sector_mcost(§, MOB_MOVE)); pr("%4d%% ", sect.sct_rail); pr("%4.3f ", sector_mcost(§, MOB_RAIL)); pr("%4d%% ", SCT_DEFENSE(§)); diff --git a/src/lib/common/move.c b/src/lib/common/move.c index 141accb5..eddc0780 100644 --- a/src/lib/common/move.c +++ b/src/lib/common/move.c @@ -45,12 +45,11 @@ sector_mcost(struct sctstr *sp, int do_bonus) { double d; - if (!(d = dchr[sp->sct_type].d_mcst)) + d = dchr[sp->sct_type].d_mcst; + if (d <= 0) return -1.0; -/* Note, the best you can get is a 1.0 here. */ - - if (do_bonus == MOB_ROAD) { + if (do_bonus == MOB_MOVE || do_bonus == MOB_MARCH) { d = d / (1.0 + sp->sct_road / 122.0); } else if (do_bonus == MOB_RAIL) { if (sp->sct_rail <= 0) @@ -64,11 +63,13 @@ sector_mcost(struct sctstr *sp, int do_bonus) d = 1.0; if (dchr[sp->sct_type].d_mcst < 25) d = (d * 100.0 - sp->sct_effic) / 500.0; -/* d = (200.0 + (d - 3.0) * sp->sct_effic) / 500.0;*/ else d = (d * 10.0 - sp->sct_effic) / 115; - if (d <= 0.0 || d < MIN_MOBCOST) - return MIN_MOBCOST; - return d; + if (do_bonus == MOB_MOVE) + return MAX(d, MIN_MOBCOST); + if (sp->sct_own != sp->sct_oldown && sp->sct_mobil <= 0 + && do_bonus != MOB_RAIL) + return MAX(d, LND_MINMOBCOST); + return MAX(d, 0.01); } diff --git a/src/lib/common/path.c b/src/lib/common/path.c index ab4604ad..0f2f5b19 100644 --- a/src/lib/common/path.c +++ b/src/lib/common/path.c @@ -342,7 +342,7 @@ BestDistPath(char *path, struct sctstr *from, struct sctstr *to, double *cost) { - return BestLandPath(path, from, to, cost, MOB_ROAD); + return BestLandPath(path, from, to, cost, MOB_MOVE); } char * diff --git a/src/lib/subs/attsub.c b/src/lib/subs/attsub.c index aabf9d08..0394f96b 100644 --- a/src/lib/subs/attsub.c +++ b/src/lib/subs/attsub.c @@ -793,7 +793,7 @@ get_mob_support(int combat_mode, struct combat *off, struct combat *def) switch (combat_mode) { case A_ATTACK: mob_support = off->mob / sector_mcost(getsectp(def->x, def->y), - MOB_ROAD); + MOB_MOVE); if (mob_support < 0) mob_support = 0; /* mob_support = off->mob / sector_mcost(def->sct_type, def->eff);*/ @@ -854,7 +854,7 @@ calc_mobcost(int combat_mode, struct combat *off, struct combat *def, off->mobcost += MAX(1, (int)(attacking_mil * - sector_mcost(getsectp(def->x, def->y), MOB_ROAD))); + sector_mcost(getsectp(def->x, def->y), MOB_MOVE))); break; case A_LBOARD: off->mobcost += MAX(1, attacking_mil / 5); @@ -1506,7 +1506,7 @@ att_reacting_units(struct combat *def, struct emp_qelem *list, int a_spy, continue; getsect(def->x, def->y, &dsect); - if (!BestLandPath(buf, §, &dsect, &move_cost, MOB_ROAD)) + if (!BestLandPath(buf, §, &dsect, &move_cost, MOB_MARCH)) continue; mobcost = land.lnd_effic * 0.01 * lchr[(int)land.lnd_type].l_spd; @@ -2445,7 +2445,7 @@ ask_move_in_off(struct combat *off, struct combat *def) return; if (off->own != player->cnum) return; - d = sector_mcost(getsectp(def->x, def->y), MOB_ROAD); + d = sector_mcost(getsectp(def->x, def->y), MOB_MOVE); if ((mob_support = MIN(off->troops, (int)(off->mob / d))) <= 0) return; sprintf(prompt, "How many mil to move in from %s (%d max)? ", diff --git a/src/lib/subs/lndsub.c b/src/lib/subs/lndsub.c index 790d6677..787ad15a 100644 --- a/src/lib/subs/lndsub.c +++ b/src/lib/subs/lndsub.c @@ -242,7 +242,7 @@ lnd_take_casualty(int combat_mode, struct llist *llp, int cas) llp->land.lnd_x = bx; llp->land.lnd_y = by; getsect(bx, by, &rsect); - mobcost = lnd_mobcost(&llp->land, &rsect, MOB_ROAD); + mobcost = lnd_mobcost(&llp->land, &rsect, MOB_MARCH); mob = llp->land.lnd_mobil - (int)mobcost; if (mob < -127) mob = -127; @@ -996,38 +996,20 @@ lnd_hit_mine(struct lndstr *lp, struct lchrstr *lcp) double lnd_mobcost(struct lndstr *lp, struct sctstr *sp, int mobtype) { - double mobcost; - double smobcost; + double effspd; - /* supply unit's speed depends on their eff, since - that is their purpose */ + effspd = lp->lnd_spd; if (lchr[(int)lp->lnd_type].l_flags & L_SUPPLY) - mobcost = lp->lnd_effic * 0.01 * lp->lnd_spd; - else - mobcost = lp->lnd_spd; - if (mobcost < 0.01) - mobcost = 0.01; + effspd *= lp->lnd_effic * 0.01; -/* sector_mcost now takes 2 different arguments, a sector pointer, and - whether or not to figure in the highway bonus, rail bonus or none. - bridge heads, bridges and highways have built-in highways bonus - because they are a 1, and this will discount that. */ - - smobcost = sector_mcost(sp, mobtype); - if (smobcost < 0.01) - smobcost = 0.01; - -/* marching through 0 mobility conquered sectors takes lots of mobility, - unless you are a train. Capturing railways is a good thing. */ - - if (sp->sct_own != sp->sct_oldown && sp->sct_mobil <= 0 && - smobcost < LND_MINMOBCOST && mobtype != MOB_RAIL) - smobcost = LND_MINMOBCOST; - - mobcost = smobcost * 5.0 * 480.0 / - (mobcost + techfact(lp->lnd_tech, mobcost)); - - return mobcost; + /* + * The return value must be sector_mcost(...) times a factor that + * depends only on the land unit. Anything else breaks path + * finding. In particular, you can't add or enforce a minimum + * cost here. Do it in sector_mcost(). + */ + return sector_mcost(sp, mobtype) * 5.0 * 480.0 + / (effspd + techfact(lp->lnd_tech, effspd)); } int @@ -1122,7 +1104,7 @@ lnd_mar_one_sector(struct emp_qelem *list, int dir, natid actor, if (lchr[(int)llp->land.lnd_type].l_flags & L_TRAIN) { llp->mobil -= lnd_mobcost(&llp->land, §, MOB_RAIL); } else { - llp->mobil -= lnd_mobcost(&llp->land, §, MOB_ROAD); + llp->mobil -= lnd_mobcost(&llp->land, §, MOB_MARCH); } llp->land.lnd_mobil = (int)llp->mobil; llp->land.lnd_harden = 0; @@ -1282,6 +1264,7 @@ lnd_path(int together, struct lndstr *lp, char *buf) struct sctstr d_sect, sect; char *cp; double dummy; + int mtype; if (!sarg_xy(buf, &destx, &desty)) return 0; @@ -1295,11 +1278,13 @@ lnd_path(int together, struct lndstr *lp, char *buf) } getsect(lp->lnd_x, lp->lnd_y, §); if (lchr[(int)lp->lnd_type].l_flags & L_TRAIN) - cp = BestLandPath(buf, §, &d_sect, &dummy, MOB_RAIL); + mtype = MOB_RAIL; else - cp = BestLandPath(buf, §, &d_sect, &dummy, MOB_ROAD); + mtype = MOB_MARCH; + cp = BestLandPath(buf, §, &d_sect, &dummy, mtype); if (!cp) { - pr("No owned path from %s to %s!\n", + pr("No owned %s from %s to %s!\n", + mtype == MOB_RAIL ? "railway" : "path", xyas(lp->lnd_x, lp->lnd_y, player->cnum), xyas(d_sect.sct_x, d_sect.sct_y, player->cnum)); return 0; diff --git a/src/lib/subs/move.c b/src/lib/subs/move.c index 7a171534..52aa8933 100644 --- a/src/lib/subs/move.c +++ b/src/lib/subs/move.c @@ -85,7 +85,7 @@ move_ground(struct sctstr *start, struct sctstr *end, } pr("Looking for best path to %s\n", path); path = BestLandPath(buf2, start, &ending_sect, &total_mcost, - MOB_ROAD); + MOB_MOVE); if (exploring && path) /* take off the 'h' */ path[strlen(path) - 1] = '\0'; if (!path) @@ -126,7 +126,7 @@ move_ground(struct sctstr *start, struct sctstr *end, if (movstr && sarg_xy(movstr, &dx, &dy)) { if (getsect(dx, dy, &dsect)) { movstr = BestLandPath(buf2, §, &dsect, &mv_cost, - MOB_ROAD); + MOB_MOVE); } else { pr("Invalid destination sector!\n"); movstr = NULL; @@ -190,7 +190,7 @@ move_ground(struct sctstr *start, struct sctstr *end, *movstr = 0; continue; } - sect_mcost = sector_mcost(&next, MOB_ROAD); + sect_mcost = sector_mcost(&next, MOB_MOVE); if ((!player->owner && (!exploring || next.sct_item[I_MILIT] || next.sct_item[I_CIVIL])) diff --git a/src/lib/subs/retreat.c b/src/lib/subs/retreat.c index 2902f0f9..ecb19893 100644 --- a/src/lib/subs/retreat.c +++ b/src/lib/subs/retreat.c @@ -471,7 +471,7 @@ retreat_land1(struct lndstr *lp, char code, int orig) putland(lp->lnd_uid, lp); return 0; } - mobcost = lnd_mobcost(lp, §, MOB_ROAD); + mobcost = lnd_mobcost(lp, §, MOB_MARCH); lp->lnd_x = newx; lp->lnd_y = newy; lp->lnd_mobil -= mobcost; diff --git a/src/lib/subs/supply.c b/src/lib/subs/supply.c index 8795d045..6384cc92 100644 --- a/src/lib/subs/supply.c +++ b/src/lib/subs/supply.c @@ -200,7 +200,7 @@ s_commod(int own, int x, int y, i_type type, int total_wanted, continue; if (sect.sct_effic < 60) continue; - if (!BestLandPath(buf, &dest, §, &move_cost, MOB_ROAD)) + if (!BestLandPath(buf, &dest, §, &move_cost, MOB_MOVE)) continue; if (!opt_NOFOOD && type == I_FOOD) minimum = 1 + (int)ceil(food_needed(sect.sct_item, @@ -273,7 +273,7 @@ s_commod(int own, int x, int y, i_type type, int total_wanted, continue; if (sect.sct_effic < 2) continue; - if (!BestLandPath(buf, &dest, §, &move_cost, MOB_ROAD)) + if (!BestLandPath(buf, &dest, §, &move_cost, MOB_MOVE)) continue; if (!opt_NOFOOD && type == I_FOOD) minimum = 1 + (int)ceil(food_needed(ship.shp_item, @@ -347,7 +347,7 @@ s_commod(int own, int x, int y, i_type type, int total_wanted, continue; getsect(land.lnd_x, land.lnd_y, §); - if (!BestLandPath(buf, &dest, §, &move_cost, MOB_ROAD)) + if (!BestLandPath(buf, &dest, §, &move_cost, MOB_MOVE)) continue; if ((land.lnd_ship >= 0) && (sect.sct_type != SCT_HARBR)) diff --git a/src/lib/update/deliver.c b/src/lib/update/deliver.c index c6992b7f..4a99b147 100644 --- a/src/lib/update/deliver.c +++ b/src/lib/update/deliver.c @@ -100,7 +100,7 @@ deliver(struct sctstr *from, struct ichrstr *ip, int dir, * calculate unit movement cost; decrease amount if * there isn't enough mobility. */ - mcost = sector_mcost(to, MOB_ROAD) * ip->i_lbs / ip->i_pkg[packing]; + mcost = sector_mcost(to, MOB_MOVE) * ip->i_lbs / ip->i_pkg[packing]; mcost /= DELIVER_BONUS; if (mobility < mcost * amt_moved) { diff --git a/src/lib/update/finish.c b/src/lib/update/finish.c index f6c64600..785faa3d 100644 --- a/src/lib/update/finish.c +++ b/src/lib/update/finish.c @@ -220,7 +220,7 @@ assemble_dist_paths(struct distinfo *distptrs) p = ReversePath(path); /* And walk the path back to the dist center to get the export cost */ - infptr->excost = pathcost(sp, p, MOB_ROAD); + infptr->excost = pathcost(sp, p, MOB_MOVE); #ifdef SAVE_FINISH_PATHS memcpy(infptr->path, p, len); #else