static char * unit_move_route(struct empobj *unit, char *buf, size_t bufsz) { coord destx; coord desty; struct sctstr sect; size_t len; double c; int mtype; if (CANT_HAPPEN(unit->ef_type != EF_LAND && unit->ef_type != EF_SHIP)) return NULL; if (!sarg_xy(buf, &destx, &desty)) return buf; if (unit->ef_type == EF_SHIP) { c = path_find(unit->x, unit->y, destx, desty, player->cnum, MOB_SAIL); if (c < 0 || unit->mobil <= 0) { pr("Can't get to '%s' right now.\n", xyas(destx, desty, player->cnum)); return NULL; } } else { getsect(unit->x, unit->y, §); mtype = lnd_mobtype((struct lndstr *)unit); /* * Note: passing sect.sct_own for actor is funny, but works: * its only effect is to confine the search to that nation's * land. It doesn't affect mobility costs. The real actor is * different for marching in allied land, and passing it would * break path finding there. */ c = path_find(unit->x, unit->y, destx, desty, sect.sct_own, mtype); if (c < 0) { pr("No owned %s from %s to %s!\n", mtype == MOB_RAIL ? "railway" : "path", xyas(unit->x, unit->y, player->cnum), xyas(destx, desty, player->cnum)); return NULL; } } len = path_find_route(buf, bufsz, unit->x, unit->y, destx, desty); if (len == 0 || unit->ef_type == EF_LAND) { if (len + 1 < bufsz) strcpy(buf + len, "h"); len++; } if (len >= bufsz) { pr("Can't handle path to %s, it's too long, sorry\n", xyas(destx, desty, player->cnum)); return NULL; } pr("Using path '%s'\n", buf); return buf; }
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); }