empserver/src/lib/update/distribute.c

206 lines
5.4 KiB
C

/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2005, Dave Pare, Jeff Bailey, Thomas Ruschak,
* Ken Stevens, Steve McClure
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ---
*
* See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
* related information and legal notices. It is expected that any future
* projects/authors will amend these files as needed.
*
* ---
*
* distribute.c: Do distribution to sectors
*
* Known contributors to this file:
* Dave Pare, 1986
* Steve McClure, 1998
*/
#include <config.h>
#include <stdlib.h>
#include "misc.h"
#include "plague.h"
#include "nat.h"
#include "sect.h"
#include "item.h"
#include "xy.h"
#include "path.h"
#include "file.h"
#include "distribute.h"
#include "update.h"
#include "subs.h"
#include "common.h"
#include "prototypes.h"
#define EXPORT_BONUS 10.0
#define IMPORT_BONUS 10.0
#ifndef MAX
#define MAX(x,y) ((x) < (y) ? (y) : (x))
#endif
int
dodistribute(struct sctstr *sp, int imex, s_char *path, double dist_i_cost,
double dist_e_cost)
/* import or export? */
{
struct ichrstr *ip;
struct sctstr *dist;
int amt;
int thresh;
int amt_dist;
int amt_sect;
i_packing sect_packing, dist_packing;
int pack;
double mcost;
int diff;
i_type item;
int changed;
int rplague;
int lplague;
if ((sp->sct_dist_x == sp->sct_x) && (sp->sct_dist_y == sp->sct_y))
return 0;
if (path == (s_char *)0) {
if (sp->sct_own != 0) {
if (imex == EXPORT) /* only want this once */
wu(0, sp->sct_own, "No path to dist sector for %s\n",
ownxy(sp));
}
return 0;
}
dist = getsectp(sp->sct_dist_x, sp->sct_dist_y);
dist_packing = dist->sct_effic >= 60 ? dchr[dist->sct_type].d_pkg : IPKG;
sect_packing = sp->sct_effic >= 60 ? dchr[sp->sct_type].d_pkg : IPKG;
lplague = rplague = changed = 0;
for (item = I_NONE + 1; item <= I_MAX; item++) {
if (sp->sct_dist[item] == 0)
continue;
ip = &ichr[item];
thresh = sp->sct_dist[item];
/*
* calculate costs for importing and exporting.
* the mob bonus is because delivering straight through
* to the dist sect is cheaper than stopping at each
* sector along the way (processor-timewise)
*/
amt_sect = sp->sct_item[item];
amt_dist = dist->sct_item[item];
diff = amt_sect - thresh;
if (item == I_CIVIL)
if (sp->sct_own != sp->sct_oldown)
continue;
if (item == I_CIVIL)
if (dist->sct_own != dist->sct_oldown)
continue;
if (diff < 0) {
if (imex != IMPORT)
continue;
if (!military_control(dist))
continue;
diff = -diff;
/*
* import.
* don't import if no mobility.
* check to make sure have enough mobility in the
* dist sector to import what we need.
*/
if (dist->sct_mobil <= 0) {
/*logerror(" dist mobil < 0"); */
continue;
}
amt = diff;
if (item == I_CIVIL)
amt_dist--; /* Don't send your last civ */
if (amt_dist < amt) {
amt = amt_dist;
if (amt_dist <= 0)
continue;
}
pack = ip->i_pkg[dist_packing];
mcost = dist_i_cost / pack * ip->i_lbs / IMPORT_BONUS;
if (dist->sct_mobil < mcost * amt)
amt = dist->sct_mobil / mcost;
lplague++;
dist->sct_item[item] -= amt;
changed++;
dist->sct_mobil -= (int)(mcost * amt);
sp->sct_item[item] += amt;
} else {
if (imex != EXPORT)
continue;
if (!military_control(sp))
continue;
if ((item == I_CIVIL) && (sp->sct_work < 100))
continue;
if ((item == I_CIVIL) && (sp->sct_own != sp->sct_oldown))
continue;
/*
* export.
* don't export if no mobility. check to make sure we
* have mobility enough to do the right thing.
* also make sure that there's enough space in the
* target sector to hold the required amt.
*/
if (sp->sct_mobil <= 0) {
/*logerror(" sp mob is zero"); */
continue;
}
amt = diff;
if (amt > amt_sect)
amt = amt_sect;
pack = MAX(ip->i_pkg[sect_packing], ip->i_pkg[dist_packing]);
mcost = dist_e_cost / pack * ip->i_lbs / EXPORT_BONUS;
if (sp->sct_mobil < mcost * amt)
amt = sp->sct_mobil / mcost;
if (amt > ITEM_MAX - amt_dist)
amt = ITEM_MAX - amt_dist;
if (amt == 0)
continue;
rplague++;
sp->sct_item[item] -= amt;
changed++;
sp->sct_mobil -= (int)(mcost * amt);
dist->sct_item[item] += amt;
}
}
if (lplague) {
lplague = dist->sct_pstage;
if (lplague == PLG_INFECT && sp->sct_pstage == PLG_HEALTHY)
sp->sct_pstage = PLG_EXPOSED;
}
if (rplague) {
rplague = sp->sct_pstage;
if (rplague == PLG_INFECT && dist->sct_pstage == PLG_HEALTHY)
dist->sct_pstage = PLG_EXPOSED;
}
return changed;
}