/* * Give @unit and its cargo to @recipient. * No action if @recipient already owns @unit. * If @giver is non-zero, inform @recipient and @giver of the transaction. * Clears mission and group on the units given away. */ void unit_give_away(struct empobj *unit, natid recipient, natid giver) { int type; struct nstr_item ni; union empobj_storage cargo; if (unit->own == recipient) return; if (giver) { mpr(unit->own, "%s given to %s\n", unit_nameof(unit), cname(recipient)); mpr(recipient, "%s given to you by %s\n", unit_nameof(unit), cname(giver)); } unit->own = recipient; unit_wipe_orders(unit); 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)) unit_give_away(&cargo.gen, recipient, giver); } }
static void divine_load_unload(struct empobj *unit, int type, int uid, char *act) { if (uid < 0) return; pr("%s %s %s #%d\n", unit_nameof(unit), act, ef_nameof(type), uid); if (unit->own && unit->own != player->cnum) wu(0, unit->own, "%s %s %s #%d by an act of %s!\n", unit_nameof(unit), act, ef_nameof(type), uid, cname(player->cnum)); /* carrier owner could differ; can't be bothered to report to him */ }
int trade_has_unsalable_cargo(struct empobj *tgp, int noisy) { int ret, i, type; short *item; struct nstr_item ni; union empobj_storage cargo; ret = 0; if (tgp->ef_type == EF_SHIP || tgp->ef_type == EF_LAND) { item = tgp->ef_type == EF_SHIP ? ((struct shpstr *)tgp)->shp_item : ((struct lndstr *)tgp)->lnd_item; for (i = I_NONE + 1; i <= I_MAX; i++) { if (item[i] && !ichr[i].i_sell) { if (noisy) pr("%s carries %s, which you can't sell.\n", unit_nameof(tgp), ichr[i].i_name); ret = 1; } } } for (type = EF_PLANE; type <= EF_NUKE; type++) { snxtitem_cargo(&ni, type, tgp->ef_type, tgp->uid); while (nxtitem(&ni, &cargo)) ret |= trade_has_unsalable_cargo(&cargo.gen, noisy); } return ret; }
void gift(natid givee, natid giver, void *ptr, char *mesg) { if (giver != givee) wu(0, givee, "%s %s %s\n", cname(giver), unit_nameof(ptr), mesg); unit_give_away(ptr, givee, 0); }
/* * Drop cargo of @unit. * Give it to @newown, unless it's zero. */ void unit_drop_cargo(struct empobj *unit, natid newown) { int type; struct nstr_item ni; union empobj_storage cargo; for (type = EF_PLANE; type <= EF_NUKE; type++) { snxtitem_cargo(&ni, type, unit->ef_type, unit->uid); while (nxtitem(&ni, &cargo)) { switch (type) { case EF_PLANE: cargo.plane.pln_ship = cargo.plane.pln_land = -1; break; case EF_LAND: cargo.land.lnd_ship = cargo.land.lnd_land = -1; break; case EF_NUKE: cargo.nuke.nuk_plane = -1; break; } mpr(cargo.gen.own, "%s transferred off %s %d to %s\n", unit_nameof(&cargo.gen), ef_nameof(unit->ef_type), unit->uid, xyas(cargo.gen.x, cargo.gen.y, cargo.gen.own)); if (newown) unit_give_away(&cargo.gen, newown, cargo.gen.own); put_empobj(type, cargo.gen.uid, &cargo.gen); } } }
static void unit_view(struct emp_qelem *list) { struct sctstr sect; struct emp_qelem *qp; struct emp_qelem *next; struct ulist *ulp; for (qp = list->q_back; qp != list; qp = next) { next = qp->q_back; ulp = (struct ulist *)qp; if (CANT_HAPPEN(!(ef_flags(ulp->unit.gen.ef_type) & EFF_XY))) continue; getsect(ulp->unit.gen.x, ulp->unit.gen.y, §); if (ulp->unit.gen.ef_type == EF_SHIP) { if (mchr[ulp->unit.ship.shp_type].m_flags & M_FOOD) pr("[fert:%d] ", sect.sct_fertil); if (mchr[ulp->unit.ship.shp_type].m_flags & M_OIL) pr("[oil:%d] ", sect.sct_oil); } pr("%s @ %s %d%% %s\n", unit_nameof(&ulp->unit.gen), xyas(ulp->unit.gen.x, ulp->unit.gen.y, player->cnum), sect.sct_effic, dchr[sect.sct_type].d_name); } }
void divine_load(struct empobj *unit, int type, int uid) { union empobj_storage carrier; divine_load_unload(unit, type, uid, "loaded onto"); if (get_empobj(type, uid, &carrier) && (unit->x != carrier.gen.x || unit->y != carrier.gen.y)) { pr("%s teleported from %s to %s!", unit_nameof(unit), xyas(unit->x, unit->y, player->cnum), xyas(carrier.gen.x, carrier.gen.y, player->cnum)); unit_teleport(unit, carrier.gen.x, carrier.gen.y); } }
/* * Report deity meddling with @unit. * Just like divine_sct_change(), only for ships, planes, land units, * nukes. */ void divine_unit_change(struct empobj *unit, char *name, int change, int goodness, char *fmt, ...) { va_list ap; char buf[4096]; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if (!change) { pr("%s of %s unchanged\n", name, unit_nameof(unit)); return; } pr("%s of %s changed %s\n", name, unit_nameof(unit), buf); if (change > 0 && unit->own && unit->own != player->cnum) { wu(0, unit->own, "%s of %s changed %s by an act of %s\n", name, unit_nameof(unit), buf, cname(player->cnum)); nreport_divine_aid(unit->own, goodness); } }
/* * Update cargo of @carrier for movement or destruction. * If the carrier is destroyed, destroy its cargo (planes, land units, * nukes). * Else update their location to the carrier's. Any op sectors equal * to location get updated, too. * Return number of units updated. */ int unit_update_cargo(struct empobj *carrier) { int cargo_type; struct nstr_item ni; union empobj_storage obj; int n = 0; for (cargo_type = EF_PLANE; cargo_type <= EF_NUKE; cargo_type++) { snxtitem_cargo(&ni, cargo_type, carrier->ef_type, carrier->uid); while (nxtitem(&ni, &obj)) { if (carrier->own) unit_teleport(&obj.gen, carrier->x, carrier->y); else { mpr(obj.gen.own, "%s lost!\n", unit_nameof(&obj.gen)); obj.gen.effic = 0; } put_empobj(cargo_type, obj.gen.uid, &obj); n++; } } return n; }
int scra(void) { struct nstr_item ni; union empobj_storage item; int type, n; struct sctstr sect; struct mchrstr *mp; struct plchrstr *pp; struct lchrstr *lp; char *p; i_type i; char prompt[128]; char buf[1024]; float eff; short *mvec; int amt; if (!(p = getstarg(player->argp[1], "Ship, land, or plane? ", buf))) return RET_SYN; switch (*p) { case 's': type = EF_SHIP; break; case 'p': type = EF_PLANE; break; case 'l': type = EF_LAND; break; default: pr("Ships, land units, or planes only! (s, l, p)\n"); return RET_SYN; } if (!snxtitem(&ni, type, player->argp[2], NULL)) return RET_SYN; n = 0; while (nxtitem(&ni, &item)) { if (!player->owner) continue; n++; } snprintf(prompt, sizeof(prompt), "Really scrap %d %s%s [n]? ", n, ef_nameof(type), splur(n)); if (!confirm(prompt)) return RET_FAIL; snxtitem_rewind(&ni); while (nxtitem(&ni, &item)) { if (!player->owner) continue; if (opt_MARKET) { if (ontradingblock(type, &item.ship)) { pr("You cannot scrap an item on the trading block!\n"); continue; } } getsect(item.gen.x, item.gen.y, §); if (type == EF_SHIP) { if (!player->owner && relations_with(sect.sct_own, player->cnum) < FRIENDLY) { pr("%s is not in a friendly harbor!\n", prship(&item.ship)); continue; } if (sect.sct_type != SCT_HARBR || sect.sct_effic < 60) { pr("%s is not in a 60%% efficient harbor!\n", prship(&item.ship)); continue; } if (mchr[item.ship.shp_type].m_flags & M_TRADE) { pr("WARNING: You only collect money from trade ships if you \"scuttle\" them!\n"); sprintf(prompt, "Are you really sure that you want to scrap %s (n)? ", prship(&item.ship)); if (!confirm(prompt)) { pr("%s not scrapped\n", prship(&item.ship)); continue; } } } else { if (!player->owner && relations_with(sect.sct_own, player->cnum) != ALLIED) { pr("%s is not in an allied sector!\n", unit_nameof(&item.gen)); continue; } if (type == EF_PLANE && (sect.sct_type != SCT_AIRPT || sect.sct_effic < 60)) { pr("%s is not in a 60%% efficient airfield!\n", prplane(&item.plane)); continue; } } pr("%s scrapped in %s\n", unit_nameof(&item.gen), xyas(item.gen.x, item.gen.y, player->cnum)); unit_drop_cargo(&item.gen, sect.sct_own); if (type == EF_SHIP) { eff = item.ship.shp_effic / 100.0; mp = &mchr[(int)item.ship.shp_type]; for (i = I_NONE + 1; i <= I_MAX; i++) { if (load_comm_ok(§, item.ship.shp_own, i, -item.ship.shp_item[i])) sect.sct_item[i] += item.ship.shp_item[i]; } mvec = mp->m_mat; if (item.ship.shp_pstage == PLG_INFECT && sect.sct_pstage == PLG_HEALTHY) sect.sct_pstage = PLG_EXPOSED; } else if (type == EF_LAND) { eff = item.land.lnd_effic / 100.0; lp = &lchr[(int)item.land.lnd_type]; for (i = I_NONE + 1; i <= I_MAX; i++) { if (load_comm_ok(§, item.land.lnd_own, i, -item.land.lnd_item[i])) sect.sct_item[i] += item.land.lnd_item[i]; } mvec = lp->l_mat; if (item.land.lnd_pstage == PLG_INFECT && sect.sct_pstage == PLG_HEALTHY) sect.sct_pstage = PLG_EXPOSED; } else { eff = item.land.lnd_effic / 100.0; pp = &plchr[(int)item.plane.pln_type]; mvec = pp->pl_mat; } item.gen.effic = 0; put_empobj(type, item.gen.uid, &item.gen); for (i = I_NONE + 1; i <= I_MAX; i++) { if (i == I_CIVIL || i == I_MILIT || i == I_UW) amt = sect.sct_item[i] + mvec[i] * eff; else amt = sect.sct_item[i] + mvec[i] * 2 / 3 * eff; if (amt > ITEM_MAX) amt = ITEM_MAX; sect.sct_item[i] = amt; } putsect(§); } return RET_OK; }
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); } }