static int still_ok_ship(struct sctstr *sectp, struct shpstr *shipp) { if (!check_sect_ok(sectp)) return 0; if (!check_ship_ok(shipp)) return 0; return 1; }
int tend(void) { struct nstr_item targets; struct nstr_item tenders; struct shpstr tender; struct shpstr target; struct ichrstr *ip; struct mchrstr *vbase; int amt; int retval; int ontender; int ontarget; int maxtender; int maxtarget; int transfer; int total; int type; char *p; char prompt[512]; char buf[1024]; p = getstarg(player->argp[1], "Tend what commodity (or 'land')? ", buf); if (!p || !*p) return RET_SYN; if (!strncmp(p, "land", 4)) type = EF_LAND; else if (NULL != (ip = item_by_name(p))) type = EF_SECTOR; else { pr("Can't tend '%s'\n", p); return RET_SYN; } if (!snxtitem(&tenders, EF_SHIP, player->argp[2], "Tender(s)? ")) return RET_SYN; while (nxtitem(&tenders, &tender)) { if (!player->owner) continue; if (type == EF_LAND) { sprintf(prompt, "Land unit(s) to tend from %s? ", prship(&tender)); p = getstarg(player->argp[3], prompt, buf); if (!p) return RET_FAIL; if (!*p) continue; if (!check_ship_ok(&tender)) return RET_SYN; if (0 != (retval = tend_land(&tender, p))) return retval; continue; } sprintf(prompt, "Number of %s to tend from %s? ", ip->i_name, prship(&tender)); p = getstarg(player->argp[3], prompt, buf); if (!p) return RET_FAIL; if (!*p) continue; if (!check_ship_ok(&tender)) return RET_SYN; if (!(amt = atoi(p))) { pr("Amount must be non-zero!\n"); return RET_SYN; } ontender = tender.shp_item[ip->i_uid]; if (ontender == 0 && amt > 0) { pr("No %s on %s\n", ip->i_name, prship(&tender)); return RET_FAIL; } vbase = &mchr[(int)tender.shp_type]; maxtender = vbase->m_item[ip->i_uid]; if (maxtender == 0) { pr("A %s cannot hold any %s\n", mchr[(int)tender.shp_type].m_name, ip->i_name); break; } if (!snxtitem(&targets, EF_SHIP, player->argp[4], "Ships to be tended? ")) return RET_FAIL; if (!check_ship_ok(&tender)) return RET_SYN; total = 0; while (nxtitem(&targets, &target)) { if (!player->owner && relations_with(target.shp_own, player->cnum) < FRIENDLY) continue; if (target.shp_uid == tender.shp_uid) continue; if (tender.shp_x != target.shp_x || tender.shp_y != target.shp_y) continue; if (ip->i_uid == I_CIVIL && tender.shp_own != target.shp_own) continue; ontarget = target.shp_item[ip->i_uid]; vbase = &mchr[(int)target.shp_type]; maxtarget = vbase->m_item[ip->i_uid]; if (amt < 0) { /* take from target and give to tender */ if (!player->owner) continue; if (ontarget == 0) { pr("No %s on %s\n", ip->i_name, prship(&target)); continue; } transfer = MIN(ontarget, -amt); transfer = MIN(maxtender - ontender, transfer); if (transfer == 0) continue; target.shp_item[ip->i_uid] = ontarget - transfer; ontender += transfer; total += transfer; } else { /* give to target from tender */ transfer = MIN(ontender, amt); transfer = MIN(transfer, maxtarget - ontarget); if (transfer == 0) continue; target.shp_item[ip->i_uid] = ontarget + transfer; ontender -= transfer; total += transfer; if (transfer && target.shp_own != player->cnum) { wu(0, target.shp_own, "%s tended %d %s to %s\n", cname(player->cnum), total, ip->i_name, prship(&target)); } } expose_ship(&tender, &target); putship(target.shp_uid, &target); if (amt > 0 && ontender == 0) { pr("%s out of %s\n", prship(&tender), ip->i_name); break; } } pr("%d total %s transferred %s %s\n", total, ip->i_name, (amt > 0) ? "off of" : "to", prship(&tender)); tender.shp_item[ip->i_uid] = ontender; tender.shp_mission = 0; putship(tender.shp_uid, &tender); } return RET_OK; }
static int tend_land(struct shpstr *tenderp, char *units) { struct nstr_item lni; struct nstr_item targets; struct shpstr target; struct lndstr land; char buf[1024]; if (!snxtitem(&lni, EF_LAND, units, NULL)) return RET_SYN; while (nxtitem(&lni, &land)) { if (!player->owner) continue; if (land.lnd_ship != tenderp->shp_uid) { pr("%s is not on %s!\n", prland(&land), prship(tenderp)); continue; } if (!(lchr[(int)land.lnd_type].l_flags & L_ASSAULT)) { pr("%s does not have \"assault\" capability and can't be tended\n", prland(&land)); continue; } if (!snxtitem(&targets, EF_SHIP, player->argp[4], "Ship to be tended? ")) return RET_FAIL; if (!check_ship_ok(tenderp) || !check_land_ok(&land)) return RET_SYN; while (nxtitem(&targets, &target)) { if (!player->owner && relations_with(target.shp_own, player->cnum) < FRIENDLY) continue; if (target.shp_uid == tenderp->shp_uid) continue; if (tenderp->shp_x != target.shp_x || tenderp->shp_y != target.shp_y) continue; /* Fit unit on ship */ getship(target.shp_uid, &target); if ((!(lchr[(int)land.lnd_type].l_flags & L_LIGHT)) && (!((mchr[(int)target.shp_type].m_flags & M_SUPPLY) && (!(mchr[(int)target.shp_type].m_flags & M_SUB))))) { pr("You can only load light units onto ships,\n" "unless the ship is a non-sub supply ship\n" "%s not tended\n", prland(&land)); continue; } if ((mchr[(int)target.shp_type].m_flags & M_SUB) && (lchr[(int)land.lnd_type].l_flags & L_SPY) && !mchr[(int)target.shp_type].m_nland) { if (shp_nland(&target) > 1) { pr("%s doesn't have room for more than two spy units!\n", prship(&target)); continue; } } else if (shp_nland(&target) >= mchr[target.shp_type].m_nland) { if (mchr[(int)target.shp_type].m_nland) pr("%s doesn't have room for any more land units!\n", prship(&target)); else pr("%s doesn't carry land units!\n", prship(&target)); continue; } pr("%s transferred from %s to %s\n", prland(&land), prship(tenderp), prship(&target)); sprintf(buf, "loaded on your %s at %s", prship(&target), xyas(target.shp_x, target.shp_y, target.shp_own)); gift(target.shp_own, player->cnum, &land, buf); land.lnd_ship = target.shp_uid; land.lnd_harden = 0; putland(land.lnd_uid, &land); expose_ship(tenderp, &target); putship(target.shp_uid, &target); putship(tenderp->shp_uid, tenderp); } } return 0; }
int orde(void) { int sub, level; int scuttling = 0; struct nstr_item nb; struct shpstr ship; struct ichrstr *i1; coord p0x, p0y, p1x, p1y; int i; char *p, *p1, *dest; char buf1[128]; char buf[1024]; char prompt[128]; if (!snxtitem(&nb, EF_SHIP, player->argp[1], NULL)) return RET_SYN; while (!player->aborted && nxtitem(&nb, (&ship))) { if (!player->owner || ship.shp_own == 0) continue; if (opt_SAIL) { if (*ship.shp_path) { pr("Ship #%d has a \"sail\" path!\n", ship.shp_uid); continue; } } sprintf(prompt, "Ship #%d, declare, cancel, suspend, resume, level? ", ship.shp_uid); p = getstarg(player->argp[2], prompt, buf); if (player->aborted || !p || !*p) return RET_FAIL; if (!check_ship_ok(&ship)) return RET_FAIL; switch (*p) { default: pr("Bad order type!\n"); return RET_SYN; case 'c': /* clear ship fields */ ship.shp_mission = 0; ship.shp_autonav &= ~(AN_AUTONAV + AN_STANDBY + AN_LOADING); for (i = 0; i < TMAX; i++) { ship.shp_tstart[i] = I_NONE; ship.shp_tend[i] = I_NONE; ship.shp_lstart[i] = 0; ship.shp_lend[i] = 0; } break; case 's': /* suspend ship movement */ ship.shp_mission = 0; ship.shp_autonav |= AN_STANDBY; break; case 'r': /* resume ship movement */ ship.shp_mission = 0; ship.shp_autonav &= ~AN_STANDBY; break; case 'd': /* declare path */ scuttling = 0; /* Need location */ p = getstarg(player->argp[3], "Destination? ", buf); if (!p || !*p) return RET_SYN; if (!sarg_xy(p, &p0x, &p0y)) return RET_SYN; p1x = p0x; p1y = p0y; p = getstarg(player->argp[4], "Second dest? ", buf); if (!p) return RET_FAIL; if (!check_ship_ok(&ship)) return RET_FAIL; if (!*p || !strcmp(p, "-")) { pr("A one-way order has been accepted.\n"); } else if (!strncmp(p, "s", 1)) { if (!(mchr[(int)ship.shp_type].m_flags & M_TRADE)) { pr("You can't auto-scuttle that ship!\n"); return RET_SYN; } pr("A scuttle order has been accepted.\n"); scuttling = 1; } else { if (!sarg_xy(p, &p1x, &p1y)) return RET_SYN; pr("A circular order has been accepted.\n"); } /* * Set new destination and trade type fields. */ ship.shp_mission = 0; ship.shp_destx[1] = p1x; ship.shp_desty[1] = p1y; ship.shp_destx[0] = p0x; ship.shp_desty[0] = p0y; ship.shp_autonav &= ~(AN_STANDBY | AN_LOADING); ship.shp_autonav |= AN_AUTONAV; if (scuttling) ship.shp_autonav |= AN_SCUTTLE; break; /* set cargo levels on the ship */ case 'l': /* convert player->argp[3] to an integer */ sprintf(buf1, "Field (1-%d) ", TMAX); if (!getstarg(player->argp[3], buf1, buf)) return RET_SYN; if (!check_ship_ok(&ship)) return RET_FAIL; sub = atoi(buf); /* check to make sure value in within range. */ if (sub > TMAX || sub < 1) { pr("Value must range from 1 to %d\n", TMAX); return RET_FAIL; } /* to keep sub in range of our arrays subtract 1 so the new range is 0-(TMAX-1) */ sub = sub - 1;; if (ship.shp_autonav & AN_AUTONAV) { dest = getstarg(player->argp[4], "Start or end? ", buf); if (!dest) return RET_FAIL; switch (*dest) { default: pr("You must enter 'start' or 'end'\n"); return RET_SYN; case 'e': case 'E': i1 = whatitem(player->argp[5], "Commodity? "); if (!i1) return RET_FAIL; p1 = getstarg(player->argp[6], "Amount? ", buf); if (!p1) return RET_SYN; if (!check_ship_ok(&ship)) return RET_FAIL; level = atoi(p1); if (level < 0) { level = 0; /* prevent negatives. */ pr("You must use positive number! Level set to 0.\n"); } ship.shp_tstart[sub] = i1->i_uid; ship.shp_lstart[sub] = level; pr("Order set\n"); break; case 's': case 'S': i1 = whatitem(player->argp[5], "Commodity? "); if (!i1) return RET_FAIL; p1 = getstarg(player->argp[6], "Amount? ", buf); if (!p1) return RET_SYN; if (!check_ship_ok(&ship)) return RET_FAIL; level = atoi(p1); if (level < 0) { level = 0; pr("You must use positive number! Level set to 0.\n"); } ship.shp_tend[sub] = i1->i_uid; ship.shp_lend[sub] = level; pr("Order Set \n"); break; } } else pr("You need to 'declare' a ship path first, see 'info order'\n"); break; } /* end of switch (*p) */ /* * Set loading flag if ship is already in one * of the specified harbors and a cargo has been * specified. */ if (((ship.shp_x == ship.shp_destx[0]) && (ship.shp_y == ship.shp_desty[0]) && (ship.shp_lstart[0] != ' ')) || ((ship.shp_x == ship.shp_desty[1]) && (ship.shp_y == ship.shp_desty[1]) && (ship.shp_lstart[1] != ' '))) { coord tcord; i_type tcomm; short lev[TMAX]; int i; ship.shp_autonav |= AN_LOADING; /* swap variables, this keeps the load_it() procedure happy. CZ */ tcord = ship.shp_destx[0]; ship.shp_destx[0] = ship.shp_destx[1]; ship.shp_destx[1] = tcord; tcord = ship.shp_desty[0]; ship.shp_desty[0] = ship.shp_desty[1]; ship.shp_desty[1] = tcord; for (i = 0; i < TMAX; i++) { lev[i] = ship.shp_lstart[i]; ship.shp_lstart[i] = ship.shp_lend[i]; ship.shp_lend[i] = lev[i]; tcomm = ship.shp_tstart[i]; ship.shp_tstart[i] = ship.shp_tend[i]; ship.shp_tend[i] = tcomm; } } putship(ship.shp_uid, &ship); } return RET_OK; }
int torp(void) { natid vshipown; int range; int dam; int subno; int victno; int erange; double hitchance; struct shpstr vship; struct shpstr sub; struct mchrstr *sub_mcp; char *ptr; struct nstr_item nbst; char buf[1024]; int ntorping = 0; char prompt[128]; if (!snxtitem(&nbst, EF_SHIP, player->argp[1], "From ship(s)? ")) return RET_SYN; while (nxtitem(&nbst, &sub)) { if (sub.shp_own != player->cnum) continue; if ((mchr[(int)sub.shp_type].m_flags & M_TORP) == 0) continue; if (sub.shp_item[I_GUN] == 0 || sub.shp_item[I_SHELL] < SHP_TORP_SHELLS) continue; if (sub.shp_item[I_MILIT] < 1) continue; if (sub.shp_effic < 60) continue; if (sub.shp_mobil <= 0) continue; ntorping++; } pr("%d ships are eligible to torpedo\n", ntorping); snxtitem_rewind(&nbst); while (nxtitem(&nbst, &sub)) { if (!sub.shp_own) continue; if (sub.shp_own != player->cnum) { continue; } sub_mcp = &mchr[sub.shp_type]; if (!(sub_mcp->m_flags & M_TORP)) { pr("Ship # %d: A %s can't fire torpedoes!\n", sub.shp_uid, sub_mcp->m_name); continue; } if (sub.shp_item[I_GUN] == 0 || sub.shp_item[I_SHELL] < SHP_TORP_SHELLS) { pr("Ship #%d has insufficient armament\n", sub.shp_uid); continue; } if (sub.shp_item[I_MILIT] < 1) { pr("Ship #%d has insufficient crew\n", sub.shp_uid); continue; } if (sub.shp_effic < 60) { pr("Ship #%d torpedo tubes inoperative.\n", sub.shp_uid); continue; } if (sub.shp_mobil <= 0) { pr("Ship #%d has insufficient mobility\n", sub.shp_uid); continue; } subno = sub.shp_uid; sprintf(prompt, "Ship %d, target? ", sub.shp_uid); if (!(ptr = getstarg(player->argp[2], prompt, buf))) return RET_SYN; if (!check_ship_ok(&sub)) return RET_FAIL; if ((victno = atoi(ptr)) < 0) return RET_SYN; if (!getship(victno, &vship)) return RET_FAIL; if (!vship.shp_own) return RET_FAIL; vshipown = vship.shp_own; if (victno == subno) { pr("Shooting yourself, eh? How strange...\n"); continue; } if (mchr[(int)vship.shp_type].m_flags & M_SUB) { if (!(sub_mcp->m_flags & M_SUBT)) { pr("You can't torpedo a submarine!\n"); continue; } } dam = shp_torp(&sub, 1); sub.shp_mission = 0; putship(sub.shp_uid, &sub); if (CANT_HAPPEN(dam < 0)) { pr("Ship #%d has insufficient armament\n", sub.shp_uid); continue; } if (!(sub_mcp->m_flags & M_SUB)) { pr("Starting our attack run...\n"); anti_torp(sub.shp_uid, ntorping, vshipown); } getship(sub.shp_uid, &sub); if (sub.shp_own == 0) continue; erange = roundrange(torprange(&sub)); pr("Effective torpedo range is %d.0\n", erange); pr("Whooosh... "); getship(victno, &vship); vshipown = vship.shp_own; range = mapdist(sub.shp_x, sub.shp_y, vship.shp_x, vship.shp_y); hitchance = shp_torp_hitchance(&sub, range); if (range <= erange) { pr("Hitchance = %.0f%%\n", hitchance * 100); } if (range > erange) pr("Out of range\n"); else if (!line_of_sight(NULL, sub.shp_x, sub.shp_y, vship.shp_x, vship.shp_y)) { pr("BOOM!... Torpedo slams into land before reaching target.\n"); /* We only tell the victim if we were within range. */ if (vshipown != 0 && vshipown != player->cnum) wu(0, vshipown, "Torpedo sighted @ %s by %s\n", xyas(sub.shp_x, sub.shp_y, vshipown), prship(&vship)); } else if (chance(hitchance)) { pr("BOOM!...\n"); if (vshipown != 0 && vshipown != player->cnum) wu(0, vshipown, "%s in %s torpedoed %s for %d damage.\n", sub_mcp->m_flags & M_SUB ? "sub" : prship(&sub), xyas(sub.shp_x, sub.shp_y, vshipown), prship(&vship), dam); pr("Torpedo hit %s for %d damage.\n", prsub(&vship), dam); if (!(mchr[vship.shp_type].m_flags & M_SUB)) { if (mchr[sub.shp_type].m_flags & M_SUB) nreport(vshipown, N_TORP_SHIP, 0, 1); else nreport(vshipown, N_SHIP_TORP, player->cnum, 1); } shipdamage(&vship, dam); if (vship.shp_effic < SHIP_MINEFF) pr("%s sunk!\n", prsub(&vship)); if (vship.shp_rflags & RET_TORPED) retreat_ship(&vship, vshipown, 't'); putship(vship.shp_uid, &vship); } else { pr("Missed\n"); if (vshipown != 0 && vshipown != player->cnum) wu(0, vshipown, "Torpedo sighted @ %s by %s\n", xyas(sub.shp_x, sub.shp_y, vshipown), prship(&vship)); } if (sub_mcp->m_flags & M_SUB) anti_torp(sub.shp_uid, ntorping, vshipown); } return RET_OK; }
int mobq(void) { struct shpstr ship; char *cp, *oldmq; int good, mobquota, count = 0; struct nstr_item nstr; char buf[1024]; if (!opt_SAIL) { pr("The SAIL option is not enabled, so this command is not valid.\n"); return RET_FAIL; } if (!snxtitem(&nstr, EF_SHIP, player->argp[1], NULL)) return RET_SYN; oldmq = player->argp[2]; if (oldmq) { good = sscanf(oldmq, "%d", &mobquota); if (!good) return RET_SYN; if (mobquota < 0 || mobquota > ship_mob_max) { pr("Bad mobility quota value %d.\n", mobquota); return RET_SYN; } if (mobquota + (ship_mob_scale * (float)etu_per_update) > ship_mob_max) { pr("warning: %d less than optimal\n", mobquota); } } while (nxtitem(&nstr, &ship)) { if (!player->owner) continue; if (!oldmq) pr("Ship #%d at %s. Old value %d.\n", ship.shp_uid, xyas(ship.shp_x, ship.shp_y, player->cnum), ship.shp_mobquota); cp = getstarg(player->argp[2], "mobility quota? ", buf); if (!cp) return RET_SYN; if (!check_ship_ok(&ship)) continue; good = sscanf(cp, "%d", &mobquota); if (!good) { pr("Huh?\n"); continue; } if (!oldmq) { if (mobquota < 0 || mobquota > ship_mob_max) { pr("Bad mobility quota value %d.\n", mobquota); continue; } if (mobquota + (ship_mob_scale * (float)etu_per_update) > ship_mob_max) { pr("warning: %d less than optimal\n", mobquota); } } ship.shp_mobquota = mobquota; count++; putship(ship.shp_uid, &ship); } if (count == 0) { if (player->argp[1]) pr("%s: No ship(s)\n", player->argp[1]); else pr("%s: No ship(s)\n", ""); return RET_FAIL; } else pr("%d ship%s\n", count, splur(count)); return RET_OK; }