static void meltitems(int etus, int fallout, int own, short *vec, int type, int x, int y, int uid) { i_type n; int melt; for (n = I_NONE + 1; n <= I_MAX; n++) { melt = roundavg(vec[n] * etus * (double)fallout / (1000.0 * ichr[n].i_melt_denom)); if (melt > vec[n]) melt = vec[n]; if (melt > 5 && own) { if (type == EF_SECTOR) wu(0, own, "Lost %d %s to radiation in %s.\n", melt, ichr[n].i_name, xyas(x, y, own)); else if (type == EF_LAND) wu(0, own, "Unit #%d lost %d %s to radiation in %s.\n", uid, melt, ichr[n].i_name, xyas(x, y, own)); else if (type == EF_SHIP) wu(0, own, "Ship #%d lost %d %s to radiation in %s.\n", uid, melt, ichr[n].i_name, xyas(x, y, own)); } vec[n] -= melt; } }
/* * Get build materials from sector @sp. * @bp is the sector's build pointer. * @mvec[] defines the materials needed to build 100%. * @pct is the percentage to build. * Adjust build percentage downwards so that available materials * suffice. Remove the materials. * Return adjusted build percentage. */ int get_materials(struct sctstr *sp, struct bp *bp, int *mvec, int pct) { int i, amt; for (i = I_NONE + 1; i <= I_MAX; i++) { if (mvec[i] == 0) continue; amt = bp_get_item(bp, sp, i); if (amt * 100 < mvec[i] * pct) pct = amt * 100 / mvec[i]; } for (i = I_NONE + 1; i <= I_MAX; i++) { if (mvec[i] == 0) continue; amt = bp_get_item(bp, sp, i); amt -= roundavg(mvec[i] * pct / 100.0); if (CANT_HAPPEN(amt < 0)) amt = 0; bp_put_item(bp, sp, i, amt); if (!player->simulation) sp->sct_item[i] = amt; } return pct; }
void decay_fallout(struct sctstr *sp, int etus) { int decay; if (etus > 24) etus = 24; decay = roundavg((decay_per_etu + 6.0) * fallout_spread * (double)etus * (double)sp->sct_fallout); sp->sct_fallout = decay < sp->sct_fallout ? sp->sct_fallout - decay : 0; }
void spread_fallout(struct sctstr *sp, int etus) { struct sctstr *ap; int n; int inc; if (etus > 24) etus = 24; for (n = DIR_FIRST; n <= DIR_LAST; n++) { ap = getsectp(sp->sct_x + diroff[n][0], sp->sct_y + diroff[n][1]); if (ap->sct_type == SCT_SANCT) continue; inc = roundavg(etus * fallout_spread * (sp->sct_fallout)) - 1; if (inc < 0) inc = 0; ap->sct_fallout = MIN(ap->sct_fallout + inc, FALLOUT_MAX); } }
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); }
static void planerepair(struct plnstr *pp, struct natstr *np, struct bp *bp, int etus) { int build; int mvec[I_MAX + 1]; struct shpstr *carrier; struct plchrstr *pcp = &plchr[(int)pp->pln_type]; struct sctstr *sp = getsectp(pp->pln_x, pp->pln_y); int delta; int mult; int avail; int w_p_eff; int used; carrier = NULL; if (pp->pln_ship >= 0) { if (pp->pln_effic >= 80) return; carrier = getshipp(pp->pln_ship); if (CANT_HAPPEN(!carrier)) return; if (carrier->shp_off) return; if (relations_with(carrier->shp_own, pp->pln_own) != ALLIED) return; } else { if (relations_with(sp->sct_own, pp->pln_own) != ALLIED) return; } if (sp->sct_off) return; mult = 1; if (np->nat_level[NAT_TLEV] < pp->pln_tech * 0.85) mult = 2; if (pp->pln_effic == 100) return; if (!player->simulation) avail = sp->sct_avail * 100; else avail = bp_get_avail(bp, sp) * 100; if (carrier) avail += etus * carrier->shp_item[I_MILIT] / 2; w_p_eff = PLN_BLD_WORK(pcp->pl_lcm, pcp->pl_hcm); delta = roundavg((double)avail / w_p_eff); if (delta <= 0) return; if (delta > (int)((float)etus * plane_grow_scale)) delta = (int)((float)etus * plane_grow_scale); if (delta > 100 - pp->pln_effic) delta = 100 - pp->pln_effic; memset(mvec, 0, sizeof(mvec)); mvec[I_MILIT] = pcp->pl_crew; mvec[I_LCM] = pcp->pl_lcm; mvec[I_HCM] = pcp->pl_hcm; build = get_materials(sp, bp, mvec, delta); if (carrier) build = delta; used = build * w_p_eff; /* * I didn't use roundavg here, because I want to * penalize the player with a large number of planes. */ if (!player->simulation) avail = (sp->sct_avail * 100 - used) / 100; else avail = (bp_get_avail(bp, sp) * 100 - used) / 100; if (avail < 0) avail = 0; if (!player->simulation) sp->sct_avail = avail; else bp_put_avail(bp, sp, avail); if (sp->sct_type != SCT_AIRPT) build /= 3; if (carrier) { if ((pp->pln_effic + build) > 80) build = 80 - pp->pln_effic; } np->nat_money -= mult * build * pcp->pl_cost / 100.0; if (!player->simulation) pp->pln_effic += (signed char)build; }
int work(void) { int nunits; struct nstr_item ni; struct sctstr sect; struct lndstr land; int work_amt, eff_amt, w; char *p; char buf[1024]; double cost; struct natstr *natp = getnatp(player->cnum); if (!snxtitem(&ni, EF_LAND, player->argp[1], NULL)) return RET_SYN; p = getstarg(player->argp[2], "Amount: ", buf); if (!p || !*p) return RET_SYN; work_amt = atoi(p); if ((work_amt < 0) || (work_amt > land_mob_max)) { pr("Mobility used must be from 0 to %d\n", land_mob_max); return RET_FAIL; } nunits = 0; while (nxtitem(&ni, &land)) { if (!player->owner || land.lnd_own == 0) continue; if (!(lchr[(int)land.lnd_type].l_flags & L_ENGINEER)) continue; if (land.lnd_mobil <= 0) { pr("%s has no mobility!\n", prland(&land)); continue; } getsect(land.lnd_x, land.lnd_y, §); if (sect.sct_effic >= 100 && sect.sct_type == sect.sct_newtype) { pr("Nothing to do for %s in %s\n", prland(&land), xyas(sect.sct_x, sect.sct_y, player->cnum)); continue; } eff_amt = MIN(land.lnd_mobil, work_amt); w = (eff_amt * land.lnd_effic) / 600; if (w < 1) { pr("%s doesn't work enough to change efficiency (try increasing amount)\n", prland(&land)); continue; } cost = 0.0; w = buildeff(§, w, &cost); if (w == 0) { pr("%s can't change efficiency in %s\n", prland(&land), xyas(land.lnd_x, land.lnd_y, player->cnum)); continue; } if (player->dolcost + cost > natp->nat_money) { pr("You can't afford to work that much in %s!\n", xyas(land.lnd_x, land.lnd_y, player->cnum)); break; } player->dolcost += cost; land.lnd_mission = 0; land.lnd_mobil -= roundavg(w * 600.0 / land.lnd_effic); nunits++; pr("%s %s efficiency at %s to %d\n", prland(&land), sect.sct_type == sect.sct_newtype ? "raised" : "lowered", xyas(land.lnd_x, land.lnd_y, player->cnum), sect.sct_effic); putland(land.lnd_uid, &land); putsect(§); } if (nunits == 0) { if (player->argp[1]) pr("%s: No unit(s)\n", player->argp[1]); else pr("%s: No unit(s)\n", ""); return RET_FAIL; } else pr("%d unit%s\n", nunits, splur(nunits)); return RET_OK; }
void plane_sona(struct emp_qelem *plane_list, int x, int y, struct shiplist **head) { struct plnstr *pp; struct plchrstr *pcp; struct mchrstr *tmcp; struct shpstr *targ, s; struct natstr *natp; struct emp_qelem *qp; struct emp_qelem *next; struct plist *ip; struct sctstr sect; int found = 0; int range, i, vis; int pingrange; int vrange; int dist; getsect(x, y, §); if ((sect.sct_type != SCT_WATER) && (sect.sct_type != SCT_HARBR)) return; for (qp = plane_list->q_forw; qp != plane_list; qp = next) { next = qp->q_forw; ip = (struct plist *)qp; pp = &ip->plane; pcp = ip->pcp; if (!(pcp->pl_flags & P_A)) /* if it isn't an ASW plane */ continue; range = (int)techfact(pp->pln_tech, (100.0 - pln_acc(pp)) / 10.0); for (i = 0; getship(i, &s); i++) { targ = &s; if (targ->shp_own == pp->pln_own || targ->shp_own == 0) continue; if (on_shiplist(targ->shp_uid, *head)) continue; tmcp = &mchr[(int)targ->shp_type]; if (!(tmcp->m_flags & M_SUB)) continue; if (!pct_chance(pln_identchance(pp, shp_hardtarget(targ), EF_SHIP))) continue; vis = shp_visib(targ); pingrange = MAX(vis, 10) * range / 10; vrange = pingrange * (pp->pln_effic / 200.0); dist = mapdist(targ->shp_x, targ->shp_y, x, y); pingrange = (MAX(pingrange, 2) * targ->shp_effic); pingrange = roundavg(pingrange / 100.0); if (dist > pingrange) continue; if (tmcp->m_flags & M_SONAR && targ->shp_own) { natp = getnatp(targ->shp_own); if (natp->nat_flags & NF_SONAR) wu(0, targ->shp_own, "Sonar ping from %s detected by %s!\n", xyas(x, y, targ->shp_own), prship(targ)); } if ((dist > vrange)) continue; add_shiplist(targ->shp_uid, head); if (!found) { pr("Sonar contact in %s\n", xyas(x, y, player->cnum)); found = 1; } if (relations_with(targ->shp_own, pp->pln_own) < FRIENDLY && !pct_chance(pln_identchance(pp, shp_hardtarget(targ), EF_SHIP))) if (!pct_chance(pln_identchance(pp, shp_hardtarget(targ), EF_SHIP))) pr("sub #%d %s\n", targ->shp_uid, xyas(targ->shp_x, targ->shp_y, player->cnum)); else pr("%s %s\n", prship(targ), xyas(targ->shp_x, targ->shp_y, player->cnum)); else pr("%s %s @ %s\n", cname(targ->shp_own), prship(targ), xyas(targ->shp_x, targ->shp_y, player->cnum)); } } if (found) pr("\n"); }
/* * Increase sector efficiency if old type == new type. * decrease sector efficiency if old type != new type. * Return amount of work used. */ static int upd_buildeff(struct natstr *np, struct sctstr *sp, int *workp, short *vec, int etu, int *desig, int sctwork, int *cost) { int work_cost = 0; int buildeff_work = *workp / 2; int n, hcms, lcms, neweff; unsigned char old_type = *desig; *cost = 0; neweff = sp->sct_effic; if (*desig != sp->sct_newtype) { /* * Tear down existing sector. * Easier to destroy than to build. */ work_cost = (sp->sct_effic + 3) / 4; if (work_cost > buildeff_work) work_cost = buildeff_work; buildeff_work -= work_cost; n = sp->sct_effic - work_cost * 4; if (n <= 0) { n = 0; *desig = sp->sct_newtype; } neweff = n; *cost += work_cost; if (!n && IS_BIG_CITY(old_type) && !IS_BIG_CITY(*desig)) { // FIXME use trunc_people() and total_work() int maxpop = max_population(np->nat_level[NAT_RLEV], *desig, n); if (vec[I_CIVIL] > maxpop) vec[I_CIVIL] = maxpop; if (vec[I_UW] > maxpop) vec[I_UW] = maxpop; *workp = (vec[I_CIVIL] * sctwork) / 100.0 + (vec[I_MILIT] * 2 / 5.0) + vec[I_UW]; *workp = roundavg((etu * *workp) / 100.0); buildeff_work = MIN((int)(*workp / 2), buildeff_work); } } if (*desig == sp->sct_newtype) { work_cost = 100 - neweff; if (work_cost > buildeff_work) work_cost = buildeff_work; if (dchr[*desig].d_lcms > 0) { lcms = vec[I_LCM]; lcms /= dchr[*desig].d_lcms; if (work_cost > lcms) work_cost = lcms; } if (dchr[*desig].d_hcms > 0) { hcms = vec[I_HCM]; hcms /= dchr[*desig].d_hcms; if (work_cost > hcms) work_cost = hcms; } neweff += work_cost; *cost += work_cost * dchr[*desig].d_build; buildeff_work -= work_cost; if ((dchr[*desig].d_lcms > 0) || (dchr[*desig].d_hcms > 0)) { vec[I_LCM] -= work_cost * dchr[*desig].d_lcms; vec[I_HCM] -= work_cost * dchr[*desig].d_hcms; } } *workp = (*workp + 1) / 2 + buildeff_work; return neweff; }
int check_trade(void) { int n; struct natstr *natp; struct trdstr trade; union empobj_storage tg; time_t now; int price; int saveid; natid seller; for (n = 0; gettrade(n, &trade); n++) { if (trade.trd_unitid < 0) continue; if (!trade_getitem(&trade, &tg)) continue; if (tg.gen.own == 0) { trade.trd_owner = 0; trade.trd_unitid = -1; puttrade(n, &trade); continue; } if (tg.gen.own != trade.trd_owner) { logerror("Something weird, tg.gen.own != trade.trd_owner!\n"); trade.trd_owner = 0; trade.trd_unitid = -1; puttrade(n, &trade); continue; } if (trade.trd_owner == trade.trd_maxbidder) continue; (void)time(&now); if (trade.trd_markettime + TRADE_DELAY > now) continue; saveid = trade.trd_unitid; seller = trade.trd_owner; trade.trd_owner = 0; trade.trd_unitid = -1; if (!puttrade(n, &trade)) { logerror("Couldn't save trade after purchase; get help!\n"); continue; } price = trade.trd_price; natp = getnatp(trade.trd_maxbidder); if (natp->nat_money < price) { nreport(trade.trd_maxbidder, N_WELCH_DEAL, seller, 1); wu(0, seller, "%s tried to buy a %s #%d from you for $%.2f\n", cname(trade.trd_maxbidder), trade_nameof(&trade, &tg.gen), saveid, price * tradetax); wu(0, seller, " but couldn't afford it.\n"); wu(0, seller, " Your item was taken off the market.\n"); wu(0, trade.trd_maxbidder, "You tried to buy %s #%d from %s for $%d\n", trade_nameof(&trade, &tg.gen), saveid, cname(seller), price); wu(0, trade.trd_maxbidder, "but couldn't afford it.\n"); continue; } /* If we get this far, the sale will go through. */ natp->nat_money -= price; putnat(natp); natp = getnatp(seller); natp->nat_money += roundavg(price * tradetax); putnat(natp); switch (trade.trd_type) { case EF_NUKE: tg.nuke.nuk_x = trade.trd_x; tg.nuke.nuk_y = trade.trd_y; tg.nuke.nuk_plane = -1; break; case EF_PLANE: if (!pln_is_in_orbit(&tg.plane)) { tg.plane.pln_x = trade.trd_x; tg.plane.pln_y = trade.trd_y; } if (opt_MOB_ACCESS) { tg.plane.pln_mobil = -(etu_per_update / sect_mob_neg_factor); game_tick_to_now(&tg.plane.pln_access); } else { tg.plane.pln_mobil = 0; } tg.plane.pln_harden = 0; tg.plane.pln_ship = -1; tg.plane.pln_land = -1; break; case EF_SHIP: break; case EF_LAND: tg.land.lnd_x = trade.trd_x; tg.land.lnd_y = trade.trd_y; if (opt_MOB_ACCESS) { tg.land.lnd_mobil = -(etu_per_update / sect_mob_neg_factor); game_tick_to_now(&tg.land.lnd_access); } else { tg.land.lnd_mobil = 0; } tg.land.lnd_harden = 0; unit_drop_cargo(&tg.gen, 0); tg.land.lnd_ship = -1; tg.land.lnd_land = -1; break; default: logerror("Bad trade type %d in trade\n", trade.trd_type); break; } unit_give_away(&tg.gen, trade.trd_maxbidder, 0); put_empobj(trade.trd_type, saveid, &tg.gen); nreport(seller, N_MAKE_SALE, trade.trd_maxbidder, 1); wu(0, seller, "%s bought %s #%d from you for $%.2f\n", cname(trade.trd_maxbidder), trade_nameof(&trade, &tg.gen), saveid, price * tradetax); wu(0, trade.trd_maxbidder, "The bidding is over & you bought %s #%d from %s for $%d\n", trade_nameof(&trade, &tg.gen), saveid, cname(seller), price); } return RET_OK; }
int enli(void) { struct nstr_sect nstr; struct sctstr sect; struct natstr *natp; int civ; int mil; int newmil; int milwant; int totalmil; int reserve; char *p; int quota; char prompt[128]; char buf[1024]; if (!snxtsct(&nstr, player->argp[1])) return RET_SYN; natp = getnatp(player->cnum); newmil = 500; sprintf(prompt, "Number to enlist (max %d) : ", newmil); if (!(p = getstarg(player->argp[2], prompt, buf))) return RET_SYN; if ((milwant = atoi(p)) > newmil) milwant = newmil; if (0 != (quota = (milwant < 0))) milwant = -milwant; totalmil = 0; reserve = natp->nat_reserve; if (reserve <= 0) { pr("No military reserves left\n"); return RET_OK; } while (nxtsct(&nstr, §)) { if (!player->owner) continue; if (sect.sct_oldown != player->cnum) continue; civ = sect.sct_item[I_CIVIL]; if (civ == 0) continue; if (sect.sct_loyal > 70) { pr("civilians refuse to report in %s!\n", xyas(sect.sct_x, sect.sct_y, player->cnum)); continue; } if (sect.sct_mobil <= 0) { pr("%s is out of mobility!\n", xyas(sect.sct_x, sect.sct_y, player->cnum)); } mil = sect.sct_item[I_MILIT]; newmil = civ * 0.5; if (quota) { if (newmil > milwant - mil) newmil = milwant - mil; if (newmil > 500) newmil = 500; } else if (newmil > milwant) newmil = milwant; if (newmil > 999 - mil) newmil = 999 - mil; if (newmil <= 0) continue; if (newmil > reserve) newmil = reserve; sect.sct_item[I_MILIT] = newmil + mil; reserve -= newmil; totalmil += newmil; sect.sct_item[I_CIVIL] = civ - newmil; pr("%3d enlisted in %s (%d)\n", newmil, xyas(sect.sct_x, sect.sct_y, player->cnum), mil + newmil); if (sect.sct_mobil > 0) sect.sct_mobil *= 1.0 - (double)newmil / (double)civ; putsect(§); if (totalmil >= 10000) { pr("Rioting in induction center interrupts enlistment\n"); break; } if (reserve == 0) { pr("Military reserve exhausted\n"); break; } } pr("Total new enlistment : %d\n", totalmil); pr("Military reserves stand at %d\n", reserve); if (totalmil) { natp->nat_reserve -= totalmil; putnat(natp); } if ((player->btused += roundavg(totalmil * 0.02)) > 0) pr("Paperwork at recruiting stations ... %d\n", player->btused); return RET_OK; }
/* * Actually get the commod * * First, try to forage in the sector * Second look for a warehouse or headquarters to leech * Third, look for a ship we own in a harbor * Fourth, look for supplies in a supply unit we own * (one good reason to do this last is that the supply * unit will then call resupply, taking more time) * * May want to put code to resupply with SAMs here, later --ts */ static int s_commod(struct empobj *sink, short *vec, i_type type, int wanted, int limit, int actually_doit) { natid own = sink->own; coord x = sink->x; coord y = sink->y; int lookrange; struct sctstr sect; struct nstr_sect ns; struct nstr_item ni; struct lchrstr *lcp; struct shpstr ship; struct lndstr land; /* leave at least 1 military in sectors/ships */ int minimum = 0; int can_move; double move_cost, weight, mobcost; int packing; struct dchrstr *dp; struct ichrstr *ip; if (wanted > limit) wanted = limit; if (wanted <= vec[type]) return 1; wanted -= vec[type]; /* try to get it from sector we're in */ if (sink->ef_type != EF_SECTOR) { getsect(x, y, §); if (sect.sct_own == own) { if (!opt_NOFOOD && type == I_FOOD) minimum = 1 + (int)ceil(food_needed(sect.sct_item, etu_per_update)); if (sect.sct_item[type] - wanted >= minimum) { sect.sct_item[type] -= wanted; if (actually_doit) { vec[type] += wanted; putsect(§); put_empobj(sink->ef_type, sink->uid, sink); } return 1; } else if (sect.sct_item[type] - minimum > 0) { wanted -= sect.sct_item[type] - minimum; sect.sct_item[type] = minimum; if (actually_doit) { vec[type] += sect.sct_item[type] - minimum; putsect(§); } } } } /* look for a headquarters or warehouse */ lookrange = tfact(own, 10.0); snxtsct_dist(&ns, x, y, lookrange); while (nxtsct(&ns, §) && wanted) { if (ns.curdist == 0) continue; if (sect.sct_own != own) continue; if ((sect.sct_type != SCT_WAREH) && (sect.sct_type != SCT_HEADQ) && (sect.sct_type != SCT_HARBR)) continue; if ((sect.sct_type == SCT_HEADQ) && (sect.sct_dist_x == sect.sct_x) && (sect.sct_dist_y == sect.sct_y)) continue; if (sect.sct_effic < 60) continue; move_cost = path_find(sect.sct_x, sect.sct_y, x, y, own, MOB_MOVE); if (move_cost < 0) continue; if (!opt_NOFOOD && type == I_FOOD) minimum = 1 + (int)ceil(food_needed(sect.sct_item, etu_per_update)); if (sect.sct_item[type] <= minimum) continue; ip = &ichr[type]; dp = &dchr[sect.sct_type]; packing = ip->i_pkg[dp->d_pkg]; if (packing > 1 && sect.sct_effic < 60) packing = 1; weight = (double)ip->i_lbs / packing; mobcost = move_cost * weight; if (mobcost > 0) can_move = (double)sect.sct_mobil / mobcost; else can_move = sect.sct_item[type] - minimum; if (can_move > sect.sct_item[type] - minimum) can_move = sect.sct_item[type] - minimum; if (can_move >= wanted) { int n; sect.sct_item[type] -= wanted; /* take off mobility for delivering sect */ n = roundavg(wanted * weight * move_cost); sect.sct_mobil -= LIMIT_TO(n, 0, sect.sct_mobil); if (actually_doit) { vec[type] += wanted; putsect(§); put_empobj(sink->ef_type, sink->uid, sink); } return 1; } else if (can_move > 0) { int n; wanted -= can_move; sect.sct_item[type] -= can_move; /* take off mobility for delivering sect */ n = roundavg(can_move * weight * move_cost); sect.sct_mobil -= LIMIT_TO(n, 0, sect.sct_mobil); if (actually_doit) { vec[type] += can_move; putsect(§); } } } /* look for an owned ship in a harbor */ snxtitem_dist(&ni, EF_SHIP, x, y, lookrange); while (nxtitem(&ni, &ship) && wanted) { if (sink->ef_type == EF_SHIP && sink->uid == ship.shp_uid) continue; if (ship.shp_own != own) continue; if (!(mchr[(int)ship.shp_type].m_flags & M_SUPPLY)) continue; getsect(ship.shp_x, ship.shp_y, §); if (sect.sct_type != SCT_HARBR) continue; if (sect.sct_effic < 2) continue; move_cost = path_find(sect.sct_x, sect.sct_y, x, y, own, MOB_MOVE); if (move_cost < 0) continue; if (!opt_NOFOOD && type == I_FOOD) minimum = 1 + (int)ceil(food_needed(ship.shp_item, etu_per_update)); if (ship.shp_item[type] <= minimum) continue; ip = &ichr[type]; dp = &dchr[sect.sct_type]; packing = ip->i_pkg[dp->d_pkg]; if (packing > 1 && sect.sct_effic < 60) packing = 1; weight = (double)ip->i_lbs / packing; mobcost = move_cost * weight; if (mobcost > 0) can_move = (double)sect.sct_mobil / mobcost; else can_move = ship.shp_item[type] - minimum; if (can_move > ship.shp_item[type] - minimum) can_move = ship.shp_item[type] - minimum; if (can_move >= wanted) { int n; ship.shp_item[type] -= wanted; n = roundavg(wanted * weight * move_cost); sect.sct_mobil -= LIMIT_TO(n, 0, sect.sct_mobil); if (actually_doit) { vec[type] += can_move; putship(ship.shp_uid, &ship); if (n) putsect(§); put_empobj(sink->ef_type, sink->uid, sink); } return 1; } else if (can_move > 0) { int n; wanted -= can_move; ship.shp_item[type] -= can_move; n = roundavg(can_move * weight * move_cost); sect.sct_mobil -= LIMIT_TO(n, 0, sect.sct_mobil); if (actually_doit) { vec[type] += can_move; putship(ship.shp_uid, &ship); if (n) putsect(§); } } } /* look for an owned supply unit */ snxtitem_dist(&ni, EF_LAND, x, y, lookrange); while (nxtitem(&ni, &land) && wanted) { int min; if (sink->ef_type == EF_LAND && sink->uid == land.lnd_uid) continue; if (land.lnd_own != own) continue; lcp = &lchr[(int)land.lnd_type]; if (!(lcp->l_flags & L_SUPPLY)) continue; if (land.lnd_item[type] <= get_minimum(&land, type)) continue; if (land.lnd_ship >= 0) { getsect(land.lnd_x, land.lnd_y, §); if (sect.sct_type != SCT_HARBR || sect.sct_effic < 2) continue; } move_cost = path_find(land.lnd_x, land.lnd_y, x, y, own, MOB_MOVE); if (move_cost < 0) continue; #if 0 /* * Recursive supply is disabled for now. It can introduce * cycles into the "resupplies from" relation. The code below * attempts to break these cycles by temporarily zapping the * commodity being supplied. That puts the land file in a * funny state temporarily, risking loss of supplies when * something goes wrong on the way. Worse, it increases * lnd_seqno even when !actually_doit, which can lead to * spurious seqno mismatch oopses in users of * lnd_could_be_supplied(). I can't be bothered to clean up * this mess right now, because recursive resupply is too dumb * to be really useful anyway: each step uses the first source * it finds, without consideration of mobility cost. If you * re-enable it, don't forget to uncomment its documentation * in supply.t as well. */ if (land.lnd_item[type] - wanted < get_minimum(&land, type)) { struct lndstr save; /* * Temporarily zap this unit's store, so the recursion * avoids it. */ save = land; land.lnd_item[type] = 0; putland(land.lnd_uid, &land); save.lnd_seqno = land.lnd_seqno; s_commod((struct empobj *)&land, land.lnd_item, type, wanted, lchr[land.lnd_type].l_item[type] - wanted, actually_doit); land.lnd_item[type] += save.lnd_item[type]; if (actually_doit) putland(land.lnd_uid, &land); else putland(save.lnd_uid, &save); } #endif min = get_minimum(&land, type); ip = &ichr[type]; weight = ip->i_lbs; mobcost = move_cost * weight; if (mobcost > 0) can_move = (double)land.lnd_mobil / mobcost; else can_move = land.lnd_item[type] - min; if (can_move > land.lnd_item[type] - min) can_move = land.lnd_item[type] - min; if (can_move >= wanted) { land.lnd_item[type] -= wanted; land.lnd_mobil -= roundavg(wanted * weight * move_cost); if (actually_doit) { vec[type] += wanted; putland(land.lnd_uid, &land); put_empobj(sink->ef_type, sink->uid, sink); } return 1; } else if (can_move > 0) { wanted -= can_move; land.lnd_item[type] -= can_move; land.lnd_mobil -= roundavg(can_move * weight * move_cost); if (actually_doit) { vec[type] += can_move; putland(land.lnd_uid, &land); } } } if (actually_doit) put_empobj(sink->ef_type, sink->uid, sink); return 0; }
int produce(struct natstr *np, struct sctstr *sp, short *vec, int work, int desig, int neweff, int *cost, int *amount) { struct pchrstr *product; double p_e; double prodeff; unsigned char *resource; double output; int actual; int unit_work, work_used; i_type item; double worker_limit; int material_limit, res_limit; int material_consume; int val; if (dchr[desig].d_prd < 0) return 0; product = &pchr[dchr[desig].d_prd]; item = product->p_type; if (product->p_nrndx) resource = (unsigned char *)sp + product->p_nrndx; else resource = NULL; *amount = 0; *cost = 0; material_limit = prod_materials_cost(product, vec, &unit_work); if (material_limit <= 0) return 0; /* sector p.e. */ p_e = neweff / 100.0; if (resource) { unit_work++; p_e *= *resource / 100.0; } if (unit_work == 0) unit_work = 1; worker_limit = work * p_e / unit_work; res_limit = prod_resource_limit(product, resource); material_consume = res_limit; if (material_consume > worker_limit) material_consume = (int)worker_limit; if (material_consume > material_limit) material_consume = material_limit; if (material_consume == 0) return 0; prodeff = prod_eff(desig, np->nat_level[product->p_nlndx]); if (prodeff <= 0.0 && !player->simulation) { wu(0, sp->sct_own, "%s level too low to produce in %s (need %d)\n", levelnames[product->p_nlndx], ownxy(sp), product->p_nlmin); return 0; } /* * Adjust produced amount by commodity production ratio */ output = material_consume * prodeff; if (item == I_NONE) { actual = ldround(output, 1); if (!player->simulation) { levels[sp->sct_own][product->p_level] += output; wu(0, sp->sct_own, "%s (%.2f) produced in %s\n", product->p_name, output, ownxy(sp)); } } else { actual = roundavg(output); if (actual <= 0) return 0; if (actual > 999) { actual = 999; material_consume = roundavg(actual / prodeff); } if (vec[item] + actual > ITEM_MAX) { actual = ITEM_MAX - vec[item]; material_consume = roundavg(actual / prodeff); if (material_consume < 0) material_consume = 0; if (sp->sct_own && !player->simulation) wu(0, sp->sct_own, "%s production backlog in %s\n", product->p_name, ownxy(sp)); } vec[item] += actual; } /* * Reset produced amount by commodity production ratio */ if (!player->simulation) { materials_charge(product, vec, material_consume); if (resource && product->p_nrdep != 0) { /* * lower natural resource in sector depending on * amount produced */ val = *resource - roundavg(product->p_nrdep * material_consume / 100.0); if (val < 0) val = 0; *resource = val; } } *amount = actual; *cost = product->p_cost * material_consume; if (opt_TECH_POP) { if (product->p_level == NAT_TLEV) { if (tpops[sp->sct_own] > 50000) *cost *= tpops[sp->sct_own] / 50000.0; } } if (CANT_HAPPEN(p_e <= 0.0)) return 0; work_used = roundavg(unit_work * material_consume / p_e); if (CANT_HAPPEN(work_used > work)) return work; return work_used; }
int check_market(void) { struct comstr comm; struct sctstr *sect; struct natstr *natp; int m; int n; time_t now; double gain; double price; for (n = 0; getcomm(n, &comm); n++) { if (comm.com_maxbidder == comm.com_owner || comm.com_owner == 0) continue; (void)time(&now); if (comm.com_markettime + MARK_DELAY > now) continue; if (CANT_HAPPEN(comm.com_type <= I_NONE || comm.com_type > I_MAX)) continue; sect = getsectp(comm.com_x, comm.com_y); m = sect->sct_item[comm.com_type]; price = comm.com_price * comm.com_amount * buytax; gain = comm.com_price * comm.com_amount; natp = getnatp(comm.com_maxbidder); if (natp->nat_money < price) { nreport(comm.com_maxbidder, N_WELCH_DEAL, comm.com_owner, 1); wu(0, comm.com_maxbidder, "You didn't have enough cash to cover the cost.\n"); wu(0, comm.com_owner, "Sale #%d fell through. Goods remain on the market.\n", n); comm.com_maxbidder = comm.com_owner; } else if (sect->sct_type != SCT_WAREH && sect->sct_type != SCT_HARBR) { wu(0, comm.com_maxbidder, "Sector not a warehouse now, sale #%d fell though.\n", n); wu(0, comm.com_owner, "Sale #%d fell through. Goods remain on the market.\n", n); comm.com_maxbidder = comm.com_owner; } else if (m + comm.com_amount > ITEM_MAX) { wu(0, comm.com_maxbidder, "Warehouse full, sale #%d fell though.\n", n); wu(0, comm.com_owner, "Sale #%d fell through. Goods remain on the market.\n", n); comm.com_maxbidder = comm.com_owner; } else { sect->sct_item[comm.com_type] = m + comm.com_amount; putsect(sect); nreport(comm.com_owner, N_MAKE_SALE, comm.com_maxbidder, 1); wu(0, comm.com_owner, "%s bought %d %s from you for $%.2f\n", cname(comm.com_maxbidder), comm.com_amount, ichr[comm.com_type].i_name, gain); wu(0, comm.com_maxbidder, "You just bought %d %s from %s for $%.2f\n", comm.com_amount, ichr[comm.com_type].i_name, cname(comm.com_owner), price); natp->nat_money -= roundavg(price); putnat(natp); natp = getnatp(comm.com_owner); natp->nat_money += roundavg(gain); putnat(natp); comm.com_owner = 0; } comm.com_owner = 0; putcomm(n, &comm); } return RET_OK; }