int move_ground(struct sctstr *start, struct sctstr *end, double weight, char *path, int (*map)(coord, coord, char *, char *), int exploring, int *dam) { struct sctstr sect; struct sctstr next; coord curx, cury, oldx, oldy; coord tmpx, tmpy; coord dx, dy; char *movstr; double sect_mcost; double total_mcost; double mv_cost; size_t len; double mobility = start->sct_mobil; int dir; char scanspace[1024]; char *argp[128]; int takedam = *dam; int out = 0; char prompt[128]; char buf[1024]; *end = *start; if (mobility <= 0.0) return -1; *dam = 0; if (path && sarg_xy(path, &dx, &dy)) { if (dx == start->sct_x && dy == start->sct_y) { pr("Start sector is ending sector!\n"); return -1; } pr("Looking for best path to %s\n", path); total_mcost = path_find(start->sct_x, start->sct_y, dx, dy, player->cnum, MOB_MOVE); path = NULL; if (total_mcost < 0) pr("No owned path exists!\n"); else { len = path_find_route(buf, sizeof(buf), start->sct_x, start->sct_y, dx, dy); if (!exploring) { if (len < sizeof(buf)) strcpy(buf + len, "h"); len++; } if (len >= sizeof(buf)) pr("Can't handle path to %s, it's too long, sorry.\n", xyas(dx, dy, player->cnum)); else { path = buf; pr("Using best path '%s', movement cost %1.3f\n", path, total_mcost); if (total_mcost * weight > mobility) { pr("Not enough mobility to go all the way." " Nothing moved.\n"); return -1; } } } } movstr = path; curx = start->sct_x; cury = start->sct_y; total_mcost = 0.0; if (getsect(curx, cury, §) < 0) { logerror("move_path: getsect %d,%d", curx, cury); return -1; } for (;;) { oldx = curx; oldy = cury; if (!movstr || *movstr == 0) { if (exploring) { map(curx, cury, NULL, NULL); } else { move_map(curx, cury, NULL); } sprintf(prompt, "<%.1f: %c %s> ", mobility, dchr[sect.sct_type].d_mnem, xyas(sect.sct_x, sect.sct_y, player->cnum)); movstr = getstring(prompt, buf); } if (movstr && sarg_xy(movstr, &dx, &dy)) { mv_cost = path_find(sect.sct_x, sect.sct_y, dx, dy, player->cnum, MOB_MOVE); if (mv_cost < 0) { pr("Can't get to %s from here!\n", xyas(dx, dy, player->cnum)); movstr = NULL; } else { len = path_find_route(buf, sizeof(buf), sect.sct_x, sect.sct_y, dx, dy); if (len < sizeof(buf)) strcpy(buf + len, "h"); len++; if (len >= sizeof(buf)) { pr("Can't handle path to %s, it's too long, sorry.\n", xyas(dx, dy, player->cnum)); movstr = NULL; } else { if ((mv_cost * weight) > mobility) { pr("Not enough mobility to go all the way. Nothing moved.\n"); movstr = NULL; } else { movstr = buf; pr("Using best path '%s', movement cost %1.3f\n", movstr, mv_cost); } } } } if (!movstr || *movstr == 0) { buf[0] = dirch[DIR_STOP]; buf[1] = 0; movstr = buf; } if ((dir = chkdir(*movstr, DIR_STOP, DIR_MAP)) < 0) { pr("\"%c\" is not legal...", *movstr); direrr("'%c' to stop ", "'%c' to view ", "& '%c' to map\n"); *movstr = 0; continue; } if (dir == DIR_MAP) { parse(movstr, scanspace, argp, NULL, NULL, NULL); if (argp[0][1]) { pr("Use of '%c' without a space before its argument is deprecated.\n" "Support for it will go away in a future release\n", *movstr); argp[2] = argp[1]; argp[1] = argp[0] + 1; } if (!exploring) map(curx, cury, argp[1], argp[2]); *movstr = 0; continue; } movstr++; if (dir == DIR_STOP) break; if (dir == DIR_VIEW) { pr("%d%% %s with %d civilians.\n", sect.sct_effic, dchr[sect.sct_type].d_name, sect.sct_item[I_CIVIL]); continue; } /* * now see if we can move into the * next sector. Mobility, terrain, * or ownership may prevent us. */ tmpx = curx + diroff[dir][0]; tmpy = cury + diroff[dir][1]; if (getsect(tmpx, tmpy, &next) < 0) { pr("You can't go there...\n"); *movstr = 0; continue; } if (!player->god) { if ((next.sct_type == SCT_SANCT) && (next.sct_own != player->cnum)) { pr("Converts, huh?\n"); *movstr = 0; continue; } sect_mcost = sector_mcost(&next, MOB_MOVE); if ((!player->owner && (!exploring || next.sct_item[I_MILIT] || next.sct_item[I_CIVIL])) || sect_mcost == -1.0) { /* already-owned, or prohibited terrain */ pr("You can't go there...\n"); *movstr = 0; continue; } sect_mcost *= weight; if (sect_mcost > mobility) { pr("Not enough mobility. "); pr("You can't go there...\n"); *movstr = 0; continue; } mobility -= sect_mcost; total_mcost += sect_mcost; } curx = next.sct_x; cury = next.sct_y; if (cury != start->sct_y) out = 1; if (curx != start->sct_x) out = 1; sect = next; if (takedam) *dam += check_lmines(sect.sct_x, sect.sct_y, weight); if (*dam >= 100) break; /* * Check and see if anyone will interdict us */ if (takedam && chance(weight / 100.0) && ((curx != oldx) || (cury != oldy))) *dam += ground_interdict(curx, cury, player->cnum, "commodities"); if (*dam >= 100) break; } *end = sect; if ((start->sct_x == end->sct_x) && (start->sct_y == end->sct_y) && !out) return -1; return roundavg(total_mcost); }
int unit_move(struct emp_qelem *list) { struct empobj *leader = get_leader(list); int leader_uid = leader->uid; int type = leader->ef_type; int moved, suppress_map, dir, stopping; char *cp; char path[1024]; unit_rad_map_set(list); pr("%s is %s\n", type == EF_SHIP ? "Flagship" : "Leader", unit_nameof(leader)); cp = ""; if (player->argp[2]) { strcpy(path, player->argp[2]); cp = unit_move_route(leader, path, sizeof(path)); if (!cp) cp = ""; } moved = suppress_map = 0; for (;;) { /* * Invariants: * - shp_may_nav() true for all ships * - lnd_may_mar() true for all land units * - leader is up-to-date * Implies all are in the same sector */ if (!*cp) { cp = unit_move_getpath(list, suppress_map, path); if (!cp) { if (type == EF_SHIP) { shp_nav_stay_behind(list, player->cnum); shp_nav_put(list, player->cnum); } else { lnd_mar_stay_behind(list, player->cnum); lnd_mar_put(list, player->cnum); } return RET_FAIL; } cp = unit_move_route(leader, path, sizeof(path)); if (!cp || !*cp) cp = "h"; suppress_map = 0; } else if ((dir = chkdir(*cp, DIR_STOP, DIR_LAST)) >= 0) { cp++; if (type == EF_SHIP) stopping = shp_nav_dir(list, dir, player->cnum) || shp_nav_gauntlet(list, 1, player->cnum); else { if (!moved && !lnd_abandon_askyn(list)) { lnd_mar_put(list, player->cnum); return RET_FAIL; } stopping = lnd_mar_dir(list, dir, player->cnum) || lnd_mar_gauntlet(list, 1, player->cnum); } if (dir == DIR_STOP) { CANT_HAPPEN(!QEMPTY(list)); return RET_OK; } moved = 1; if (stopping) cp = ""; } else { cp = unit_move_non_dir(list, cp, &suppress_map); if (!cp) { direrr("`%c' to stop", ", `%c' to view", NULL); pr(", `i' to list %s, `f' to change %s,\n", type == EF_SHIP ? "ships" : "units", type == EF_SHIP ? "flagship" : "leader"); pr("`r' to radar, %s`l' to look, `M' to map, `B' to bmap,\n", type == EF_SHIP ? "`s' to sonar, " : ""); pr("`d' to drop mines, and `m' to minesweep\n"); cp = ""; } } if (type == EF_SHIP) shp_nav_stay_behind(list, player->cnum); else lnd_mar_stay_behind(list, player->cnum); if (QEMPTY(list)) { pr("No %s left\n", type == EF_SHIP ? "ships" : "lands"); return RET_OK; } leader = get_leader(list); if (leader->uid != leader_uid) { leader_uid = leader->uid; pr("Changing %s to %s\n", leader->ef_type == EF_SHIP ? "flagship" : "leader", unit_nameof(leader)); } unit_rad_map_set(list); } }