/* * format: skywatch [<SECTS>] */ int skyw(void) { struct sctstr sect; struct nstr_sect nstr; struct sky *skyp; struct sky *list[TSIZE]; int i, n; int vrange, see; int x, y, dx, dy, dxmax; int nsat = 0; double tech; struct nstr_item ni; if (!snxtsct(&nstr, player->argp[1])) return RET_SYN; for (i = 0; i < TSIZE; i++) list[i] = NULL; skyp = malloc(sizeof(*skyp)); snxtitem_all(&ni, EF_PLANE); while (nxtitem(&ni, &skyp->s_sat)) { if (!skyp->s_sat.pln_own) continue; if (!pln_is_in_orbit(&skyp->s_sat)) continue; getsect(skyp->s_sat.pln_x, skyp->s_sat.pln_y, §); n = scthash(skyp->s_sat.pln_x, skyp->s_sat.pln_y, TSIZE); skyp->s_spotted = 0; skyp->s_next = list[n]; list[n] = skyp; skyp = malloc(sizeof(*skyp)); nsat++; } /* get that last one! */ free(skyp); pr("- = [ Skywatch report for %s ] = -\n", cname(player->cnum)); pr(" Country Satellite Location\n"); tech = tfact(player->cnum, 1.0); while (nxtsct(&nstr, §) && nsat) { if (sect.sct_own != player->cnum) continue; see = sect.sct_type == SCT_RADAR ? 14 : 4; vrange = (int)(sect.sct_effic / 100.0 * see * tech); if (vrange < 1) vrange = 1; for (dy = -vrange; dy <= vrange; dy++) { y = ynorm(sect.sct_y + dy); dxmax = 2 * vrange - abs(dy); for (dx = -dxmax; dx <= dxmax; dx += 2) { x = xnorm(sect.sct_x + dx); n = scthash(x, y, TSIZE); if (!list[n]) continue; nsat -= showsat(&list[n], x, y); } } } /* free up the sky structs calloc'ed above */ for (i = 0; i < TSIZE; i++) { while (NULL != (skyp = list[i])) { list[i] = skyp->s_next; free(skyp); } } 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; }
/* * format: coastwatch [<SECTS>] */ int coas(void) { struct sctstr sect; struct nstr_sect nstr; struct coast *cp; struct coast *list[TSIZE]; int i, n; int vrange, see; int x, y, dx, dy, dxmax; int nship = 0; double tech; struct nstr_item ni; if (!snxtsct(&nstr, player->argp[1])) return RET_SYN; for (i = 0; i < TSIZE; i++) list[i] = NULL; cp = malloc(sizeof(*cp)); snxtitem_all(&ni, EF_SHIP); while (nxtitem(&ni, &cp->c_shp)) { if (cp->c_shp.shp_own == 0 || cp->c_shp.shp_own == player->cnum) continue; /* * don't bother putting subs in the table... * unless they're in a sector you own (harbor or such) */ getsect(cp->c_shp.shp_x, cp->c_shp.shp_y, §); if ((mchr[(int)cp->c_shp.shp_type].m_flags & M_SUB) && (sect.sct_own != player->cnum)) continue; n = scthash(cp->c_shp.shp_x, cp->c_shp.shp_y, TSIZE); cp->c_spotted = 0; cp->c_number = i; cp->c_next = list[n]; list[n] = cp; cp = malloc(sizeof(*cp)); nship++; } /* get that last one! */ free(cp); pr("- = [ Coastwatch report for %s ] = -\n", cname(player->cnum)); pr(" Country Ship Location\n"); tech = tfact(player->cnum, 1.0); while (nxtsct(&nstr, §) && nship) { if (sect.sct_own != player->cnum) continue; see = sect.sct_type == SCT_RADAR ? 14 : 4; vrange = (int)(sect.sct_effic / 100.0 * see * tech); if (vrange < 1) vrange = 1; for (dy = -vrange; dy <= vrange; dy++) { y = ynorm(sect.sct_y + dy); dxmax = 2 * vrange - abs(dy); for (dx = -dxmax; dx <= dxmax; dx += 2) { x = xnorm(sect.sct_x + dx); n = scthash(x, y, TSIZE); if (!list[n]) continue; nship -= showship(&list[n], x, y); } } } /* free up the coast structs calloc'ed above */ for (i = 0; i < TSIZE; i++) { while (NULL != (cp = list[i])) { list[i] = cp->c_next; free(cp); } } return RET_OK; }