static int move_amount(int sect_amt, int unit_amt, int unit_max, int load_unload, int amount) { int move_amt; if (amount < 0) move_amt = -amount - unit_amt; else move_amt = load_unload == LOAD ? amount : -amount; move_amt = LIMIT_TO(move_amt, -unit_amt, unit_max - unit_amt); move_amt = LIMIT_TO(move_amt, sect_amt - ITEM_MAX, sect_amt); return move_amt; }
/* * 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; }
static void parse_args(int argc, char *argv[]) { if (argc < 2) { help("missing arguments"); exit(1); } if (argc > 8) { help("too many arguments"); exit(1); } nc = atoi(argv[0]); if (nc < 1) { puts("fairland: error -- number of continents must be > 0"); exit(1); } sc = atoi(argv[1]); if (sc < 1) { puts("fairland: error -- size of continents must be > 0"); exit(1); } if (argc > 2) ni = atoi(argv[2]); else ni = nc; if (argc > 3) is = atoi(argv[3]); else is = sc / 2; if (is < 1) is = 1; if (argc > 4) sp = atoi(argv[4]); else sp = DEFAULT_SPIKE; sp = LIMIT_TO(sp, 0, 100); if (argc > 5) pm = atoi(argv[5]); else pm = DEFAULT_MOUNTAIN; if (pm < 0) pm = 0; if (argc > 6) di = atoi(argv[6]); else di = DEFAULT_CONTDIST; if (di < 0) { puts("fairland: error -- distance between continents must be >= 0"); exit(1); } if (di > WORLD_X / 2 || di > WORLD_Y / 2) { puts("fairland: error -- distance between continents too large"); exit(1); } if (argc > 7) id = atoi(argv[7]); else id = DEFAULT_ISLDIST; if (id < 0) { puts("fairland: error -- distance from islands to continents must be >= 0"); exit(1); } if (id > WORLD_X || id > WORLD_Y) { puts("fairland: error -- distance from islands to continents too large"); exit(1); } if (nc * sc + nc * my_sqrt(sc) * 2 * (di + 1) > WORLD_X * WORLD_Y) { puts("fairland: warning -- world might be too small to fit continents."); puts("arguments should satisfy:"); puts("nc*sc*sc + nc*sqrt(sc)*2*(di+1) < WORLD_X * WORLD_Y"); } }