Import of Empire 4.2.12

This commit is contained in:
Markus Armbruster 2003-08-23 12:23:04 +00:00
commit d8b7fdfae1
817 changed files with 126589 additions and 0 deletions

67
src/lib/update/Makefile Normal file
View file

@ -0,0 +1,67 @@
#
# Empire - A multi-player, client/server Internet based war game.
# Copyright (C) 1986-2000, 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.
#
# Makefile - Wolfpack, 1996
# Note that these could have been listed 1 per line, but I chose to just
# stick them all together this way to shorten the file.
include ../../../build.conf
include ../../make.src
include ../../make.defs
LIB = $(SRCDIR)/lib/libupdate.a
NTLIB = $(SRCDIR)\lib\libupdate.lib
OBJS = age.o anno.o bp.o deliver.o distribute.o finish.o human.o land.o \
main.o material.o mobility.o move_sat.o nat.o nav_ship.o nav_util.o \
nxtitemp.o nxtsctp.o plague.o plane.o populace.o prepare.o produce.o \
removewants.o revolt.o sail.o sect.o ship.o
NTOBJS = age.obj anno.obj bp.obj deliver.obj distribute.obj finish.obj \
human.obj land.obj main.obj material.obj mobility.obj move_sat.obj \
nat.obj nav_ship.obj nav_util.obj nxtitemp.obj nxtsctp.obj plague.obj \
plane.obj populace.obj prepare.obj produce.obj removewants.obj \
revolt.obj sail.obj sect.obj ship.obj
all: $(LIB)
nt: $(NTLIB)
$(NTLIB): $(NTOBJS)
-del /q $@
lib /OUT:$@ /DEBUGTYPE:CV $(NTOBJS)
$(LIB): $(OBJS)
rm -f $(LIB)
ar cq $(LIB) $(OBJS)
$(RANLIB) $(LIB)
clean:
-(rm -f $(OBJS))
-(del /q $(NTOBJS))
include ../../make.rules
include Makedepend

102
src/lib/update/age.c Normal file
View file

@ -0,0 +1,102 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* age.c: Age people
*
* Known contributors to this file:
* Dave Pare, 1986
*/
#include "misc.h"
#include "nat.h"
#include "file.h"
#include "update.h"
#include "gen.h"
void
age_levels(int etu)
{
extern float level_age_rate;
register float best_tech;
register float best_res;
register struct natstr *np;
int i;
double level;
double delta;
int deltares;
best_tech = 0.0;
best_res = 0.0;
for (i=0; NULL != (np = getnatp(i)); i++) {
if ((np->nat_stat & STAT_NORM) == 0)
continue;
if (np->nat_stat & STAT_GOD)
continue;
if (np->nat_stat == VIS)
continue;
if (best_tech < np->nat_level[NAT_TLEV])
best_tech = np->nat_level[NAT_TLEV];
if (best_res < np->nat_level[NAT_RLEV])
best_res = np->nat_level[NAT_RLEV];
if (level_age_rate != 0.0) {
delta = np->nat_level[NAT_RLEV] * etu /
(100 * level_age_rate);
np->nat_level[NAT_RLEV] -= delta;
delta = np->nat_level[NAT_TLEV] * etu /
(100 * level_age_rate);
np->nat_level[NAT_TLEV] -= delta;
}
/*
* age reserves by 1% per every 24 etus
*/
deltares = -roundavg(np->nat_reserve * etu / 2400.0);
if (deltares != 0)
np->nat_reserve += deltares;
/* Chad Zabel - above number is negative ( was a -= there
which was wrong. */
}
best_tech /= 5;
best_res /= 5;
for (i=0; NULL != (np = getnatp(i)); i++) {
if ((np->nat_stat & STAT_INUSE) == 0)
continue;
if (np->nat_stat & STAT_GOD)
continue;
if (np->nat_stat == VIS)
continue;
level = np->nat_level[NAT_TLEV];
if (level < best_tech && chance(0.2))
np->nat_level[NAT_TLEV] += (best_tech - level) / 3;
level = np->nat_level[NAT_RLEV];
if (level < best_res && chance(0.2))
np->nat_level[NAT_RLEV] += (best_res - level) / 3;
}
}

137
src/lib/update/anno.c Normal file
View file

@ -0,0 +1,137 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* anno.c: Delete announcements older than ANNO_KEEP_DAYS
*
* Known contributors to this file:
* Ken Stevens, 1995
* Doug Hay, 1998
* Steve McClure, 2000
*/
#include "misc.h"
#include "tel.h"
#include <stdio.h>
#include <fcntl.h>
#if !defined(_WIN32)
#include <sys/file.h>
#include <unistd.h>
#endif
#include "update.h"
#include "common.h"
void
delete_old_announcements(void)
{
time_t now;
time_t old;
struct telstr tgm;
FILE *oldfp;
int tmpfd;
s_char tmp_filename[1024];
int writeit;
s_char message[MAXTELSIZE];
int deleted = 0;
int saved = 0;
int length;
int nbytes;
int first = 1;
time(&now);
old = now - days(ANNO_KEEP_DAYS);
logerror("Deleting annos older than %s", ctime(&old));
#if !defined(_WIN32)
if ((oldfp = fopen(annfil, "r+")) == 0) {
#else
if ((oldfp = fopen(annfil, "r+b")) == 0) {
#endif
logerror("can't read telegram file %s", annfil);
return;
}
sprintf(tmp_filename, "%s.tmp", annfil);
#if !defined(_WIN32)
if ((tmpfd = open(tmp_filename, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
#else
if ((tmpfd = open(tmp_filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666)) < 0) {
#endif
logerror("can't write telegram file %s", tmp_filename);
return;
}
while (fread((s_char *) &tgm, sizeof(tgm), 1, oldfp) == 1) {
writeit = 1;
if (tgm.tel_length < 0) {
logerror("bad telegram file header (length)");
return;
}
if (tgm.tel_type < 0 || tgm.tel_type > TEL_LAST) {
logerror("bad telegram file header (type)");
writeit = 0;
}
if (first) {
first = 0;
if (tgm.tel_date >= old) {
fclose(oldfp);
return;
}
}
if (tgm.tel_date < old) {
writeit = 0;
}
if (writeit) {
if (write(tmpfd, &tgm, sizeof(tgm)) < (int)sizeof(tgm)) {
logerror("error writing to ann.tmp");
return;
}
++saved;
} else {
++deleted;
}
length = tgm.tel_length;
while (length > 0) {
nbytes = length;
if (nbytes > (int)sizeof(message))
nbytes = sizeof(message);
(void) fread(message, sizeof(s_char), nbytes, oldfp);
if (writeit) {
if (write(tmpfd, message, nbytes) < nbytes) {
logerror("Error writing to ann.tmp");
return;
}
}
length -= nbytes;
}
}
logerror("%d announcements deleted; %d announcements saved",
deleted, saved);
fclose(oldfp);
close(tmpfd);
unlink(annfil);
rename(tmp_filename, annfil);
}

97
src/lib/update/bp.c Normal file
View file

@ -0,0 +1,97 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* bp.c: Functions for build pointer (bp) handling
*
* Known contributors to this file:
* Ville Virrankoski, 1996
*/
#include "misc.h"
#include "nat.h"
#include "file.h"
#include "sect.h"
#include "var.h"
#include "budg.h"
#include "update.h"
#include "common.h"
#include "optlist.h"
static int bud_key[I_MAX+2] = {0,1,2,3,4,0,0,0,0,0,0,5,6,0,0,7};
int
*get_wp(int *bp, struct sctstr *sp, int cm)
{
return (bp + (sp->sct_x + (sp->sct_y * WORLD_X)) + WORLD_X * WORLD_Y * (cm - 1));
}
int
gt_bg_nmbr(int *bp, struct sctstr *sp, int comm)
{
int *wp;
int cm;
int svec[I_MAX+1];
if ((cm = bud_key[comm]) == 0) {
getvec(VT_ITEM, svec, (s_char *)sp, EF_SECTOR);
return svec[comm];
} else {
wp = get_wp(bp, sp, cm);
return *wp;
}
}
void pt_bg_nmbr(int *bp, struct sctstr *sp, int comm, int amount)
{
int *wp;
int cm;
if ((cm = bud_key[comm]) != 0) {
wp = get_wp(bp, sp, cm);
*wp = amount;
}
}
void
fill_update_array(int *bp, struct sctstr *sp)
{
int vec[I_MAX+1];
int i, k;
int *wp;
if (getvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR) <= 0)
return;
for (i=1;i<=I_MAX;i++)
if ((k = bud_key[i]) != 0) {
wp = get_wp(bp, sp, k);
*wp = vec[i];
}
wp = get_wp(bp, sp, bud_key[I_MAX+1]);
*wp = sp->sct_avail;
}

119
src/lib/update/deliver.c Normal file
View file

@ -0,0 +1,119 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* deliver.c: Deliver commodities to neighboring sector
*
* Known contributors to this file:
*
*/
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "item.h"
#include "path.h"
#include "file.h"
#include "xy.h"
#include "update.h"
#include "subs.h"
#include "common.h"
int
deliver(register struct sctstr *from, struct ichrstr *ip, int dir, int thresh, int amt_src, int plague)
{
register struct sctstr *to;
int vtype; /* item vartype */
int pack_src;
int amt_moved;
int amt_dst;
int mobility;
float mcost;
struct dchrstr *dp;
int n;
if (dir <= 0 || dir > DIR_UL)
return 0;
if (amt_src <= 0)
return 0;
if ((amt_moved = amt_src - thresh) <= 0)
return 0;
/*
* make sure delivery looks ok. Check where its going,
* where its coming from, and see if there is more than
* the threshold amount
*/
if (!military_control(from))
return 0;
to = getsectp(from->sct_x+diroff[dir][0], from->sct_y+diroff[dir][1]);
if (to->sct_own != from->sct_own) {
wu(0, from->sct_own, "%s delivery walkout at %s\n",
ip->i_name, ownxy(from));
return 0;
}
dp = &dchr[from->sct_type];
vtype = ip->i_vtype;
pack_src = ip->i_pkg[dp->d_pkg];
mobility = from->sct_mobil / 2;
if (vtype == V_CIVIL && from->sct_own != from->sct_oldown) {
wu(0, from->sct_own, "The conquered populace in %s refuses to relocate!\n", ownxy(from));
return 0;
}
/*
* disallow delivery into prohibited sectors.
* calculate unit movement cost; decrease amount if
* there isn't enough mobility.
*/
mcost = sector_mcost(to, MOB_ROAD)*ip->i_lbs/pack_src;
mcost /= 4.0;
if (mobility < mcost * amt_moved) {
/* XXX can mcost be == 0? */
amt_moved = (int) (mobility / mcost);
if (amt_moved <= 0)
return 0;
}
amt_dst = getvar(vtype, (caddr_t)to, EF_SECTOR);
if (amt_moved + amt_dst > 9990) {
/* delivery backlog */
if ((amt_moved = 9990 - amt_dst) <= 0)
return 0;
}
if (putvar(vtype, amt_moved + amt_dst, (s_char *)to, EF_SECTOR) < 0) {
/* "No room to deliver commodities */
wu(0, from->sct_own, "no room for %s in %s\n",
ip->i_name, ownxy(to));
return 0;
}
/* deliver the plague too! */
if (plague == PLG_INFECT && getvar(V_PSTAGE, (s_char *)to,EF_SECTOR) == 0)
putvar(V_PSTAGE, PLG_EXPOSED, (s_char *)to, EF_SECTOR);
n = from->sct_mobil - (int) (mcost * amt_moved);
if (n < 0)
n = 0;
from->sct_mobil = n;
return amt_moved;
}

223
src/lib/update/distribute.c Normal file
View file

@ -0,0 +1,223 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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 <stdlib.h>
#include "misc.h"
#include "var.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"
int
dodistribute(struct sctstr *sp, int imex, s_char *path, double dist_i_cost, double dist_e_cost)
/* import or export? */
{
struct sctstr *getdistsp();
float distpathcost();
struct ichrstr *ip;
struct sctstr *dist;
int amt;
int thresh;
int amt_dist;
int amt_sect;
int packing;
float imcost;
float excost;
int dist_packing;
int diff;
int item;
int dists[I_MAX+1];
int remote[I_MAX+1];
int local[I_MAX+1];
int changed;
int rplague;
int lplague;
getvec(VT_ITEM, local, (s_char *)sp, EF_SECTOR);
if ((sp->sct_dist_x == sp->sct_x) && (sp->sct_dist_y == sp->sct_y))
return 0;
if (getvec(VT_DIST, dists, (s_char *)sp, EF_SECTOR) <= 0)
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);
if (dist->sct_effic >= 60)
dist_packing = dchr[dist->sct_type].d_pkg;
else
dist_packing = NPKG; /* No packing */
if (sp->sct_effic >= 60)
packing = dchr[sp->sct_type].d_pkg;
else
packing = NPKG; /* No packing */
if ((dist->sct_effic >= 60) && dchr[dist->sct_type].d_pkg == WPKG)
packing = dchr[dist->sct_type].d_pkg;
getvec(VT_ITEM, remote, (s_char *)dist, EF_SECTOR);
lplague = rplague = changed = 0;
for (item = 1; item < I_MAX+1; item++) {
if (dists[item] == 0)
continue;
ip = &ichr[item];
thresh = dists[item];
/*
* calculate costs for importing and exporting.
* the div 10.0 is because delivering straight through
* to the dist sect is cheaper than stopping at each
* sector along the way (processor-timewise)
*/
excost = (dist_e_cost/ip->i_pkg[packing] * ip->i_lbs) / 10.0;
imcost = (dist_i_cost/ip->i_pkg[dist_packing] *ip->i_lbs)/10.0;
amt_sect = local[item];
amt_dist = remote[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;
}
if (dist->sct_mobil < imcost * amt)
amt = dist->sct_mobil / imcost;
lplague++;
/* XXX replace with vector assign and putvec() */
remote[item] -= amt;
changed++;
dist->sct_mobil -= (int) (imcost * amt);
local[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;
if (sp->sct_mobil < excost * amt)
amt = sp->sct_mobil / excost;
if (amt + amt_dist > 9999)
amt = 9999 - amt_dist;
if (amt == 0)
continue;
/* XXX replace with vector assign and putvec() */
rplague++;
local[item] -= amt;
changed++;
sp->sct_mobil -= (int) (excost * amt);
remote[item] += amt;
}
}
putvec(VT_ITEM, remote, (s_char *)dist, EF_SECTOR);
putvec(VT_ITEM, local, (s_char *)sp, EF_SECTOR);
if (lplague) {
lplague = getvar(V_PSTAGE, (s_char *)dist, EF_SECTOR);
if (lplague == PLG_INFECT &&
getvar(V_PSTAGE, (s_char *)sp, EF_SECTOR) == PLG_HEALTHY) {
putvar(V_PSTAGE, PLG_EXPOSED, (s_char *)sp, EF_SECTOR);
}
}
if (rplague) {
rplague = getvar(V_PSTAGE, (s_char *)sp, EF_SECTOR);
if (rplague == PLG_INFECT &&
getvar(V_PSTAGE, (s_char *)dist, EF_SECTOR) == PLG_HEALTHY) {
putvar(V_PSTAGE, PLG_EXPOSED, (s_char *)dist, EF_SECTOR);
}
}
return changed;
}

270
src/lib/update/finish.c Normal file
View file

@ -0,0 +1,270 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* finish.c: Finish the update
*
* Known contributors to this file:
* Dave Pare, 1986
* Thomas Ruschak, 1993
* Steve McClure, 1998
*/
#include <math.h>
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "nat.h"
#include "item.h"
#include "news.h"
#include "file.h"
#include "xy.h"
#include "path.h"
#include "distribute.h"
#include "update.h"
#include "common.h"
#include "optlist.h"
/* Used for building up distribution info */
struct distinfo {
s_char *path; /* path to take */
double imcost; /* import cost */
double excost; /* export cost */
};
/* This is our global buffer of distribution pointers. Note that
* We only malloc this once, and never again (until reboot time
* of course :) ) We do clear it each and every time. */
struct distinfo *g_distptrs = (struct distinfo *)0;
/* Note that even though we malloc and save the path, it is never
* used. Thus, this option. If you want to malloc and save every
* path and then free when done, just enable this. Or, if the
* dodistribute ever uses the path for something other than checking
* to see that a path exists, enable this */
/* #define SAVE_FINISH_PATHS */
#ifndef SAVE_FINISH_PATHS
static s_char *finish_path = "h"; /* Placeholder indicating path exists */
#endif /* SAVE_FINISH_PATHS */
static void assemble_dist_paths(struct distinfo *distptrs);
s_char *BestDistPath();
s_char *ReversePath(s_char *path);
double pathcost();
void
finish_sects(int etu)
{
register struct sctstr *sp;
struct natstr *np;
int n;
int vec[I_MAX+1];
int changed;
struct distinfo *infptr;
if (g_distptrs == (struct distinfo *)0) {
logerror("First update since reboot, allocating buffer\n");
/* Allocate the information buffer */
g_distptrs = (struct distinfo *)(malloc((WORLD_X * WORLD_Y) *
sizeof(struct distinfo)));
if (g_distptrs == (struct distinfo *)0) {
logerror("malloc failed in finish_sects.\n");
return;
}
logerror("Allocated '%d' bytes '%d' indices\n",
((WORLD_X * WORLD_Y) * sizeof(struct distinfo)),
(WORLD_X * WORLD_Y));
}
/* Wipe it clean */
bzero((s_char *)g_distptrs, ((WORLD_X * WORLD_Y) *
sizeof(struct distinfo)));
logerror("delivering...\n");
/* Do deliveries */
for (n=0; NULL != (sp = getsectid(n)); n++) {
if (sp->sct_type == SCT_WATER)
continue;
if (sp->sct_own == 0)
continue;
np = getnatp(sp->sct_own);
if (np->nat_money < 0)
continue;
changed = 0;
if (getvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR) > 0)
changed += dodeliver(sp, vec);
if (changed)
putvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
}
logerror("done delivering\n");
logerror("assembling paths...\n");
/* First, enable the best_path cacheing */
bp_enable_cachepath();
/* Now assemble the paths */
assemble_dist_paths(g_distptrs);
/* Now disable the best_path cacheing */
bp_disable_cachepath();
/* Now, clear the best_path cache that may have been created */
bp_clear_cachepath();
logerror("done assembling paths\n");
logerror("exporting...");
for (n=0; NULL != (sp = getsectid(n)); n++) {
if (sp->sct_type == SCT_WATER || sp->sct_own == 0)
continue;
np = getnatp(sp->sct_own);
if (np->nat_money < 0)
continue;
/* Get the pointer */
infptr = &g_distptrs[XYOFFSET(sp->sct_x, sp->sct_y)];
dodistribute(sp, EXPORT,
infptr->path, infptr->imcost, infptr->excost);
}
logerror("done exporting\n");
/* Note that we free the paths (if allocated) as we loop here */
logerror("importing...");
for (n=0; NULL != (sp = getsectid(n)); n++) {
/* Get the pointer (we do it first so we can free if needed) */
infptr = &g_distptrs[XYOFFSET(sp->sct_x, sp->sct_y)];
if (sp->sct_type == SCT_WATER || sp->sct_own == 0) {
#ifdef SAVE_FINISH_PATHS
if (infptr->path)
free((s_char *)infptr->path);
#endif /* SAVE_FINISH_PATHS */
continue;
}
np = getnatp(sp->sct_own);
if (np->nat_money < 0) {
#ifdef SAVE_FINISH_PATHS
if (infptr->path)
free((s_char *)infptr->path);
#endif /* SAVE_FINISH_PATHS */
continue;
}
dodistribute(sp, IMPORT,
infptr->path, infptr->imcost, infptr->excost);
#ifdef SAVE_FINISH_PATHS
if (infptr->path)
free((s_char *)infptr->path);
#endif /* SAVE_FINISH_PATHS */
}
logerror("done importing\n");
}
static void
assemble_dist_paths(struct distinfo *distptrs)
{
s_char *path, *p;
double d;
struct sctstr *sp;
struct sctstr *dist;
struct distinfo *infptr;
int n;
s_char buf[512];
for (n=0; NULL != (sp = getsectid(n)); n++) {
if ((sp->sct_dist_x == sp->sct_x) && (sp->sct_dist_y == sp->sct_y))
continue;
/* Set the pointer */
infptr = &distptrs[XYOFFSET(sp->sct_x, sp->sct_y)];
/* now, get the dist sector */
dist = getsectp(sp->sct_dist_x, sp->sct_dist_y);
if (dist == (struct sctstr *)0){
logerror("Bad dist sect %d,%d for %d,%d !\n",sp->sct_dist_x,
sp->sct_dist_y,sp->sct_x,sp->sct_y);
continue;
}
/* Now, get the best distribution path over roads */
/* Note we go from the dist center to the sector. This gives
us the import path for that sector. */
path = BestDistPath(buf, dist, sp, &d, MOB_ROAD);
/* Now, we have a path */
if (path != (s_char *)0) {
#ifdef SAVE_FINISH_PATHS
int len;
/* Here we malloc a buffer and save it */
len = strlen(path);
infptr->path = (s_char *)malloc(len);
if (infptr->path == (s_char *)0) {
logerror("malloc failed in assemble_dist_path!\n");
return;
}
#endif /* SAVE_FINISH_PATHS */
/* Save the import cost */
infptr->imcost = d;
/* Now, reverse the path */
p = ReversePath(path);
/* And walk the path back to the dist center to get the export
cost */
infptr->excost = pathcost(sp, p, MOB_ROAD);
#ifdef SAVE_FINISH_PATHS
bcopy(p, infptr->path, len);
#else
infptr->path = finish_path;
#endif /* SAVE_FINISH_PATHS */
}
}
}
s_char
*ReversePath(s_char *path)
{
s_char *patharray = "aucdefjhigklmyopqrstbvwxnz";
static s_char new_path[512];
int ind;
if (path == (s_char *)0)
return (s_char *)0;
ind = strlen(path);
if (ind == 0)
return (s_char *)0;
if (path[ind - 1] == 'h')
ind--;
new_path[ind--] = '\0';
new_path[ind] = '\0';
while (ind >= 0) {
new_path[ind--] = patharray[*(path++) - 'a'];
}
return new_path;
}

326
src/lib/update/human.c Normal file
View file

@ -0,0 +1,326 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* human.c: Food related functions
*
* Known contributors to this file:
* Dave Pare, 1986
* Steve McClure, 1996
*/
#include <math.h>
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "nat.h"
#include "item.h"
#include "news.h"
#include "file.h"
#include "xy.h"
#include "optlist.h"
#include "budg.h"
#include "player.h"
#include "update.h"
#include "common.h"
#include "gen.h"
#include "subs.h"
/*
* feed the individual sector
*
*/
int
do_feed(register struct sctstr *sp, register struct natstr *np, int *vec, int *workp, int *bp, int etu)
{
extern double eatrate;
int people;
int work_avail;
int starved, sctwork;
int needed, dummy;
int civvies, uws;
int mil;
int maxpop;
/* grow people & stuff */
sctwork = sp->sct_work;
maxpop = max_pop(np->nat_level[NAT_RLEV], sp);
civvies = (vec[I_CIVIL] > maxpop) ? maxpop : vec[I_CIVIL];
uws = (vec[I_UW] > maxpop) ? maxpop : vec[I_UW];
mil = (vec[I_MILIT] > maxpop) ? maxpop : vec[I_MILIT];
work_avail = total_work(sctwork, etu, civvies, mil, uws);
people = vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW];
if (sp->sct_type != SCT_SANCT) {
if (opt_NOFOOD == 0) {
if (vec[I_FOOD] < 1 + etu * people * eatrate) {
/* need to grow "emergency rations" */
work_avail -= (2 *
growfood(sp, vec, (int)(work_avail/2), etu));
/* It's twice as hard to grow those than norm*/
pt_bg_nmbr(bp, sp, I_MAX+1, work_avail);
if (!player->simulation)
sp->sct_avail = work_avail;
}
if ((vec[I_FOOD] < 1 + etu * people * eatrate) &&
(sp->sct_own == sp->sct_oldown)){
/* steal food from warehouses, headquarters,
supply ships in port, or supply units */
int needed;
needed = ldround((double)(1+etu*people*eatrate),1);
/* Now, find some food */
vec[I_FOOD] = supply_commod(sp->sct_own,sp->sct_x,
sp->sct_y,I_FOOD,needed);
}
}
starved = feed_people(vec, etu, &needed);
if ((starved > 0 && sp->sct_own) && (!player->simulation)) {
/* don't report POGO starvation */
wu(0, sp->sct_own, "%d starved in %s.\n", starved,
xyas(sp->sct_x, sp->sct_y, sp->sct_own));
if (starved > 25)
nreport(sp->sct_own, N_DIE_FAMINE, 0, 1);
}
if (starved > 0) {
if (!player->simulation)
starvation(sp);
sctwork = 0;
} else {
if (sp->sct_work < 100)
sctwork = sp->sct_work + 8 + (random() % 15);
if (sctwork > 100)
sctwork = 100;
if (!player->simulation)
sp->sct_work = sctwork;
dummy = grow_people(sp, etu, np, &work_avail, sctwork, vec);
}
} else
sctwork = sp->sct_work = 100;
/* Here is where we truncate extra people, always */
trunc_people(sp, np, vec);
pt_bg_nmbr(bp, sp, I_CIVIL, vec[I_CIVIL]);
pt_bg_nmbr(bp, sp, I_UW, vec[I_UW]);
pt_bg_nmbr(bp, sp, I_MILIT, vec[I_MILIT]);
*workp = work_avail;
return sctwork;
}
int
growfood(struct sctstr *sp, register int *vec, int work, int etu)
{
extern double fgrate;
extern double fcrate;
double food_fertil;
double food_workers;
double food;
int work_used;
/* I'm being very nice and commenting out this so players
* won't whine about starvation
if (sp->sct_fertil == 0 || work == 0)
return 0;
*/
food_workers = work * fcrate;
food_fertil = etu * sp->sct_fertil * fgrate;
food = food_fertil;
if (food > food_workers)
food = food_workers;
/*
* be nice; grow minimum one food unit.
* This makes life simpler for the player.
*/
vec[I_FOOD] += (int) food;
if (vec[I_FOOD] == 0)
vec[I_FOOD] = 1;
if (vec[I_FOOD] > 9999)
vec[I_FOOD] = 9999;
work_used = (int) food / fcrate;
return work_used;
}
/*
* returns the number who starved, if any.
*/
int
feed_people(register int *vec, int etu, int *needed)
{
extern double eatrate;
double food_eaten;
double people_left;
int can_eat;
int total_people;
int to_starve;
int starved;
if (opt_NOFOOD)
return 0;
food_eaten = (double)(((double)etu * (double)eatrate) *
(double)(vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW]));
if (food_eaten <= 1)
return 0;
starved = 0;
*needed = 0;
if (food_eaten > vec[I_FOOD]) {
*needed = food_eaten - vec[I_FOOD];
if ((double)(*needed) < (double)(food_eaten - (double)vec[I_FOOD]))
(*needed)++;
if (opt_NEW_STARVE) {
can_eat = (vec[I_FOOD] / (etu * eatrate));
total_people = vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW];
/* only want to starve off at most 1/2 the populace. */
if (can_eat < (total_people/2))
can_eat = total_people/2;
to_starve = total_people - can_eat;
while(to_starve && vec[I_UW]){
to_starve--;
starved++;
vec[I_UW]--;
}
while(to_starve && vec[I_CIVIL]){
to_starve--;
starved++;
vec[I_CIVIL]--;
}
while(to_starve && vec[I_MILIT]){
to_starve--;
starved++;
vec[I_MILIT]--;
}
vec[I_FOOD] = 0;
}
else { /* ! opt_NEW_STARVE */
people_left = (vec[I_FOOD] + 0.01) / (food_eaten + 0.01);
starved = vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW];
/* only want to starve off at most 1/2 the populace. */
if (people_left < 0.5)
people_left = 0.5;
vec[I_CIVIL] = (int) (vec[I_CIVIL] * people_left);
vec[I_MILIT] = (int) (vec[I_MILIT] * people_left);
vec[I_UW] = (int) (vec[I_UW] * people_left);
starved -= vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW];
vec[I_FOOD] = 0;
} /* end opt_NEW_STARVE */
} else {
vec[I_FOOD] -= roundavg(food_eaten);
}
return starved;
}
/*
* Truncate any extra people that may be around
*/
void
trunc_people(struct sctstr *sp, register struct natstr *np, register int *vec)
{
int maxpop = max_pop(np->nat_level[NAT_RLEV], sp);
if (vec[I_CIVIL] > maxpop)
vec[I_CIVIL] = maxpop;
if (vec[I_UW] > maxpop)
vec[I_UW] = maxpop;
}
/*
* Grow babies, and add to populace.
* XXX Might think about dropping in a birth
* rate limitation on countries with high tech
* production? Maybe with just high education?
*/
int grow_people(struct sctstr *sp, register int etu, register struct natstr *np, int *workp, int sctwork, register int *vec)
{
extern double obrate;
extern double uwbrate;
extern double babyeat;
int newciv;
int newuw;
int new_birth;
int new_food;
int maxpop = max_pop(np->nat_level[NAT_RLEV], sp);
newciv = 0;
newuw = 0;
if (vec[I_CIVIL] < maxpop) {
new_birth = (int) roundavg(obrate * (double)(etu * vec[I_CIVIL]));
if (opt_NOFOOD)
new_food = (int) (0.5 + maxpop / (2.0 * babyeat));
else /* we are using food */
new_food = (int) (0.5 + vec[I_FOOD] / (2.0 * babyeat));
newciv = new_birth;
if (newciv > new_food)
newciv = new_food;
/* Now, check max pops */
if ((vec[I_CIVIL] + newciv) > maxpop)
newciv = maxpop - vec[I_CIVIL];
vec[I_CIVIL] += newciv;
}
if (vec[I_UW] < maxpop) {
/*
* now grow uw's
*/
new_birth = (int) roundavg(uwbrate * (double)(etu * vec[I_UW]));
if (opt_NOFOOD)
new_food = (int) (0.5 + maxpop / (2.0 * babyeat));
else /* food is important */
new_food = (int) (0.5 + vec[I_FOOD] / (2.0 * babyeat));
newuw = new_birth;
if (newuw > new_food)
newuw = new_food;
/* Now, check max pops */
if ((vec[I_UW] + newuw) > maxpop)
newuw = maxpop - vec[I_UW];
vec[I_UW] += newuw;
}
/*
* subtract the baby eat food (if we are using FOOD) and return
* # of births.
*/
if (opt_NOFOOD == 0 && (newciv || newuw))
vec[I_FOOD] -= roundavg((newciv + newuw) * babyeat);
*workp += total_work(sctwork, etu, newciv, 0, newuw);
return newciv + newuw;
}
/*
* percentage of people who starved
*/
void
starvation(struct sctstr *sp)
{
sp->sct_work = 0;
sp->sct_loyal += (random() % 8) + 2;
}

439
src/lib/update/land.c Normal file
View file

@ -0,0 +1,439 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* land.c: Do production for land units
*
* Known contributors to this file:
* Dave Pare, 1986
* Thomas Ruschak, 1992
* Steve McClure, 1996
*/
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "nat.h"
#include "land.h"
#include "ship.h"
#include "var.h"
#include "news.h"
#include "file.h"
#include "product.h"
#include "optlist.h"
#include "budg.h"
#include "player.h"
#include "update.h"
#include "lost.h"
#include "common.h"
#include "subs.h"
#include "common.h"
#include "gen.h"
int mil_dbl_pay;
#ifndef MIN
#define MIN(x,y) ((x) > (y) ? (y) : (x))
#endif
void upd_land(register struct lndstr *lp, int landno, register int etus, struct natstr *np, int *bp, int build);
int
prod_land(int etus, int natnum, int *bp, int build)
/* build = 1, maintain = 0 */
{
register struct lndstr *lp;
struct sctstr *sp;
struct natstr *np;
int n, k=0;
extern long lnd_money[MAXNOC];
int start_money;
int lastx = 9999, lasty = 9999;
bp_enable_cachepath();
for (n=0; NULL != (lp = getlandp(n)); n++) {
if (lp->lnd_own == 0)
continue;
if (lp->lnd_own != natnum)
continue;
sp = getsectp(lp->lnd_x,lp->lnd_y);
if (sp->sct_type == SCT_SANCT)
continue;
if (lastx == 9999 || lasty == 9999) {
lastx = lp->lnd_x;
lasty = lp->lnd_y;
}
if (lastx != lp->lnd_x || lasty != lp->lnd_y) {
/* Reset the cache */
bp_disable_cachepath();
bp_clear_cachepath();
bp_enable_cachepath();
}
np = getnatp(lp->lnd_own);
start_money = np->nat_money;
upd_land(lp, n, etus, np, bp, build);
lnd_money[lp->lnd_own] += np->nat_money - start_money;
if ((build && (np->nat_money != start_money)) || (!build))
k++;
if (player->simulation)
np->nat_money = start_money;
}
bp_disable_cachepath();
bp_clear_cachepath();
return k;
}
void
upd_land(register struct lndstr *lp, int landno, register int etus, struct natstr *np, int *bp, int build)
/* build = 1, maintain = 0 */
{
extern int morale_base;
struct lchrstr *lcp;
int vec[I_MAX+1];
int cvec[I_MAX+1];
int n;
double techfact(int, double);
int min = morale_base-(int)np->nat_level[NAT_HLEV];
int mult;
extern double money_land;
int needed;
int cost;
int eff;
if (!player->simulation)
if (lp->lnd_retreat < min)
lp->lnd_retreat = min;
lcp = &lchr[(int)lp->lnd_type];
getvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
if (build == 1){
if (np->nat_priorities[PRI_LBUILD] == 0 ||
np->nat_money < 0)
return;
if (lp->lnd_effic < LAND_MINEFF ||
!(landrepair(lp,vec,np,bp,etus))){
makelost(EF_LAND, lp->lnd_own, lp->lnd_uid, lp->lnd_x, lp->lnd_y);
lp->lnd_own = 0;
return;
}
}else{
mult = 1;
if (np->nat_level[NAT_TLEV] < lp->lnd_tech * 0.85)
mult = 2;
if (lcp->l_flags & L_ENGINEER)
mult *= 3;
/* cost = -(mult * etus * dmin(0.0, money_land * LND_COST(lcp->l_cost, lp->lnd_tech - lcp->l_tech)));*/
cost = -(mult * etus * dmin(0.0, money_land * lcp->l_cost));
if ((np->nat_priorities[PRI_LMAINT] == 0 ||
np->nat_money < cost) && !player->simulation) {
if ((eff = lp->lnd_effic - etus/5) < LAND_MINEFF) {
wu(0, lp->lnd_own,
"%s lost to lack of maintenance\n",
prland(lp));
makelost(EF_LAND, lp->lnd_own, lp->lnd_uid, lp->lnd_x, lp->lnd_y);
lp->lnd_own = 0;
return;
}
wu(0, lp->lnd_own,
"%s lost %d%% to lack of maintenance\n",
prland(lp), lp->lnd_effic - eff);
lp->lnd_effic = eff;
} else {
np->nat_money -= cost;
}
/* Mil costs are now part of regular mil costs, not maint costs */
/* np->nat_money += (int) (money_mil * etus * lnd_getmil(lp));*/
/* Grab more stuff */
if ((opt_NOFOOD == 0) && !player->simulation)
resupply_commod(lp,I_FOOD);
getvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
if (!player->simulation) {
if ((n = feed_land(lp, vec, etus, &needed, 1)) > 0) {
wu(0, lp->lnd_own, "%d starved in %s%s\n",
n, prland(lp),
(lp->lnd_effic < LAND_MINEFF ?
", killing it" : ""));
if (n > 10)
nreport(lp->lnd_own, N_DIE_FAMINE, 0, 1);
}
/*
* do plague stuff. plague can't break out on land units,
* but it can still kill people on them.
*/
getvec(VT_COND, cvec, (s_char *)lp, EF_LAND);
if (cvec[C_PSTAGE] > 0) {
n = plague_people(np, vec, cvec, etus);
switch (n) {
case PLG_DYING:
wu(0, lp->lnd_own,
"PLAGUE deaths reported on %s\n",
prland(lp));
nreport(lp->lnd_own, N_DIE_PLAGUE, 0, 1);
break;
case PLG_INFECT:
wu(0, lp->lnd_own, "%s battling PLAGUE\n",
prland(lp));
break;
case PLG_INCUBATE:
/* Are we still incubating? */
if (n == cvec[C_PSTAGE]) {
/* Yes. Will it turn "infectious" next time? */
if (cvec[C_PTIME] <= etus) {
/* Yes. Report an outbreak. */
wu(0, lp->lnd_own,
"Outbreak of PLAGUE on %s!\n",
prland(lp));
nreport(lp->lnd_own, N_OUT_PLAGUE, 0, 1);
}
} else {
/* It has already moved on to "infectious" */
wu(0, lp->lnd_own,
"%s battling PLAGUE\n", prland(lp));
}
break;
case PLG_EXPOSED:
/* Has the plague moved to "incubation" yet? */
if (n != cvec[C_PSTAGE]) {
/* Yes. Will it turn "infectious" next time? */
if (cvec[C_PTIME] <= etus) {
/* Yes. Report an outbreak. */
wu(0, lp->lnd_own,
"Outbreak of PLAGUE on %s!\n",
prland(lp));
nreport(lp->lnd_own, N_OUT_PLAGUE, 0, 1);
}
}
break;
default:
break;
}
putvec(VT_COND, cvec, (s_char *)lp, EF_LAND);
}
putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
} /* end !player->simulation */
}
}
/*ARGSUSED*/
int
landrepair(register struct lndstr *land, int *vec, struct natstr *np, int *bp, int etus)
{
extern int mil_dbl_pay;
extern int land_grow_scale;
register int delta;
struct sctstr *sp;
struct lchrstr *lp;
float leftp, buildp;
int left, build;
int mil_needed, lcm_needed, hcm_needed, gun_needed, shell_needed;
int avail;
int w_p_eff;
int mult;
int svec[I_MAX+1];
int mvec[I_MAX+1];
lp = &lchr[(int)land->lnd_type];
sp = getsectp(land->lnd_x, land->lnd_y);
if (sp->sct_off)
return 1;
getvec(VT_ITEM, svec, (s_char *)sp, EF_SECTOR);
mult = 1;
if (np->nat_level[NAT_TLEV] < land->lnd_tech * 0.85)
mult = 2;
if (land->lnd_effic == 100) {
/* land is ok; no repairs needed */
return 1;
}
if (sp->sct_own != land->lnd_own)
return 1;
if (!player->simulation)
avail = sp->sct_avail * 100;
else
avail = gt_bg_nmbr(bp, sp, I_MAX+1) * 100;
w_p_eff = 20 + (lp->l_lcm + 2 * lp->l_hcm);
delta = roundavg((double)avail/w_p_eff);
if (delta <= 0)
return 1;
if (delta > etus*land_grow_scale)
delta = etus*land_grow_scale;
/* delta is the max amount we can grow */
left = 100 - land->lnd_effic;
if (left > delta)
left = delta;
leftp = ((float)left/100.0);
bzero((s_char *)mvec, sizeof(mvec));
mvec[I_LCM] = lcm_needed = ldround((double)(lp->l_lcm * leftp),1);
mvec[I_HCM] = hcm_needed = ldround((double)(lp->l_hcm * leftp),1);
/*
mvec[I_GUN] = gun_needed = ldround((double)(lp->l_gun * leftp),1);
mvec[I_MILIT] = mil_needed = ldround((double)(lp->l_mil * leftp),1);
mvec[I_SHELL] = shell_needed = ldround((double)(lp->l_shell *leftp),1);
*/
mvec[I_GUN] = gun_needed = 0;
mvec[I_MILIT] = mil_needed = 0;
mvec[I_SHELL] = shell_needed = 0;
get_materials(sp, bp, mvec, 0);
if (mvec[I_MILIT]>=mil_needed)
buildp=leftp;
else
buildp=((float)mvec[I_MILIT]/(float)lp->l_mil);
if (mvec[I_LCM] < lcm_needed)
buildp = MIN(buildp,((float)mvec[I_LCM]/(float)lp->l_lcm));
if (mvec[I_HCM] < hcm_needed)
buildp = MIN(buildp,((float)mvec[I_HCM]/(float)lp->l_hcm));
if (mvec[I_GUN] < gun_needed)
buildp = MIN(buildp,((float)mvec[I_GUN]/(float)lp->l_gun));
if (mvec[I_SHELL] < shell_needed)
buildp = MIN(buildp,((float)mvec[I_SHELL]/(float)lp->l_shell));
build=ldround((double)(buildp*100.0),1);
bzero((s_char *)mvec, sizeof(mvec));
mvec[I_LCM] = lcm_needed = roundavg((double)(lp->l_lcm * buildp));
mvec[I_HCM] = hcm_needed = roundavg((double)(lp->l_hcm * buildp));
/*
mvec[I_GUN] = gun_needed = roundavg((double)(lp->l_gun * buildp));
mvec[I_MILIT] = mil_needed = roundavg((double)(lp->l_mil * buildp));
mvec[I_SHELL] = shell_needed = roundavg((double)(lp->l_shell *buildp));
*/
mvec[I_GUN] = gun_needed = 0;
mvec[I_MILIT] = mil_needed = 0;
mvec[I_SHELL] = shell_needed = 0;
mil_dbl_pay += mil_needed;
get_materials(sp, bp, mvec, 1);
if ((sp->sct_type != SCT_HEADQ) && (sp->sct_type != SCT_FORTR))
build /= 3;
avail -= build * w_p_eff;
if (!player->simulation) {
sp->sct_avail = avail/100;
if (sp->sct_avail < 0)
sp->sct_avail = 0;
} else {
pt_bg_nmbr(bp, sp, I_MAX+1, avail/100);
if (gt_bg_nmbr(bp, sp, I_MAX+1) < 0)
pt_bg_nmbr(bp, sp, I_MAX+1, 0);
}
if (build<0)
logerror("land unit %d building %d ! \n",land->lnd_uid,build);
np->nat_money -= mult * lp->l_cost * build / 100.0;
if (!player->simulation) {
land->lnd_effic += (s_char)build;
putsect(sp);
}
return 1;
}
/*
* returns the number who starved, if any.
*/
int
feed_land(struct lndstr *lp, register int *vec, int etus, int *needed, int doit)
{
extern double eatrate;
double food_eaten, ship_eaten;
double people_left;
int can_eat, need, svec[I_MAX+1];
int total_people;
int starved;
struct lchrstr *lcp;
struct shpstr *sp;
if (opt_NOFOOD) return 0; /* no food no work to be done */
lcp = &lchr[(int)lp->lnd_type];
food_eaten = (etus * eatrate) * total_mil(lp);
starved = 0;
*needed = 0;
/*
* If we're on a ship, and we don't have enough food,
* get some food off the carrying ship. (Don't starve
* the ship, tho...
*/
/* doit - Only try to take food off the ship during the update */
if ((food_eaten > vec[I_FOOD]) && (lp->lnd_ship >= 0) && doit){
need = (int)food_eaten - vec[I_FOOD];
sp = getshipp(lp->lnd_ship);
getvec(VT_ITEM, svec, (s_char *)sp, EF_SHIP);
ship_eaten = (etus * eatrate) *
(svec[I_CIVIL]+svec[I_MILIT]+svec[I_UW]);
if ((svec[I_FOOD]-need) > ship_eaten){
vec[I_FOOD] += need;
svec[I_FOOD] -= need;
}
else if ((svec[I_FOOD]-ship_eaten) > 0){
vec[I_FOOD] += (svec[I_FOOD] - ship_eaten);
svec[I_FOOD] -= (svec[I_FOOD] - ship_eaten);
}
putvec(VT_ITEM, svec, (s_char *)sp, EF_SHIP);
}
if (food_eaten > vec[I_FOOD]) {
*needed = food_eaten - vec[I_FOOD];
if (*needed < (food_eaten - vec[I_FOOD]))
(*needed)++;
can_eat = (vec[I_FOOD] / (etus * eatrate));
total_people = total_mil(lp);
/* only want to starve off at most 1/2 the populace. */
if (can_eat < (total_people/2))
can_eat = total_people/2;
people_left = (vec[I_FOOD] + 0.01) / (food_eaten + 0.01);
/* only want to starve off at most 1/2 the populace. */
if (people_left < 0.5)
people_left = 0.5;
/* lp->lnd_effic *= people_left;*/
starved = vec[I_MILIT] - (vec[I_MILIT] * people_left);
/* if (!player->simulation)
wu(0, lp->lnd_own, "%d mil starved on unit %s.\n",
starved,
prland(lp));*/
vec[I_MILIT] -= starved;
vec[I_FOOD] = 0;
} else {
vec[I_FOOD] -= (int)food_eaten;
}
return starved;
}

252
src/lib/update/main.c Normal file
View file

@ -0,0 +1,252 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* main.c: World update main function
*
* Known contributors to this file:
* Dave Pare, 1994
* Steve McClure, 1996
* Doug Hay, 1998
*/
#include "misc.h"
#include "nat.h"
#include "file.h"
#include "sect.h"
#include "player.h"
#include "empthread.h"
#include "var.h"
#include "budg.h"
#include "product.h"
#include "player.h"
#include "update.h"
#include "common.h"
#include "optlist.h"
#include <stdlib.h>
#if !defined(_WIN32)
#include <sys/time.h>
#endif
long money[MAXNOC];
long pops[MAXNOC];
long sea_money[MAXNOC];
long lnd_money[MAXNOC];
long air_money[MAXNOC];
long tpops[MAXNOC];
extern int mil_dbl_pay;
int update_pending = 0;
/*ARGSUSED*/
void
update_main(void *argv)
{
extern int etu_per_update;
extern double money_res;
int etu = etu_per_update;
int n;
int x;
int *bp;
int cn,cn2,rel;
struct natstr *cnp;
struct natstr *np;
/* First, make sure all mobility is updated correctly. */
if (opt_MOB_ACCESS) {
mob_ship(etu);
mob_sect(etu);
mob_plane(etu);
mob_land(etu);
}
update_pending = 1;
player->proc = empth_self();
player->cnum = 0;
player->god = 1;
/*
* set up all the variables which get used in the
* sector production routine (for producing education,
* happiness, and printing out the state of the nation)
*/
logerror("production update (%d etus)", etu);
bzero((s_char *)pops, sizeof(pops));
bzero((s_char *)air_money, sizeof(air_money));
bzero((s_char *)sea_money, sizeof(sea_money));
bzero((s_char *)lnd_money, sizeof(lnd_money));
bp = (int *) calloc(WORLD_X * WORLD_Y * 7, sizeof(int));
for (n=0; n<MAXNOC; n++) {
money[n] = 0;
if ((np = getnatp(n)) == (struct natstr *)0)
continue;
money[n] = np->nat_money;
tpops[n] = count_pop(n);
}
logerror("preparing sectors...");
prepare_sects(etu, bp);
logerror("done preparing sectors.");
logerror("producing for countries...");
for (x=0; x<MAXNOC; x++){
int y,z,sb=0,sm=0,pb=0,pm=0,lm=0,lb=0;
long p_sect[SCT_MAXDEF+1][2];
bzero((s_char *)p_sect, sizeof(p_sect));
mil_dbl_pay = 0;
if ((np = getnatp(x)) == (struct natstr *)0)
continue;
if (np->nat_stat & STAT_SANCT ) {
#ifdef DEBUG
logerror("Country %i is in sanctuary and did not update",x);
#endif
continue;
}
np->nat_money += (int) (np->nat_reserve * money_res * etu);
for(y=1; y<SCT_MAXDEF+8; y++) {
for(z=0; z<SCT_MAXDEF+8; z++) {
if (np->nat_priorities[z] == y) {
do_prod(z, etu, x, bp, p_sect,
&sb, &sm, &pb, &pm, &lb, &lm);
}
}
}
/* 0 is maintain, 1 is build */
if (!sm) prod_ship(etu, x, bp, 0);
if (!sb) prod_ship(etu, x, bp, 1);
if (!pm) prod_plane(etu, x, bp, 0);
if (!pb) prod_plane(etu, x, bp, 1);
if (!lm) prod_land(etu, x, bp, 0);
if (!lb) prod_land(etu, x, bp, 1);
/* produce all sects that haven't produced yet */
produce_sect(x, etu, bp, p_sect, -1);
np->nat_money -= p_sect[SCT_CAPIT][1];
}
logerror("done producing for countries.");
finish_sects(etu);
prod_nat(etu);
age_levels(etu);
free(bp);
/*flushwu();*/
if (opt_SLOW_WAR) {
/* Update war declarations */
/* MOBILIZATION->SITZKRIEG->AT_WAR */
for (cn=1; cn < MAXNOC; cn++) {
if ((cnp = getnatp(cn)) == 0)
break;
for (cn2=1; cn2 < MAXNOC; cn2++) {
if (cn2 == cn)
continue;
rel=getrel(cnp,cn2);
if (rel == MOBILIZATION){
rel = SITZKRIEG;
setrel(cn,cn2,rel);
}
else if (rel == SITZKRIEG){
rel = AT_WAR;
setrel(cn,cn2,rel);
}
}
}
}
/* Age contact */
if (opt_LOSE_CONTACT) {
for (cn=1; cn<MAXNOC; cn++) {
if ((cnp = getnatp(cn)) != NULL) agecontact(cnp);
}
}
/* Only update mobility for non-MOB_ACCESS here, since it doesn't
get done for MOB_ACCESS anyway during the update */
if (!opt_MOB_ACCESS) {
mob_ship(etu);
mob_sect(etu);
mob_plane(etu);
mob_land(etu);
}
if (opt_DEMANDUPDATE)
update_removewants();
/* flush all mem file objects to disk */
ef_flush(EF_NATION);
ef_flush(EF_SECTOR);
ef_flush(EF_SHIP);
ef_flush(EF_PLANE);
ef_flush(EF_LAND);
delete_old_announcements();
/* Clear all the telegram flags */
for (cn = 0; cn < MAXNOC; cn++)
clear_telegram_is_new(cn);
update_pending = 0;
logerror("End update");
player_delete(player);
empth_exit();
/*NOTREACHED*/
}
void
do_prod(int sector_type, int etu, int n, int *bp, long int (*p_sect)[2], int *ship_build, int *ship_maint, int *plane_build, int *plane_maint, int *land_build, int *land_maint)
{
extern double money_mil;
struct natstr *np;
np = getnatp(n);
if (sector_type == PRI_SMAINT){
prod_ship(etu,n,bp,0);
*ship_maint=1;
}
else
if (sector_type == PRI_SBUILD){
prod_ship(etu,n,bp,1);
*ship_build=1;
}
else
if (sector_type == PRI_PMAINT){
prod_plane(etu,n,bp,0);
*plane_maint=1;
}
else
if (sector_type == PRI_PBUILD){
prod_plane(etu,n,bp,1);
*plane_build=1;
}
else
if (sector_type == PRI_LMAINT){
if (*land_build)
np->nat_money -= (int) (money_mil * etu * mil_dbl_pay);
prod_land(etu,n,bp,0);
*land_maint=1;
}
else
if (sector_type == PRI_LBUILD){
prod_land(etu,n,bp,1);
*land_build=1;
}
else {
produce_sect(n,etu,bp,p_sect,sector_type);
}
}

93
src/lib/update/material.c Normal file
View file

@ -0,0 +1,93 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* material.c: Tries to find materials for production
*
* Known contributors to this file:
* Ville Virrankoski, 1996
*/
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "file.h"
#include "optlist.h"
#include "budg.h"
#include "player.h"
#include "update.h"
#include "common.h"
#include "subs.h"
#ifndef MIN
#define MIN(x,y) ((x) > (y) ? (y) : (x))
#endif
void
get_materials(struct sctstr *sp, int *bp, int *mvec, int check)
/* only check if found=0, remove them=1 */
{
struct sctstr *usp;
int i;
int used_already;
int still_left;
int svec[I_MAX+1];
getvec(VT_ITEM, svec, (s_char *)sp, EF_SECTOR);
for(i=1;i<=I_MAX;i++) {
if (mvec[i]==0)
continue;
usp = sp;
if (check) {
still_left = gt_bg_nmbr(bp, sp, i);
if ((still_left - mvec[i])<0)
still_left = 0;
else
still_left -= mvec[i];
if (opt_GRAB_THINGS)
mvec[i] = supply_commod(usp->sct_own, usp->sct_x, usp->sct_y,
i, mvec[i]);
pt_bg_nmbr(bp, sp, i, still_left);
svec[i] = still_left;
if (!player->simulation)
putvec(VT_ITEM, svec, (s_char *)sp, EF_SECTOR);
} else {
if (opt_GRAB_THINGS) {
used_already = svec[i] - gt_bg_nmbr(bp, sp, i);
mvec[i] = try_supply_commod(usp->sct_own, usp->sct_x, usp->sct_y,
i, (mvec[i] + used_already));
mvec[i] -= used_already;
} else { /* ! GRAB_THINGS */
still_left = gt_bg_nmbr(bp, sp, i);
mvec[i] = MIN(mvec[i], still_left);
}
}
}
}

563
src/lib/update/mobility.c Normal file
View file

@ -0,0 +1,563 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* mobility.c: Add mobility to each of the items which accumulate mobility.
*
* Known contributors to this file:
* Dave Pare, 1986
* Steve McClure, 1998-1999
*/
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "ship.h"
#include "land.h"
#include "plane.h"
#include "nat.h"
#include "file.h"
#include "optlist.h"
#include "mission.h"
#include "update.h"
#include "gen.h"
#include "subs.h"
#include "optlist.h"
extern int timestamp_fixing;
extern int update_pending;
int do_upd_checking = 0;
int
increase_mob(time_t *counter, float mult)
{
time_t secs;
time_t now;
time_t left;
extern long s_p_etu;
extern int updating_mob;
int newetus;
float newmob;
int inewmob;
time(&now);
secs = now - *counter;
if (secs < 1 || secs < s_p_etu)
return 0;
newetus = (int)(secs / s_p_etu);
if (newetus < 1)
return 0;
left = (secs % s_p_etu);
do {
newmob = (float)(newetus * mult);
inewmob = (int)(newetus * mult);
if (newmob == inewmob || newetus > 7)
break;
newetus--;
left += s_p_etu;
} while (newetus > 0);
if (newetus <= 0)
return 0;
time(counter);
*counter = *counter - left;
if (updating_mob)
return (newetus);
return 0;
}
void
update_timestamps(time_t lastsavedtime)
{
struct shpstr *shipp;
struct sctstr *sectp;
struct lndstr *landp;
struct plnstr *planep;
int n;
time_t now;
time_t delta;
timestamp_fixing = 1;
time(&now);
delta = now - lastsavedtime;
for (n = 0; (shipp = getshipp(n)); n++)
shipp->shp_access += delta;
for (n = 0; (sectp = getsectid(n)); n++)
sectp->sct_access += delta;
for (n = 0; (landp = getlandp(n)); n++)
landp->lnd_access += delta;
for (n = 0; (planep = getplanep(n)); n++)
planep->pln_access += delta;
timestamp_fixing = 0;
}
void
update_all_mob(void)
{
struct shpstr *shipp;
struct sctstr *sectp;
struct lndstr *landp;
struct plnstr *planep;
int n;
n = 0;
while (1) {
do_upd_checking = 1;
shipp = getshipp(n);
sectp = getsectid(n);
landp = getlandp(n);
planep = getplanep(n);
do_upd_checking = 0;
if (shipp)
shp_do_upd_mob(shipp);
if (sectp)
sct_do_upd_mob(sectp);
if (landp)
lnd_do_upd_mob(landp);
if (planep)
pln_do_upd_mob(planep);
if (!shipp && !sectp && !landp && !planep)
break;
n++;
}
do_upd_checking = 0;
}
void
sct_do_upd_mob(register struct sctstr *sp)
{
extern float sect_mob_scale;
int etus;
if (do_upd_checking || timestamp_fixing || update_pending)
return;
if (sp->sct_own == 0)
return;
if (sp->sct_type == SCT_SANCT)
return;
if ((etus = increase_mob(&sp->sct_access, sect_mob_scale)) == 0)
return;
do_upd_checking = 1;
do_mob_sect(sp, etus);
/* putsect(sp);*/
do_upd_checking = 0;
}
void
shp_do_upd_mob(register struct shpstr *sp)
{
extern float ship_mob_scale;
int etus;
if (do_upd_checking || timestamp_fixing || update_pending)
return;
if (sp->shp_own == 0)
return;
if ((etus = increase_mob(&sp->shp_access, ship_mob_scale)) == 0)
return;
do_upd_checking = 1;
do_mob_ship(sp, etus);
do_upd_checking = 0;
}
void
lnd_do_upd_mob(register struct lndstr *lp)
{
extern float land_mob_scale;
int etus;
if (do_upd_checking || timestamp_fixing || update_pending)
return;
if (lp->lnd_own == 0)
return;
if ((etus = increase_mob(&lp->lnd_access, land_mob_scale)) == 0)
return;
do_upd_checking = 1;
do_mob_land(lp, etus);
do_upd_checking = 0;
}
void
pln_do_upd_mob(register struct plnstr *pp)
{
extern float plane_mob_scale;
int etus;
if (do_upd_checking || timestamp_fixing || update_pending)
return;
if (pp->pln_own == 0)
return;
if ((etus = increase_mob(&pp->pln_access, plane_mob_scale)) == 0)
return;
do_upd_checking = 1;
do_mob_plane(pp, etus);
do_upd_checking = 0;
}
void
mob_sect(register int etus)
{
register struct sctstr *sp;
register int n;
time_t now;
time(&now);
for (n=0; NULL != (sp = getsectid(n)); n++) {
sp->sct_timestamp = now;
if (opt_MOB_ACCESS)
sct_do_upd_mob(sp);
else
do_mob_sect(sp, etus);
}
}
void
do_mob_sect(register struct sctstr *sp, register int etus)
{
extern float sect_mob_scale;
extern int sect_mob_max;
register int value;
if (sp->sct_own == 0)
return;
if (sp->sct_type == SCT_SANCT)
return;
/* Do we have to even bother? */
if (sp->sct_mobil >= sect_mob_max) {
/* No, so set just in case and then return */
sp->sct_mobil = sect_mob_max;
return;
}
value = sp->sct_mobil + ((float)etus * sect_mob_scale);
if (value > sect_mob_max)
value = sect_mob_max;
sp->sct_mobil = value;
}
void
mob_ship(register int etus)
{
register struct shpstr *sp;
register int n;
time_t now;
time(&now);
for (n=0; NULL != (sp = getshipp(n)); n++) {
sp->shp_timestamp = now;
if (opt_MOB_ACCESS)
shp_do_upd_mob(sp);
else
do_mob_ship(sp, etus);
}
}
void
do_mob_ship(register struct shpstr *sp, register int etus)
{
extern int ship_mob_max;
extern float ship_mob_scale;
int newfuel=0;
register int value;
int can_add,have_fuel_for,total_add;
double d;
extern int fuel_mult;
if (sp->shp_own == 0)
return;
/* Do we even have to bother updating this mobility? */
if (sp->shp_mobil >= ship_mob_max) {
/* No, so don't. Just set it to max (just in case) and
return. */
sp->shp_mobil = ship_mob_max;
return;
}
if (opt_FUEL == 0) { /* only a bit to do ... */
value = sp->shp_mobil + ((float)etus * ship_mob_scale);
if (value > ship_mob_max)
value = ship_mob_max;
sp->shp_mobil = value;
return; /* so we ship the FUEL stuff */
}
/* opt_FUEL in force */
if (mchr[(int)sp->shp_type].m_fuelu == 0) {
value = sp->shp_mobil + ((float)etus * ship_mob_scale);
if (value > ship_mob_max)
value = ship_mob_max;
sp->shp_mobil = (s_char)value;
} else {
can_add = ship_mob_max - sp->shp_mobil;
if (can_add > ((float)etus*ship_mob_scale))
can_add = ((float)etus*ship_mob_scale);
have_fuel_for = ldround((((double)sp->shp_fuel /
(double)mchr[(int)sp->shp_type].m_fuelu)*
(double)fuel_mult),1);
if (can_add > have_fuel_for){
int need;
need = can_add - have_fuel_for;
d = (double)need;
d *= (double)mchr[(int)sp->shp_type].m_fuelu;
d /= (double)fuel_mult;
d /= 5.0;
if ((d-(int)d) > 0.0)
d++;
need = (int)d;
newfuel = supply_commod(sp->shp_own,sp->shp_x,
sp->shp_y,I_PETROL,need);
sp->shp_fuel += (u_char)(newfuel * 5);
}
have_fuel_for = ldround((((double)sp->shp_fuel /
(double)mchr[(int)sp->shp_type].m_fuelu)*
(double)fuel_mult),1);
if (can_add > have_fuel_for){
int need;
need = can_add - have_fuel_for;
d = (double)need;
d *= (double)mchr[(int)sp->shp_type].m_fuelu;
d /= (double)fuel_mult;
d /= 50.0;
if ((d-(int)d) > 0.0)
d++;
need = (int)d;
newfuel = supply_commod(sp->shp_own,sp->shp_x,
sp->shp_y,I_OIL,need);
sp->shp_fuel += (u_char)(newfuel * 50);
}
have_fuel_for = ldround((((double)sp->shp_fuel /
(double)mchr[(int)sp->shp_type].m_fuelu)*
(double)fuel_mult),1);
if (can_add > have_fuel_for)
total_add = have_fuel_for;
else
total_add = can_add;
d = (double)total_add;
d *= (double)mchr[(int)sp->shp_type].m_fuelu;
d /= (double)fuel_mult;
sp->shp_fuel -= (u_char)ldround(d,1);
sp->shp_fuel = (u_char)min(sp->shp_fuel,
mchr[(int)sp->shp_type].m_fuelc);
sp->shp_mobil += (s_char)total_add;
}
}
void
mob_land(register int etus)
{
register struct lndstr *lp;
register int n;
time_t now;
time(&now);
for (n=0; NULL != (lp = getlandp(n)); n++) {
lp->lnd_timestamp = now;
if (opt_MOB_ACCESS)
lnd_do_upd_mob(lp);
else
do_mob_land(lp, etus);
}
}
void
do_mob_land(register struct lndstr *lp, register int etus)
{
extern int land_mob_max;
extern float land_mob_scale;
int newfuel=0;
register int value;
int can_add,have_fuel_for,total_add;
double d;
extern int fuel_mult;
if (lp->lnd_own == 0)
return;
if (lp->lnd_mobil >= land_mob_max) {
lp->lnd_mobil = land_mob_max;
return;
}
/*
* Give damaged units a break. When at low
* efficiency, units can go to -100 mob when
* marching 1 step, making them slower than
* normal mil. This helps take the curse off.
* If MOB_ACCESS is on, we don't do this, as it would
* be too much of an advantage. So, we just add double
* the small amount of mob if we are < 0 instead.
*/
if (!opt_MOB_ACCESS) {
if (lp->lnd_mobil < 0)
lp->lnd_mobil /= 2;
}
if (opt_FUEL == 0) { /* just some bits and pieces */
if (opt_MOB_ACCESS) {
if (lp->lnd_mobil < 0)
value = lp->lnd_mobil + (2 * ((float)etus * land_mob_scale));
else
value = lp->lnd_mobil + ((float)etus * land_mob_scale);
} else {
value = lp->lnd_mobil + ((float)etus * land_mob_scale);
}
if (value > land_mob_max)
value = land_mob_max;
lp->lnd_mobil = value;
return; /* Done! */
}
/* opt_FUEL in force ... */
if (lp->lnd_fuelu == 0){
if (opt_MOB_ACCESS) {
if (lp->lnd_mobil < 0)
value = lp->lnd_mobil + (2 * ((float)etus * land_mob_scale));
else
value = lp->lnd_mobil + ((float)etus * land_mob_scale);
} else {
value = lp->lnd_mobil + ((float)etus * land_mob_scale);
}
if (value > land_mob_max)
value = land_mob_max;
lp->lnd_mobil = value;
} else {
can_add = land_mob_max - lp->lnd_mobil;
if (can_add > ((float)etus*land_mob_scale))
can_add = ((float)etus*land_mob_scale);
have_fuel_for = (lp->lnd_fuel /
lp->lnd_fuelu)*fuel_mult;
if (can_add > have_fuel_for){
int need;
need = can_add - have_fuel_for;
d = (double)need;
d *= (double)lp->lnd_fuelu;
d /= (double)fuel_mult;
d /= 5.0;
if ((d-(int)d) > 0.0)
d++;
need = (int)d;
newfuel = supply_commod(lp->lnd_own,lp->lnd_x,
lp->lnd_y,I_PETROL,need);
lp->lnd_fuel += (u_char)(newfuel * 5);
}
have_fuel_for = (lp->lnd_fuel /
lp->lnd_fuelu)*fuel_mult;
if (can_add > have_fuel_for){
int need;
need = can_add - have_fuel_for;
d = (double)need;
d *= (double)lp->lnd_fuelu;
d /= (double)fuel_mult;
d /= 50.0;
if ((d-(int)d) > 0.0)
d++;
need = (int)d;
newfuel = supply_commod(lp->lnd_own,lp->lnd_x,
lp->lnd_y,I_OIL,need);
lp->lnd_fuel += (u_char)(newfuel * 50);
}
have_fuel_for = (lp->lnd_fuel /
lp->lnd_fuelu)*fuel_mult;
if (can_add > have_fuel_for){
total_add = have_fuel_for;
}
else
total_add = can_add;
d = (double)total_add;
d *= (double)lp->lnd_fuelu;
d /= (double)fuel_mult;
lp->lnd_fuel -= (u_char)ldround(d,1);
lp->lnd_fuel = (u_char)min(lp->lnd_fuel,
lp->lnd_fuelc);
if(total_add + lp->lnd_mobil > land_mob_max) {
total_add = land_mob_max - lp->lnd_mobil;
}
if (opt_MOB_ACCESS) {
if (lp->lnd_mobil < 0)
lp->lnd_mobil += (s_char)total_add;
}
lp->lnd_mobil += (s_char)total_add;
}
}
void
mob_plane(register int etus)
{
register struct plnstr *pp;
register int n;
time_t now;
time(&now);
for (n=0; NULL != (pp = getplanep(n)); n++) {
pp->pln_timestamp = now;
if (opt_MOB_ACCESS)
pln_do_upd_mob(pp);
else
do_mob_plane(pp, etus);
}
}
void
do_mob_plane(register struct plnstr *pp, register int etus)
{
extern int plane_mob_max;
extern float plane_mob_scale;
register int value;
if (pp->pln_own == 0)
return;
if (pp->pln_mobil >= plane_mob_max) {
pp->pln_mobil = plane_mob_max;
return;
}
value = pp->pln_mobil + ((float)etus * plane_mob_scale);
if (value > plane_mob_max)
value = plane_mob_max;
pp->pln_mobil = value;
}

93
src/lib/update/move_sat.c Normal file
View file

@ -0,0 +1,93 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* move_sat.c: Move a satellite to the next point in it's orbit.
*
* Known contributors to this file:
*
*/
#include <math.h>
#include "misc.h"
#include "var.h"
#include "plane.h"
#include "sect.h"
#include "xy.h"
#include "nsc.h"
#include "nat.h"
#include "path.h"
#include "deity.h"
#include "file.h"
#include "update.h"
#include "subs.h"
#include "optlist.h"
#ifndef PI
#define PI 3.14159265358979323846
#endif
void
move_sat(register struct plnstr *pp)
{
coord x1,y1,x2,y2;
coord dx,dy;
float newtheta;
struct sctstr sect;
newtheta = pp->pln_theta + .05;
if (newtheta >= 1.0)
{
newtheta -= 1.0;
}
x1 = (coord)(2 * pp->pln_theta * WORLD_X);
x1 = xnorm(x1);
y1 = (coord)(sin(6 * PI * pp->pln_theta) * (WORLD_Y / 4));
x2 = (coord)(2 * newtheta * WORLD_X);
x2 = xnorm(x2);
y2 = (coord)(sin(6 * PI * newtheta) * (WORLD_Y / 4));
dx = x1 - pp->pln_x;
dy = y1 - pp->pln_y;
x2 -= dx;
y2 -= dy;
if ((x2 + y2) & 1)
{
x2++;
}
pp->pln_x = xnorm(x2);
pp->pln_y = ynorm(y2);
pp->pln_theta = newtheta;
getsect(pp->pln_x, pp->pln_y, &sect);
if (sect.sct_own)
if (pp->pln_own != sect.sct_own)
wu(0, sect.sct_own, "%s satellite spotted over %s\n",
cname(pp->pln_own), xyas(pp->pln_x, pp->pln_y, sect.sct_own));
return;
}

309
src/lib/update/nat.c Normal file
View file

@ -0,0 +1,309 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* nat.c: Accumulate tech, edu, research and happiness.
*
* Known contributors to this file:
* Dave Pare, 1989
* Steve McClure, 1997
*/
#include <math.h>
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "nat.h"
#include "item.h"
#include "news.h"
#include "file.h"
#include "xy.h"
#include "optlist.h"
#include "update.h"
#include "subs.h"
float levels[MAXNOC][4];
/*
* hap and edu avg mean that the weight on current happiness is
* (cur_hap * hap_avg + hap_prod * etu) / (hap_avg + etu);
* same for education.
* right now, happiness has 1 day (48 etu) average, prod of 10 from
* initial level of 0 yields (1) 1.42, (6) 6.03, (12) 8.42, (18) 9.37
*
* education has 4 day (192 etu) average, prod of 10 from initial
* level of 0 yields (1) 0.4, (6) 2.2, (12) 3.9, (18) 5.2.
*/
extern float hap_avg;
extern float edu_avg;
extern float ally_factor;
/*
* for values below the "easy level" values, production is
* as normal. For values above "easy", production gets harder
* based on an equation in "limit_level()" in update/nat.c.
* Basically, the smaller the the values for "level_log", the
* smaller return on investment above level_easy[] values.
*/
/*
* Damn! I hate this, but ...
* The values here for tech are *not* the real ones.
* They are changed later in the limit_level routine.
*/
/*tech res edu hap */
float level_easy[4] = { 0.75, 0.75, 5.00, 5.00 };
float level_log[4] = { 1.75, 2.00, 4.00, 6.00 };
/*
* technique to limit the sharpers who turn entire countries
* into tech plants overnight...
*/
double
logx(double d, double base)
{
if (base == 1.0)
return d;
return log10(d) / log10(base);
}
double
limit_level(double level, int type, int flag)
{
double above_easy;
double above;
double logbase;
double easy;
/*
* Begin ugly hack.
*/
extern float easy_tech, tech_log_base;
level_easy[0] = easy_tech;
level_log[0] = tech_log_base;
/*
* End ugly hack.
*/
if (level > level_easy[type]) {
logbase = level_log[type];
easy = level_easy[type];
above_easy = level - easy;
if (flag)
above = above_easy / logx(logbase + above_easy,logbase);
else
above = logx(above_easy + 1.0, logbase);
if (above > 250) above = 250;
return ((above) < 0) ? easy : (easy + above);
} else
return level;
}
void
prod_nat(int etu)
{
extern long money[MAXNOC];
extern long pops[MAXNOC];
extern double hap_cons, edu_cons;
extern long sea_money[MAXNOC];
extern long lnd_money[MAXNOC];
extern long air_money[MAXNOC];
struct natstr *np;
float hap;
float edu;
float hap_edu;
long pop;
double rlev;
double tlev;
double tech[MAXNOC];
double res[MAXNOC];
double newvalue;
natid n;
int cn,cont;
for (n=0; NULL != (np = getnatp(n)); n++) {
if ((np->nat_stat & STAT_NORM) == 0)
continue;
/*
* hap_edu: the more education people have, the
* more happiness they want.
*/
hap_edu = np->nat_level[NAT_ELEV];
hap_edu = 1.5 - ((hap_edu + 10.0) / (hap_edu + 20.0));
pop = pops[n] + 1;
/*
* get per-population happiness and education
* see what the total per-civilian production is
* for this time period.
*/
hap = levels[n][NAT_HLEV] * hap_edu * hap_cons /
((float)pop * etu);
edu = levels[n][NAT_ELEV] * edu_cons /
((float)pop * etu);
wu((natid)0, n, "%3.0f happiness, %3.0f education produced\n",
levels[n][NAT_HLEV], levels[n][NAT_ELEV]);
hap = limit_level(hap, NAT_HLEV, 1);
edu = limit_level(edu, NAT_ELEV, 1);
/*
* change the "moving average"...old happiness and
* education levels are weighted heavier than current
* production.
*/
newvalue = (np->nat_level[NAT_HLEV] * hap_avg + hap * etu) /
(hap_avg + etu);
np->nat_level[NAT_HLEV] = newvalue;
newvalue = (np->nat_level[NAT_ELEV] * edu_avg + edu * etu) /
(edu_avg + etu);
np->nat_level[NAT_ELEV] = newvalue;
/*
* limit tech/research production
*/
levels[n][NAT_TLEV] =
limit_level(levels[n][NAT_TLEV] / 1,
NAT_TLEV, 0) * 1;
levels[n][NAT_RLEV] =
limit_level(levels[n][NAT_RLEV] / 1,
NAT_RLEV, 0) * 1;
wu((natid)0, n,
"total pop is %d, yielding %4.2f hap, %4.2f edu\n",
pop - 1, hap, edu);
}
if (ally_factor > 0.0)
share_incr(res, tech);
else {
bzero((s_char *)res, sizeof(res));
bzero((s_char *)tech, sizeof(tech));
}
for (n=0; NULL != (np = getnatp(n)); n++) {
if ((np->nat_stat & STAT_NORM) == 0)
continue;
tlev = levels[n][NAT_TLEV];
rlev = levels[n][NAT_RLEV];
if (tech[n] != 0.0 || res[n] != 0.0) {
wu((natid)0, n,
"%5.4f technology (%5.4f + %5.4f), ",
tlev + tech[n], tlev, tech[n]);
wu((natid)0, n,
"%5.4f research (%5.4f + %5.4f) produced\n",
rlev + res[n], rlev, res[n]);
} else
wu((natid)0, n,
"%5.4f tech, %5.4f research produced\n",
tlev, rlev);
rlev += res[n];
tlev += tech[n];
if (rlev != 0.0)
np->nat_level[NAT_RLEV] += rlev;
if (tlev != 0.0)
np->nat_level[NAT_TLEV] += tlev;
if ((sea_money[n] != 0) || (air_money[n] != 0) ||
(lnd_money[n] != 0))
wu((natid)0, n,
"Army delta $%d, Navy delta $%d, Air force delta $%d\n",
lnd_money[n], sea_money[n], air_money[n]);
wu((natid)0, n, "money delta was $%d for this update\n",
np->nat_money - money[n]);
if (opt_LOSE_CONTACT) {
for (cn=0; cn <= MAXNOC; cn++) {
cont = getcontact(np, cn);
if (cont > 0) {
logerror ("country %d at level %d with country %d.\n", n, cont, cn);
setcont(n, cn, cont-1);
}
}
}
}
}
/*
* find out everyones increment
*/
void
share_incr(register double *res, register double *tech)
{
register struct natstr *np;
register struct natstr *other;
register natid i;
register natid j;
int rnc;
int tnc;
for (i=0; NULL != (np = getnatp(i)); i++) {
res[i] = tech[i] = 0.0;
if ((np->nat_stat & STAT_INUSE) == 0)
continue;
if (np->nat_stat & STAT_GOD)
continue;
if (np->nat_stat == VIS)
continue;
rnc = tnc = 0;
for (j=0; NULL != (other = getnatp(j)); j++) {
if (j == i)
continue;
if (other->nat_stat & STAT_GOD)
continue;
if (other->nat_stat == VIS)
continue;
if ((other->nat_stat & STAT_INUSE) == 0)
continue;
if (opt_HIDDEN) {
if (!getcontact(np, j))
continue;
}
if (!opt_ALL_BLEED) {
if (getrel(np, j) != ALLIED)
continue;
if (getrel(other, i) != ALLIED)
continue;
res[i] += levels[j][NAT_RLEV];
tech[i] += levels[j][NAT_TLEV];
rnc++;
tnc++;
} else {
if (levels[j][NAT_TLEV] > 0.001) {
tech[i] += levels[j][NAT_TLEV];
tnc++;
}
if (levels[j][NAT_RLEV] > 0.001) {
res[i] += levels[j][NAT_RLEV];
rnc++;
}
}
}
if (rnc == 0 && tnc == 0)
continue;
if (rnc > 0) {
res[i] /= rnc * ally_factor;
}
if (tnc > 0) {
tech[i] /= tnc * ally_factor;
}
/* logerror("Country #%d gets %g res from %d allies, %g tech from %d allies", i, res[i], rnc, tech[i], tnc);*/
}
}

373
src/lib/update/nav_ship.c Normal file
View file

@ -0,0 +1,373 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* nav_ship.c: Navigate ships and such
*
* Known contributors to this file:
* Chad Zabel, 1994
* Ken Stevens, 1995
*/
#include "misc.h"
#include <ctype.h>
#include "var.h"
#include "ship.h"
#include "sect.h"
#include "news.h"
#include "xy.h"
#include "nsc.h"
#include "nat.h"
#include "path.h"
#include "deity.h"
#include "file.h"
#include "item.h"
#include "optlist.h"
#include "player.h"
#include "update.h"
#include "subs.h"
#include "common.h"
#include <stdlib.h>
extern int check_nav(struct sctstr *sect);
void
scuttle_it(register struct shpstr *sp)
{
struct sctstr *sectp;
sp->shp_autonav &= ~AN_SCUTTLE;
if (!(sectp = getsectp(sp->shp_x,sp->shp_y))) {
wu(0, 0, "bad sector (%d,%d) ship %d\n", sp->shp_x, sp->shp_y,
sp->shp_uid);
return;
}
if (sectp->sct_type != SCT_HARBR || sectp->sct_effic < 2) {
wu(0, sp->shp_own,
"%s is not in a harbor at least 2%% eff! Not scuttling.\n",
prship(sp));
return;
}
if (opt_TRADESHIPS) {
if (!(mchr[(int)sp->shp_type].m_flags & M_TRADE)) {
wu(0, sp->shp_own,
"You can only autoscuttle trade ships!\n");
return;
}
}
wu(0, sp->shp_own, "Scuttling %s in sector %s\n",
prship(sp),
xyas(sp->shp_x, sp->shp_y, sp->shp_own));
if (opt_TRADESHIPS) {
scuttle_tradeship(sp, 0);
}
scuttle_ship(sp);
}
static void
nav_check_atdest(register struct shpstr *sp, struct mchrstr *mcp)
{
if ((sp->shp_x == sp->shp_destx[0]) &&
(sp->shp_y == sp->shp_desty[0])) {
if ((sp->shp_destx[0] == sp->shp_destx[1]) &&
(sp->shp_desty[0] == sp->shp_desty[1])) {
/* End of road */
sp->shp_autonav &= ~AN_AUTONAV;
wu(0, sp->shp_own, "%s arrived at %s, finished\n",
prship(sp),
xyas(sp->shp_x,sp->shp_y,sp->shp_own));
if (sp->shp_autonav & AN_SCUTTLE) {
scuttle_it(sp);
}
} else {
/* unload all cargo */
unload_it(sp);
wu(0, sp->shp_own, "%s arrived at %s\n",
prship(sp),
xyas(sp->shp_x,sp->shp_y,sp->shp_own));
/* Swap */
swap(sp);
}
} else
sp->shp_autonav &= ~AN_LOADING;
}
/* flip the 2 fields that deal with autonav movement. */
/* CZ 6/1/94 */
void
swap(register struct shpstr *sp)
{
coord tcord;
s_char tcomm[TMAX];
short lev[TMAX];
int i;
tcord = sp->shp_destx[0];
sp->shp_destx[0] = sp->shp_destx[1];
sp->shp_destx[1] = tcord;
tcord = sp->shp_desty[0];
sp->shp_desty[0] = sp->shp_desty[1];
sp->shp_desty[1] = tcord;
for (i=0;i<TMAX;++i){
lev[i] = sp->shp_lstart[i];
tcomm[i] = sp->shp_tstart[i]; }
for (i=0;i<TMAX;++i) {
sp->shp_lstart[i] = sp->shp_lend[i];
sp->shp_tstart[i] = sp->shp_tend[i]; }
for (i=0;i<TMAX;++i) {
sp->shp_lend[i] = lev[i];
sp->shp_tend[i] = tcomm[i]; }
/* set load bit */
sp->shp_autonav |= AN_LOADING;
}
/* New Autonav code.
* Chad Zabel
* 6-1-94
*/
static int
nav_loadship(register struct shpstr *sp, natid cnum)
{
struct sctstr *sectp;
s_char item;
int i,
landown,
shipown,
level,
didsomething[TMAX],
rel;
for (i=0;i<TMAX;i++)
didsomething[i]=0;
/* Turn off the loading flag.
* if any of the loads fail on the ship
* it will be turned back on.
*/
sp->shp_autonav &= ~AN_LOADING;
if (!(sectp = getsectp(sp->shp_x,sp->shp_y)))
return RET_SYS; /* safety */
/* I suspect RET_SYS isn't really what you want here --dfp */
landown = sectp->sct_own;
shipown = sp->shp_own;
rel = getrel(getnatp(sectp->sct_own),cnum);
/* loop through each field for that ship */
for (i=0;i<TMAX;++i) {
item = sp->shp_tend[i]; /* commodity */
level = sp->shp_lend[i]; /* amount */
/* check and see if the data fields have been set. */
if (item == ' ' || level == 0) {
/* nothing to do move on. */
didsomething[i] = 1;
continue;
}
if (landown == 0) {
/* either sea or deity harbor */
didsomething[i] = 1;
continue;
}
if (sectp->sct_type != SCT_HARBR &&
(!opt_BIG_CITY || sectp->sct_type != SCT_CAPIT)) {
/* we can only load in harbors */
didsomething[i] = 1;
continue;
}
if (landown == shipown || rel >= FRIENDLY)
didsomething[i] = load_it(sp,sectp,i);
}
/* check for any unsucessful loads */
/* if we have any return 0 to stop */
/* the nav_ship loop. */
for (i=0;i<TMAX;i++) {
if(didsomething[i] == 0)
return 0;
}
/* All loads were succesful */
return 1;
}
/* new autonav code.
*
* 1. Try and move to the next sector/harbor given by the player.
* 2. Once we reach a harbor try and load all cargo holds for that ship.
* 3. If the ship reaches its max levels set by the player try to use
* up all mobility getting to the next harbor.
* Continue to loop until the ship runs out of mobility, a load fails,
* the ship gets sunk (forts,ect..), the ship hits a mine.
*
* A check has been added for fuel so ships don't end up running
* out of mobility in the ocean.
*
* Questions, bugs (fixes) , or new ideas should be directed at
* Chad Zabel.
* 6-1-94
* Modified to use shp_nav by Ken Stevens 1995
*/
int
nav_ship(register struct shpstr *sp)
{
extern double techfact(int, double);
struct sctstr *sectp;
s_char *cp,item;
int stopping;
int quit;
int didsomething = 0;
int max_amt, food_amt, comm;
s_char buf[1024];
struct emp_qelem ship_list;
struct emp_qelem *qp, *newqp;
struct mlist *mlp;
int dummyint;
double dummydouble;
int dir;
natid cnum;
struct mchrstr *mcp, *vship;
/* just return if no autonaving to do for this ship */
if (!(sp->shp_autonav & AN_AUTONAV) || (sp->shp_autonav & AN_STANDBY))
return RET_OK;
cnum = sp->shp_own;
vship = mcp = &mchr[(int)sp->shp_type];
/* Make a list of one ships so we can use the navi.c code */
emp_initque(&ship_list);
mlp = (struct mlist *) malloc(sizeof(struct mlist));
mlp->mcp = mchr + sp->shp_type;
bcopy((s_char *)sp, (s_char *)&mlp->ship, sizeof(struct shpstr));
mlp->mobil = (double)sp->shp_mobil;
emp_insque(&mlp->queue, &ship_list);
quit = 1; /* setup loop, we want to check it 1 time. */
do {
if ((sp->shp_mobil > 0) && (!(sp->shp_autonav & AN_LOADING)) &&
(!(sp->shp_autonav & AN_STANDBY))) {
shp_nav(&ship_list, &dummydouble, &dummydouble, &dummyint,
sp->shp_own);
if (QEMPTY(&ship_list))
return RET_OK;
/* before we move check to see if ship needs fuel. */
sectp = getsectp(sp->shp_x,sp->shp_y);
if (opt_FUEL &&
sectp->sct_own != 0 &&
sp->shp_fuel <= 0 &&
mlp->mcp->m_fuelu != 0)
auto_fuel_ship(sp);
mlp->ship.shp_fuel = sp->shp_fuel;
cp = BestShipPath(buf, sp->shp_x, sp->shp_y,
sp->shp_destx[0], sp->shp_desty[0],
sp->shp_own);
if (cp == 0 || (*cp == '\0') || (*cp == '?')) {
wu(0, cnum,
"%s bad path, ship put on standby\n",
prship(sp));
sp->shp_autonav |= AN_STANDBY;
putship(sp->shp_uid, (s_char *)sp);
/* We need to free the ship list */
qp = ship_list.q_forw;
while (qp != &(ship_list)) {
newqp = qp->q_forw;
emp_remque(qp);
free((s_char *)qp);
qp = newqp;
}
return RET_SYN;
}
stopping = 0;
while (*cp && !stopping && sp->shp_own &&
mlp->mobil > 0.0) {
dir = chkdir(*cp++, DIR_STOP, DIR_LAST);
stopping |= shp_nav_one_sector(&ship_list, dir,
sp->shp_own, 0);
}
/* sp->shp_mobil = (int) mobil;
*/
/* Ship not sunk */
if (sp->shp_own)
nav_check_atdest(sp, mcp);
}
quit = 0; /* stop loop */
/* Try to load the ship */
if (sp->shp_autonav & AN_LOADING) {
didsomething = nav_loadship(sp, cnum);
if (didsomething)
quit = 1;
}
/* special case for fishing boats */
if ((mchr[(int)sp->shp_type].m_flags & M_FOOD) == 1) {
item = (s_char)'f';
comm = com_num(&item);
food_amt=getvar(comm,(s_char *) sp, EF_SHIP);
max_amt=(vl_find(comm,vship->m_vtype,
vship->m_vamt,
(int) vship->m_nv));
sectp=getsectp(sp->shp_x,sp->shp_y);
if (food_amt<max_amt && (sectp->sct_own==0))
quit=0;
}
/* reset flag and check if we can move. */
} while (quit); /* end loop */
putship(sp->shp_uid, sp);
/* We need to free the ship list (just in case) */
qp = ship_list.q_forw;
while (qp != &(ship_list)) {
newqp = qp->q_forw;
emp_remque(qp);
free((s_char *)qp);
qp = newqp;
}
return RET_OK;
}

310
src/lib/update/nav_util.c Normal file
View file

@ -0,0 +1,310 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* nav_util.c: Utilities for autonav and sail
*
* Known contributors to this file:
*
*/
#include "misc.h"
#include <ctype.h>
#include "var.h"
#include "ship.h"
#include "plane.h"
#include "land.h"
#include "nuke.h"
#include "sect.h"
#include "news.h"
#include "xy.h"
#include "nsc.h"
#include "nat.h"
#include "path.h"
#include "deity.h"
#include "file.h"
#include "item.h"
#include "optlist.h"
#include "player.h"
#include "update.h"
#include "subs.h"
#include "common.h"
#include "gen.h"
/* Format a ship name */
int
check_nav(struct sctstr *sect)
{
extern struct dchrstr dchr[];
switch (dchr[sect->sct_type].d_flg & 03) {
case NAVOK:
break;
case NAV_02:
if (sect->sct_effic < 2)
return CN_CONSTRUCTION;
break;
case NAV_60:
if (sect->sct_effic < 60)
return CN_CONSTRUCTION;
break;
default:
return CN_LANDLOCKED;
}
return CN_NAVIGABLE;
}
/* load a specific ship given its
* location and what field to modify.
* new autonav code
* Chad Zabel 6/1/94
*/
int
load_it(register struct shpstr *sp, register struct sctstr *psect, int i)
{
int comm, shipown, amount, ship_amt, sect_amt,
abs_max, max_amt, transfer;
s_char item;
struct mchrstr *vship;
amount = sp->shp_lend[i];
shipown = sp->shp_own;
item = sp->shp_tend[i]; /* commodity */
comm = com_num(&item);
ship_amt = getvar(comm,(s_char *) sp , EF_SHIP);
sect_amt = getvar(comm,(s_char *) psect, EF_SECTOR);
/* check for disloyal civilians */
if (psect->sct_oldown != shipown && comm == V_CIVIL)
{ wu(0,shipown,"Ship #%d - unable to load disloyal civilians at %s.",
sp->shp_uid, xyas(psect->sct_x,psect->sct_y,psect->sct_own));
return 0;
}
if (comm == V_CIVIL || comm == V_MILIT)
sect_amt--; /* leave 1 civ or mil to hold the sector. */
vship = &mchr[(int)sp->shp_type];
abs_max = max_amt = (vl_find(comm,vship->m_vtype,
vship->m_vamt,(int) vship->m_nv));
if (!abs_max)
return 0; /* can't load the ship, skip to the end. */
max_amt = min (sect_amt, max_amt - ship_amt);
if (max_amt <= 0 && (ship_amt != abs_max)) {
sp->shp_autonav |= AN_LOADING;
return 0;
}
transfer = amount - ship_amt;
if (transfer > sect_amt) { /* not enough in the */
transfer = sect_amt; /* sector to fill the */
sp->shp_autonav |= AN_LOADING; /* ship, set load flag */
}
if (ship_amt + transfer > abs_max) /* Do not load more */
transfer = abs_max-ship_amt; /* then the max alowed */
/* on the ship. */
if (transfer == 0)
return 0; /* nothing to move */
putvar(comm, ship_amt + transfer, (s_char *)sp, EF_SHIP);
if (comm == V_CIVIL || comm == V_MILIT)
sect_amt++; /*adjustment*/
putvar(comm, sect_amt - transfer, (s_char *)psect, EF_SECTOR);
/* deal with the plague */
if (getvar(V_PSTAGE, (s_char *)psect, EF_SECTOR) == PLG_INFECT &&
getvar(V_PSTAGE, (s_char *)sp , EF_SHIP) == PLG_HEALTHY)
putvar(V_PSTAGE, PLG_EXPOSED, (s_char *)sp, EF_SHIP);
if (getvar(V_PSTAGE, (s_char *)sp, EF_SHIP) == PLG_INFECT &&
getvar(V_PSTAGE, (s_char *)psect, EF_SECTOR) == PLG_HEALTHY)
putvar(V_PSTAGE, PLG_EXPOSED, (s_char *)psect, EF_SECTOR);
return 1; /* we did someloading return 1 to keep */
/* our loop happy in nav_ship() */
}
/* unload_it
* A guess alot of this looks like load_it but because of its location
* in the autonav code I had to split the 2 procedures up.
* unload_it dumps all the goods from the ship to the harbor.
* ONLY goods in the trade fields will be unloaded.
* new autonav code
* Chad Zabel 6/1/94
*/
void
unload_it(register struct shpstr *sp)
{
struct sctstr *sectp;
s_char item;
int i;
int landowner;
int shipown;
int comm;
int sect_amt;
int ship_amt;
int abs_max = 99999; /* max amount a sector can hold. */
int max_amt;
int level;
sectp = getsectp(sp->shp_x,sp->shp_y);
landowner = sectp->sct_own;
shipown = sp->shp_own;
for(i=0;i<TMAX;++i) {
item = sp->shp_tend[i];
level = sp->shp_lend[i];
if (item == ' ' || level == 0)
continue;
if (landowner == 0 )
continue;
if (sectp->sct_type != SCT_HARBR)
continue;
comm = com_num(&item);
ship_amt = getvar(comm,(s_char *) sp ,EF_SHIP);
sect_amt = getvar(comm,(s_char *) sectp ,EF_SECTOR);
/* check for disloyal civilians */
if (sectp->sct_oldown != shipown && comm == V_CIVIL)
{
wu(0,sp->shp_own,"Ship #%d - unable to unload civilians into a disloyal sector at %s.",
sp->shp_uid, xyas(sectp->sct_x,sectp->sct_y,sectp->sct_own));
continue;
}
if (comm == V_CIVIL)
ship_amt--; /* This leaves 1 civs on board the ship */
if (sect_amt >= abs_max)
continue; /* The sector is full. */
max_amt = min (ship_amt,abs_max - sect_amt);
if (max_amt <= 0)
continue;
putvar(comm, ship_amt - max_amt, (s_char *) sp ,EF_SHIP);
putvar(comm, sect_amt + max_amt, (s_char *) sectp,EF_SECTOR);
if (getvar(V_PSTAGE, (s_char *)sectp,EF_SECTOR) == PLG_INFECT &&
getvar(V_PSTAGE, (s_char *)sp ,EF_SHIP ) == PLG_HEALTHY)
putvar(V_PSTAGE, PLG_EXPOSED,(s_char *)sp, EF_SHIP);
if (getvar(V_PSTAGE, (s_char *)sp ,EF_SHIP ) == PLG_INFECT &&
getvar(V_PSTAGE, (s_char *)sectp,EF_SECTOR) == PLG_HEALTHY)
putvar(V_PSTAGE, PLG_EXPOSED,(s_char *)sectp, EF_SECTOR);
}
}
/* com_num
* This small but useful bit of code runs through the list
* of commodities and return the integer value of the
* commodity it finds if possible. Very handy when using getvar().
* Basicly its a hacked version of whatitem.c found in the
* /player directory.
* new autonav code.
* Chad Zabel 6/1/94
*/
int
com_num(s_char *ptr)
{
struct ichrstr *ip;
for(ip = &ichr[1];ip->i_mnem != 0; ip++) {
if (*ptr == ip->i_mnem)
return ip->i_vtype;
}
return 0; /*NOTREACHED*/
}
/* auto_fuel_ship
* Assume a check for fuel=0 has already been made and passed.
* Try to fill a ship using petro. and then oil.
* new autonav code.
* This should be merged with the fuel command someday.
* Chad Zabel 6/1/94
*/
void
auto_fuel_ship(register struct shpstr *sp)
{
double d;
int totalfuel = 0;
int need;
int maxfuel;
int newfuel = 0;
int add_fuel = 0;
if (opt_FUEL == 0) return;
getship(sp->shp_uid,sp); /* refresh */
/* fill with petro */
maxfuel = mchr[(int)sp->shp_type].m_fuelc;
d = (double) maxfuel / 5.0;
if (( d-(int)d > 0.0 ))
d++;
need = (int)d;
newfuel = supply_commod(sp->shp_own,sp->shp_x,
sp->shp_y,I_PETROL,need);
add_fuel += newfuel * 5;
if (add_fuel > maxfuel)
add_fuel = maxfuel;
sp->shp_fuel += add_fuel;
totalfuel += add_fuel;
if (totalfuel == maxfuel) {
putship(sp->shp_uid,sp);
return; /* the ship is full */
}
add_fuel = 0;
/* fill with oil */
d = (double) (maxfuel - totalfuel) / 50.0;
if ((d-(int)d > 0.0))
d++;
need = (int)d;
newfuel = supply_commod(sp->shp_own,sp->shp_x,
sp->shp_y,I_OIL,need);
add_fuel = newfuel * 50;
if (add_fuel > maxfuel)
add_fuel = maxfuel;
sp->shp_fuel += add_fuel;
putship(sp->shp_uid,sp);
}

119
src/lib/update/nxtitemp.c Normal file
View file

@ -0,0 +1,119 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* nxtitemp.c: Get next item from list
*
* Known contributors to this file:
* Dave Pare, 1989
*/
#include "misc.h"
#include "var.h"
#include "xy.h"
#include "plane.h"
#include "ship.h"
#include "nuke.h"
#include "land.h"
#include "nsc.h"
#include "nat.h"
#include "file.h"
#include "genitem.h"
#include "player.h"
#include "update.h"
#include "gen.h"
#include "common.h"
s_char *
nxtitemp(struct nstr_item *np, int owner)
{
struct genitem *gp;
int selected;
if (np->sel == NS_UNDEF)
return 0;
do {
if (np->sel == NS_LIST) {
np->index++;
if (np->index >= np->size)
return 0;
np->cur = np->list[np->index];
} else {
np->cur++;
}
gp = (struct genitem *)ef_ptr(np->type,np->cur);
if (gp == (struct genitem *)0)
return 0;
selected = 1;
switch (np->sel) {
/*
* This one won't work unless you're running in emp_player
*
*/
case NS_LIST:
if ((np->flags & EFF_OWNER) && !owner)
selected = 0;
break;
case NS_ALL:
/* XXX maybe combine NS_LIST and NS_ALL later */
break;
case NS_DIST:
if (!xyinrange(gp->x, gp->y, &np->range)) {
selected = 0;
break;
}
np->curdist = mapdist((int)gp->x, (int)gp->y,
(int)np->cx, (int)np->cy);
if (np->curdist > np->dist)
selected = 0;
break;
case NS_AREA:
if (!xyinrange(gp->x, gp->y, &np->range))
selected = 0;
if (gp->x == np->range.hx || gp->y == np->range.hy)
selected = 0;
break;
case NS_XY:
if (xnorm(gp->x) != np->cx || ynorm(gp->y) != np->cy)
selected = 0;
break;
case NS_GROUP:
if (np->group != gp->group)
selected = 0;
break;
default:
logerror("nxtitemp: bad selector %d\n", np->sel);
return 0;
}
if (selected && np->ncond) {
/* nstr_exec is expensive, so we do it last */
if (!nstr_exec(np->cond, np->ncond, (s_char *)gp, np->type))
selected = 0;
}
} while (!selected);
return (s_char *)gp;
}

76
src/lib/update/nxtsctp.c Normal file
View file

@ -0,0 +1,76 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* nxtsctp.c: select/get the next sector from a rnage of sectors
*
* Known contributors to this file:
* Dave Pare, 1989
*/
#include "misc.h"
#include "var.h"
#include "xy.h"
#include "sect.h"
#include "nsc.h"
#include "file.h"
#include "update.h"
#include "gen.h"
#include "optlist.h"
/*
* get the next sector in the range
* that matches the conditions.
*/
struct sctstr *
nxtsctp(register struct nstr_sect *np)
{
while (1) {
np->dx++;
np->x++;
if (np->x >= WORLD_X)
np->x = 0;
if (np->dx >= np->range.width) {
np->dx = 0;
np->x = np->range.lx;
np->dy++;
if (np->dy >= np->range.height)
return (struct sctstr *)0;
np->y++;
if (np->y >= WORLD_Y)
np->y = 0;
}
if ((np->y + np->x) & 01)
continue;
if (np->type == NS_DIST) {
np->curdist = mapdist(np->x, np->y, np->cx, np->cy);
if (np->curdist > np->dist)
continue;
}
return(getsectp(np->x, np->y));
}
/*NOTREACHED*/
}

200
src/lib/update/plague.c Normal file
View file

@ -0,0 +1,200 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* plague.c: Plague related functions
*
* Known contributors to this file:
* Steve McClure, 1998-2000
*/
#include <math.h>
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "nat.h"
#include "item.h"
#include "news.h"
#include "file.h"
#include "xy.h"
#include "optlist.h"
#include "update.h"
#include "common.h"
#include "subs.h"
#include "lost.h"
#include "gen.h"
void
do_plague(struct sctstr *sp, struct natstr *np, int etu)
{
int vec[I_MAX+1];
int cvec[I_MAX+1];
int n;
if (opt_NO_PLAGUE) /* no plague nothing to do */
return;
if (getvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR) <= 0)
return;
if (getvec(VT_COND, cvec, (s_char *)sp, EF_SECTOR) <= 0)
bzero((s_char *)cvec, sizeof(cvec));
if (cvec[C_PSTAGE] == 0) {
cvec[C_PSTAGE] = infect_people(np, vec, sp->sct_effic,
(int)sp->sct_mobil, sp);
cvec[C_PTIME] = 0;
} else {
n = plague_people(np, vec, cvec, etu);
switch (n) {
case PLG_DYING:
wu(0, sp->sct_own, "PLAGUE deaths reported in %s.\n",
ownxy(sp));
nreport(sp->sct_own, N_DIE_PLAGUE, 0, 1);
break;
case PLG_INFECT:
wu(0, sp->sct_own, "%s battling PLAGUE\n", ownxy(sp));
break;
case PLG_INCUBATE:
/* Are we still incubating? */
if (n == cvec[C_PSTAGE]) {
/* Yes. Will it turn "infectious" next time? */
if (cvec[C_PTIME] <= etu) {
/* Yes. Report an outbreak. */
wu(0, sp->sct_own,
"Outbreak of PLAGUE in %s!\n",
ownxy(sp));
nreport(sp->sct_own, N_OUT_PLAGUE, 0, 1);
}
} else {
/* It has already moved on to "infectious" */
wu(0, sp->sct_own, "%s battling PLAGUE\n", ownxy(sp));
}
break;
case PLG_EXPOSED:
/* Has the plague moved to "incubation" yet? */
if (n != cvec[C_PSTAGE]) {
/* Yes. Will it turn "infectious" next time? */
if (cvec[C_PTIME] <= etu) {
/* Yes. Report an outbreak. */
wu(0, sp->sct_own,
"Outbreak of PLAGUE in %s!\n",
ownxy(sp));
nreport(sp->sct_own, N_OUT_PLAGUE, 0, 1);
}
}
break;
default:
break;
}
}
if (vec[I_CIVIL] == 0 && vec[I_MILIT] == 0 &&
!has_units(sp->sct_x,sp->sct_y,sp->sct_own,0)) {
makelost(EF_SECTOR, sp->sct_own, 0, sp->sct_x, sp->sct_y);
sp->sct_own = 0;
sp->sct_oldown = 0;
}
putvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
putvec(VT_COND, cvec, (s_char *)sp, EF_SECTOR);
}
/*ARGSUSED*/
int
infect_people(struct natstr *np, register int *vec, u_int eff, int mobil, struct sctstr *sp)
{
double plg_num;
double plg_denom;
double plg_chance;
double civvies = 999.0;
if (opt_NO_PLAGUE) /* no plague nothing to do */
return PLG_HEALTHY;
if (np->nat_level[NAT_TLEV] <= 10.0)
return PLG_HEALTHY;
if (opt_BIG_CITY && (sp->sct_type == SCT_CAPIT))
civvies = 9999.0;
/*
* make plague where there was none before...
*/
plg_num = ((vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW]) / civvies) *
((vec[I_IRON] + vec[I_OIL] + (vec[I_RAD] * 2)) / 10.0 +
np->nat_level[NAT_TLEV] + 100.0);
plg_denom = eff + mobil + 100 + np->nat_level[NAT_RLEV];
plg_chance = ((plg_num / plg_denom) - 1.0) * 0.01;
if (chance(plg_chance))
return PLG_EXPOSED;
return PLG_HEALTHY;
}
/*
* Given the fact that plague exists, kill off
* people if in plague state DYING. Increment
* the plague time. Return "current" plague
* stage. No reports generated here anymore.
*/
int
plague_people(struct natstr *np, register int *vec, register int *cvec, int etus)
{
int stage;
double plg_num;
double plg_denom;
double pct_left;
if (opt_NO_PLAGUE) /* no plague nothing to do */
return PLG_HEALTHY;
cvec[C_PTIME] -= etus;
stage = cvec[C_PSTAGE];
switch (stage) {
case PLG_DYING:
plg_num = 100.0 * etus;
plg_denom = (np->nat_level[NAT_RLEV] + 100.0) *
(vec[C_PTIME] + etus + 1.0);
pct_left = 1.0 - (double)(plg_num / plg_denom);
if (pct_left < 0.2)
pct_left = 0.2;
vec[I_CIVIL] = vec[I_CIVIL] * pct_left;
vec[I_MILIT] = vec[I_MILIT] * pct_left;
vec[I_UW] = vec[I_UW] * pct_left;
break;
case PLG_INFECT:
case PLG_INCUBATE:
break;
case PLG_EXPOSED:
cvec[C_PTIME] = 0;
break;
default:
/* bad */
cvec[C_PTIME] = 0;
break;
}
if (cvec[C_PTIME] <= 0) {
cvec[C_PSTAGE]--;
cvec[C_PTIME] = (etus / 2) + (random() % etus);
}
return stage;
}

282
src/lib/update/plane.c Normal file
View file

@ -0,0 +1,282 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* plane.c: Do production for planes
*
* Known contributors to this file:
* Dave Pare, 1986
* Steve McClure, 1998
*/
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "plane.h"
#include "ship.h"
#include "nat.h"
#include "file.h"
#include "optlist.h"
#include "budg.h"
#include "player.h"
#include "update.h"
#include "lost.h"
#include "subs.h"
#include "common.h"
#include "gen.h"
#ifndef MIN
#define MIN(x,y) ((x) > (y) ? (y) : (x))
#endif
int
prod_plane(int etus, int natnum, int *bp, int buildem)
/* Build = 1, maintain =0 */
{
extern double money_mil;
extern double money_plane;
extern int plane_grow_scale;
extern long air_money[MAXNOC];
register struct plnstr *pp;
register struct plchrstr *plp;
struct natstr *np;
float leftp, buildp;
int left, build;
int lcm_needed,hcm_needed;
int mil_needed;
int svec[I_MAX+1];
int mvec[I_MAX+1];
int n, k=0;
struct shpstr *shp;
struct plchrstr *desc;
struct sctstr *sp;
int delta;
int mult;
int cost;
int eff;
int avail;
int w_p_eff;
int used;
int start_money, onship=0;
for (n=0; NULL != (pp = getplanep(n)); n++) {
if (pp->pln_own == 0)
continue;
if (pp->pln_own != natnum)
continue;
if (pp->pln_effic < PLANE_MINEFF) {
makelost(EF_PLANE, pp->pln_own, pp->pln_uid,
pp->pln_x, pp->pln_y);
pp->pln_own = 0;
continue;
}
plp = &plchr[(int)pp->pln_type];
if (pp->pln_flags & PLN_LAUNCHED) {
if (opt_ORBIT && (buildem == 0)) {
if ((!player->simulation) &&
(plp->pl_flags & P_O) &&
(pp->pln_flags & PLN_LAUNCHED) &&
!(plp->pl_flags & P_M) &&
!(pp->pln_flags & PLN_SYNCHRONOUS))
move_sat(pp);
}
continue;
}
onship = 0;
shp = (struct shpstr *)0;
if (pp->pln_ship >= 0 && (buildem == 1)) {
if (pp->pln_effic >= 80)
continue;
onship = 1;
shp = getshipp(pp->pln_ship);
if (shp == 0 || shp->shp_own != pp->pln_own) {
/* nplane is unsigned... */
if (shp->shp_nplane > 0)
shp->shp_nplane --;
makelost(EF_PLANE, pp->pln_own, pp->pln_uid, pp->pln_x, pp->pln_y);
pp->pln_own = 0;
continue;
}
}
np = getnatp(pp->pln_own);
desc = &plchr[(int)pp->pln_type];
sp = getsectp(pp->pln_x, pp->pln_y);
getvec(VT_ITEM, svec, (s_char *)sp, EF_SECTOR);
mult=1;
if (np->nat_level[NAT_TLEV] < pp->pln_tech * 0.85)
mult = 2;
if (buildem == 0) {
/* flight pay is 5x the pay received by other military */
start_money = np->nat_money;
cost = -(mult * etus *
dmin(0.0, desc->pl_cost * money_plane));
if ((np->nat_priorities[PRI_PMAINT] == 0 ||
np->nat_money < cost) && !player->simulation) {
if ((eff = pp->pln_effic - etus/5) < PLANE_MINEFF) {
wu(0, pp->pln_own,
"%s lost to lack of maintenance\n",
prplane(pp));
makelost(EF_PLANE, pp->pln_own, pp->pln_uid, pp->pln_x, pp->pln_y);
pp->pln_own = 0;
continue;
}
wu(0, pp->pln_own,
"%s lost %d%% to lack of maintenance\n",
prplane(pp), pp->pln_effic - eff);
pp->pln_effic = eff;
} else {
np->nat_money -= cost;
}
np->nat_money += (etus * plp->pl_crew * money_mil * 5);
air_money[pp->pln_own] += np->nat_money - start_money;
k++;
if (player->simulation)
np->nat_money = start_money;
if ((pp->pln_flags & PLN_LAUNCHED) == PLN_LAUNCHED)
continue;
}else{
if (sp->sct_off)
continue;
if (np->nat_priorities[PRI_PBUILD] == 0 ||
np->nat_money < 0)
continue;
start_money = np->nat_money;
left = 100 - pp->pln_effic;
if (left <= 0)
continue;
if (!player->simulation)
avail = sp->sct_avail * 100;
else
avail = gt_bg_nmbr(bp, sp, I_MAX+1) * 100;
if (pp->pln_ship >= 0) {
int vec[I_MAX+1];
shp = getshipp(pp->pln_ship);
getvec(VT_ITEM, vec, (s_char *)shp, EF_SHIP);
avail += (etus * vec[I_MILIT]/2);
}
w_p_eff = 20 + (desc->pl_lcm + 2 * desc->pl_hcm);
delta = roundavg((double)avail/w_p_eff);
if (delta <= 0)
continue;
if (delta > etus*plane_grow_scale)
delta = etus*plane_grow_scale;
if (delta > left)
delta = left;
/* delta is the max amount we can grow */
left = 100 - pp->pln_effic;
if (left > delta)
left = delta;
leftp = ((float)left/100.0);
bzero((s_char *)mvec, sizeof(mvec));
mvec[I_MILIT] = mil_needed =
ldround((double)(plp->pl_crew * leftp),1);
mvec[I_LCM] = lcm_needed =
ldround((double)(plp->pl_lcm * leftp),1);
mvec[I_HCM] = hcm_needed =
ldround((double)(plp->pl_hcm * leftp),1);
get_materials(sp, bp, mvec, 0);
if (mvec[I_MILIT]>=mil_needed)
buildp=leftp;
else
buildp=((float)mvec[I_MILIT]/(float)plp->pl_crew);
if (mvec[I_LCM] < lcm_needed)
buildp = MIN(buildp,((float)mvec[I_LCM]/
(float)plp->pl_lcm));
if (mvec[I_HCM] < hcm_needed)
buildp = MIN(buildp,((float)mvec[I_HCM]/
(float)plp->pl_hcm));
build=ldround((double)(buildp*100.0),1);
bzero((s_char *)mvec, sizeof(mvec));
mvec[I_MILIT] = mil_needed =
roundavg((double)(plp->pl_crew * buildp));
mvec[I_LCM] = lcm_needed =
roundavg((double)(plp->pl_lcm * buildp));
mvec[I_HCM] = hcm_needed =
roundavg((double)(plp->pl_hcm * buildp));
get_materials(sp, bp, mvec, 1);
if (onship) 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 = (gt_bg_nmbr(bp,sp,I_MAX+1) *100 -used) / 100;
if (avail < 0)
avail = 0;
if (!player->simulation)
sp->sct_avail = avail;
else
pt_bg_nmbr(bp,sp,I_MAX+1,avail);
if (sp->sct_type != SCT_AIRPT)
build /= 3;
if (onship){
if ((pp->pln_effic + build) > 80)
build = 80- pp ->pln_effic;
}
np->nat_money -= roundavg(mult * build *
desc->pl_cost / 100.0);
air_money[pp->pln_own] += np->nat_money - start_money;
if (!player->simulation)
pp->pln_effic += (s_char)build;
else
np->nat_money = start_money;
k++;
}
}
return k;
}

141
src/lib/update/populace.c Normal file
View file

@ -0,0 +1,141 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* populace.c: Return workforce available
*
* Known contributors to this file:
* Dave Pare, 1986
*/
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "nat.h"
#include "news.h"
#include "var.h"
#include "file.h"
#include "path.h"
#include "xy.h"
#include "land.h"
#include "budg.h"
#include "update.h"
#include "subs.h"
#include "gen.h"
#include "common.h"
#include "lost.h"
void
populace(struct natstr *np, register struct sctstr *sp, register int *vec, int etu)
{
float hap;
float tech;
float edu;
float pct;
int n;
if (vec[I_CIVIL] == 0 && vec[I_MILIT] > 0) {
sp->sct_work = 100;
sp->sct_loyal = 0;
sp->sct_oldown = sp->sct_own;
}
if (!vec[I_CIVIL] && !vec[I_MILIT] && !vec[I_UW] &&
!has_units(sp->sct_x,sp->sct_y,sp->sct_own,0)) {
makelost(EF_SECTOR, sp->sct_own, 0, sp->sct_x, sp->sct_y);
sp->sct_own = 0;
sp->sct_oldown = 0;
return;
}
if (sp->sct_own != sp->sct_oldown && sp->sct_loyal == 0) {
sp->sct_oldown = sp->sct_own;
}
hap = np->nat_level[NAT_HLEV];
edu = np->nat_level[NAT_ELEV];
tech = np->nat_level[NAT_TLEV];
pct = (double)((tech - 40) / 40.0 + edu / 3.0);
if (sp->sct_own == sp->sct_oldown && hap < pct &&
chance((double)(((double)pct-(double)hap)/(double)5.0))) {
/*
* zap the loyalty of unhappy civilians.
* there is a 20% chance per hap point below the
* "recommended" amount of this happening.
*/
n = roundavg(etu * 0.125);
if (n == 0) n = 1;
n = sp->sct_loyal + (random() % n) + 1;
if (n > 127)
n = 127;
sp->sct_loyal = n;
}
if (sp->sct_loyal > 65 && vec[I_MILIT] < vec[I_CIVIL]/20) {
int work_red;
work_red = sp->sct_loyal - (50 + (random() % 15));
n = sp->sct_work - work_red;
if (n < 0)
n = 0;
sp->sct_work = n;
if (chance((double)work_red/1000.0)) {
/*
* small chance of rebellion...
* if work_red is (max) 67,
* then revolt chance is 6.7%
*/
revolt(sp);
} else if (chance(.30) && sp->sct_own)
wu(0, sp->sct_own, "Civil unrest in %s!\n", ownxy(sp));
}
if (sp->sct_loyal) {
n = sp->sct_loyal;
if (chance(0.75))
n -= roundavg(etu * 0.25);
else
n += roundavg(etu * 0.125);
if (n < 0)
n = 0;
else if (n > 127)
n = 127;
sp->sct_loyal = n;
if (sp->sct_loyal == 0) {
if (sp->sct_oldown != sp->sct_own) {
wu(0, sp->sct_own,
"Sector %s is now fully yours\n",
ownxy(sp));
sp->sct_oldown = sp->sct_own;
}
sp->sct_loyal = 0;
}
}
return;
}
int
total_work(register int sctwork, register int etu, register int civil, register int milit, register int uw)
{
return ((int)((((civil * sctwork) / 100.0 +
(milit * 2 / 5.0) + uw)) * etu) / 100);
}

187
src/lib/update/prepare.c Normal file
View file

@ -0,0 +1,187 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* prepare.c: Perform prelimiary updates of sectors
*
* Known contributors to this file:
* Dave Pare, 1986
* Thomas Ruschak, 1992
* Steve McClure, 1997
*/
#include <math.h>
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "nat.h"
#include "item.h"
#include "news.h"
#include "file.h"
#include "xy.h"
#include "path.h"
#include "optlist.h"
#include "budg.h"
#include "player.h"
#include "ship.h"
#include "land.h"
#include "update.h"
#include "gen.h"
#include "common.h"
extern float levels[MAXNOC][4];
void
prepare_sects(int etu, int *bp)
{
extern long pops[];
register struct sctstr *sp;
struct natstr *np;
int n, civ_tax, uw_tax, mil_pay;
bzero((s_char *)levels, sizeof(levels));
/* Process all the fallout. */
if (opt_FALLOUT) {
if (!player->simulation) {
/* First, we determine which sectors to process fallout in */
for (n = 0; NULL != (sp = getsectid(n)); n++) {
if (getvar(V_FALLOUT, (s_char *)sp, EF_SECTOR))
sp->sct_updated = 1;
else
sp->sct_updated = 0;
}
/* Next, we process the fallout there */
for (n = 0; NULL != (sp = getsectid(n)); n++)
if (sp->sct_updated)
do_fallout(sp, etu);
/* Next, we spread the fallout */
for (n = 0; NULL != (sp = getsectid(n)); n++)
if (sp->sct_updated)
spread_fallout(sp, etu);
/* Next, we decay the fallout */
for (n = 0; NULL != (sp = getsectid(n)); n++)
if (getvar(V_FALLOUT, (s_char *)sp, EF_SECTOR))
decay_fallout(sp, etu);
}
}
for (n=0; NULL != (sp = getsectid(n)); n++) {
sp->sct_updated = 0;
if (sp->sct_type == SCT_WATER)
continue;
fill_update_array(bp, sp);
np = getnatp(sp->sct_own);
#ifdef DEBUG
if (np->nat_stat & STAT_SANCT)
logerror("Prepare.c: country in sanctuary skipped production");
#endif /* DEBUG */
if (!(np->nat_stat & STAT_SANCT)){
guerrilla(sp);
do_plague(sp, np, etu);
tax(sp, np, etu, &pops[sp->sct_own], &civ_tax, &uw_tax, &mil_pay);
np->nat_money += civ_tax + uw_tax + mil_pay;
if (sp->sct_type == SCT_BANK)
np->nat_money += bank_income(sp, etu);
}
}
for (n=0; NULL != (np = getnatp(n)); n++) {
np->nat_money += upd_slmilcosts(np->nat_cnum, etu);
}
}
void
tax(struct sctstr *sp, struct natstr *np, int etu, long *pop, int *civ_tax, int *uw_tax, int *mil_pay)
{
int vec[I_MAX+1];
extern double money_civ, money_mil, money_uw;
*civ_tax = 0;
*uw_tax = 0;
*mil_pay = 0;
if (getvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR) <= 0)
return;
if (!player->simulation)
populace(np, sp, vec, etu);
*civ_tax = (int)(0.5 + vec[I_CIVIL] * sp->sct_effic *
etu * money_civ / 100);
/*
* captured civs only pay 1/4 taxes
*/
if (sp->sct_own != sp->sct_oldown)
*civ_tax = *civ_tax / 4;
*uw_tax = (int)(0.5 + vec[I_UW] * sp->sct_effic *
etu * money_uw / 100);
*mil_pay = vec[I_MILIT] * etu * money_mil;
/*
* only non-captured civs add to census for nation
*/
if (sp->sct_oldown == sp->sct_own)
*pop += vec[I_CIVIL];
}
int
upd_slmilcosts(natid n, int etu)
{
extern double money_mil;
struct shpstr *sp;
struct lndstr *lp;
int mil = 0;
int totalmil = 0;
int mil_pay = 0;
int i;
for (i = 0; NULL != (sp = getshipp(i)); i++) {
if (!sp->shp_own || sp->shp_own != n)
continue;
if ((mil = getvar(V_MILIT, (s_char *)sp, EF_SHIP)) > 0)
totalmil += mil;
}
for (i = 0; NULL != (lp = getlandp(i)); i++) {
if (!lp->lnd_own || lp->lnd_own != n)
continue;
if ((mil = getvar(V_MILIT, (s_char *)lp, EF_LAND)) > 0)
totalmil += mil;
}
mil_pay = totalmil * etu * money_mil;
return (mil_pay);
}
int
bank_income(struct sctstr *sp, int etu)
{
extern double bankint;
int vec[I_MAX+1];
if (getvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR) <= 0)
return 0;
else
return (int)(vec[I_BAR] * etu * bankint * sp->sct_effic / 100);
}

237
src/lib/update/produce.c Normal file
View file

@ -0,0 +1,237 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* produce.c: Produce goodies
*
* Known contributors to this file:
*
*/
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "product.h"
#include "nat.h"
#include "file.h"
#include "xy.h"
#include "player.h"
#include "update.h"
#include "gen.h"
#include "subs.h"
#include "common.h"
#include "optlist.h"
s_char *levelnames[] = { "Technology", "Research", "Education", "Happiness" };
int
produce(struct natstr *np, struct sctstr *sp, int *vec, int work, int sctwork, int desig, int neweff, int *cost, int *amount)
{
extern float levels[MAXNOC][4];
extern long tpops[];
register struct pchrstr *product;
int vtype;
double p_e;
double level_p_e;
s_char *resource;
int output;
int actual;
int unit_work;
double depend;
int item;
int worker_limit;
int material_limit;
int material_consume;
int val;
product = &pchr[dchr[desig].d_prd];
if (product == &pchr[0])
return 0;
vtype = product->p_type;
item = vtype &~ VT_ITEM;
*amount = 0;
*cost = 0;
if ((material_limit = materials_cost(product, vec, &unit_work)) <= 0)
return 0;
/*
* calculate production efficiency.
*/
p_e = neweff / 100.0;
if (product->p_nrndx != 0) {
unit_work++;
resource = ((s_char *) sp) + product->p_nrndx;
p_e = (*resource * p_e) / 100.0;
if (product->p_nrdep > 0) {
/* XXX this looks way wrong */
depend = (*resource * 100.0) / product->p_nrdep;
if (p_e > depend)
p_e = depend;
}
}
/*
* determine number that can be made with
* the available workforce
*/
if (unit_work == 0)
unit_work = 1;
material_consume = material_limit;
worker_limit = roundavg(work * p_e / unit_work);
if (material_consume > worker_limit)
material_consume = worker_limit;
if (material_consume == 0)
return 0;
level_p_e = 1.0;
if (product->p_nlndx >= 0) {
level_p_e = np->nat_level[product->p_nlndx] - product->p_nlmin;
if ((level_p_e < 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;
}
level_p_e = level_p_e / (level_p_e + product->p_nllag);
}
/*
* Adjust produced amount by commodity production ratio
*/
output = roundavg(product->p_effic * 0.01 * material_consume);
if ((vtype == 0) && (!player->simulation)) {
levels[sp->sct_own][product->p_level] += output * level_p_e;
wu((natid)0, sp->sct_own, "%s (%.2f) produced in %s\n",
product->p_name, output * level_p_e, ownxy(sp));
} else {
if ((actual = roundavg(level_p_e * output)) <= 0)
return 0;
if (product->p_nrdep != 0) {
if(*resource*100 < product->p_nrdep*actual)
actual = *resource*100/product->p_nrdep;
}
if (actual > 999) {
actual = 999;
material_consume = (int)(actual / (product->p_effic * 0.01));
}
vec[item] += actual;
if (vec[item] > 9999) {
material_consume =
roundavg((9999.0 - vec[item] + actual) *
material_consume / actual);
if (material_consume < 0)
material_consume = 0;
vec[item] = 9999;
if ((/* vtype != V_FOOD && */ sp->sct_own) &&
(!player->simulation))
wu(0, sp->sct_own,
"%s production backlog in %s\n",
product->p_name, ownxy(sp));
}
}
/*
* Reset produced amount by commodity production ratio
*/
if (!player->simulation) {
materials_charge(product, vec, material_consume);
if (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 = (double)*cost * (double)tpops[sp->sct_own] / 50000.0;
}
}
/* The min() here is to take care of integer rounding errors */
if (p_e > 0.0) {
return min(work, (int)(unit_work * material_consume / p_e));
}
return 0;
}
int
materials_cost(struct pchrstr *product, register int *vec, int *costp)
{
register u_char *vp;
register u_short *ap;
register int count;
register int cost;
register int n;
register u_char *endp;
count = 9999;
cost = 0;
ap = product->p_vamt;
endp = product->p_vtype + product->p_nv;
for (vp = product->p_vtype; vp < endp; vp++, ap++) {
if (!*ap)
continue;
n = vec[*vp & ~VT_ITEM] / *ap;
if (n < count)
count = n;
cost += *ap;
}
*costp = cost;
return count;
}
void
materials_charge(struct pchrstr *product, register int *vec, register int count)
{
register u_char *vp;
register u_short *ap;
register u_char *endp;
register int item;
register int n;
ap = product->p_vamt;
endp = product->p_vtype + product->p_nv;
for (vp = product->p_vtype; vp < endp; vp++, ap++) {
item = *vp & ~VT_ITEM;
if (item < 0 || item > I_MAX) {
logerror("materials_charge: bad item %d", item);
continue;
}
if ((n = vec[item] - *ap * count) < 0) {
logerror("materials_charge: %d > %d item #%d",
n, vec[item], item);
n = 0;
}
vec[item] = n;
}
}

View file

@ -0,0 +1,58 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* removewants.c: Remove the "I want an update" flag.
*
* Known contributors to this file:
*
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include "misc.h"
#include "nat.h"
#include "file.h"
#include "update.h"
int
update_removewants(void)
{
natid cn;
struct natstr *natp;
for (cn = 0; NULL != (natp=getnatp(cn)); cn++) {
if ((natp->nat_stat & STAT_INUSE) &&
(natp->nat_update & WUPD_WANT) == 0){
natp->nat_missed++;
}
natp->nat_update = natp->nat_stat & ~WUPD_WANT;
}
return 0;
}

595
src/lib/update/revolt.c Normal file
View file

@ -0,0 +1,595 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* revolt.c: Have disloyal populace revolt!
*
* Known contributors to this file:
* Dave Pare, 1986
* Steve McClure, 1997-2000
*/
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "nat.h"
#include "news.h"
#include "var.h"
#include "file.h"
#include "path.h"
#include "xy.h"
#include "land.h"
#include "nsc.h"
#include "plane.h"
#include "update.h"
#include "common.h"
#include "gen.h"
#include "lost.h"
#include "subs.h"
#define get_che_cnum(x) ((x) >> 8)
#define set_che_cnum(x, cn) ((x) = ((x) & 0xff) | ((cn) << 8))
#define get_che_value(x) ((x) & 0xff)
#define set_che_value(x, n) ((x) = ((x) & 0xff00) | (n))
#define CHE_MAX 255
void
revolt(struct sctstr *sp)
{
int che_civ;
int che_uw;
int civ;
int uw;
u_short che_combo;
int che;
int n;
int target;
che_combo = getvar(V_CHE, (s_char *)sp, EF_SECTOR);
che = get_che_value(che_combo);
target = get_che_cnum(che_combo);
if (che_combo != 0 && (target != sp->sct_own || che >= CHE_MAX))
return;
civ = getvar(V_CIVIL, (s_char *)sp, EF_SECTOR);
uw = getvar(V_UW, (s_char *)sp, EF_SECTOR);
if (che > (civ + uw) * 3)
return;
che_uw = 0;
che_civ = 0;
/* che due to civilian unrest */
n = 10 - (random() % 20);
che_civ = 3 + (civ * n/500);
if (che_civ < 0)
che_civ = 0;
else if (che_civ * 3 > civ)
che_civ = civ / 3;
if (che + che_civ > CHE_MAX)
che_civ = CHE_MAX - che;
che += che_civ;
if (che < CHE_MAX) {
/* che due to uw unrest */
n = 10 + (random() % 30);
che_uw = 5 + (uw * n/500);
if (che_uw > uw)
che_uw = uw;
if (che + che_uw > CHE_MAX)
che_uw = CHE_MAX - che_uw;
che += che_uw;
}
if (che_civ + che_uw > 0) {
civ -= che_civ;
uw -= che_uw;
set_che_cnum(che_combo, sp->sct_own);
set_che_value(che_combo, che);
putvar(V_CHE, (int)che_combo, (s_char *)sp, EF_SECTOR);
if (che_civ > 0)
putvar(V_CIVIL, civ, (s_char *)sp, EF_SECTOR);
if (che_uw > 0)
putvar(V_UW, uw, (s_char *)sp, EF_SECTOR);
#ifdef DEBUG
logerror("(#%d) %d che fired up in %s",
sp->sct_own, che, ownxy(sp));
#endif
}
}
/*
* summary of effects.
* if there are no military in the sector, che recruit from
* populace if pop loyalty is > 10. They spread subversion otherwise,
* trying to lower pop loyalty.
* if che outnumber military, they stay and shoot it out, kill the
* military.
* if che are outnumbered by less than 5 to 1, they blow up stuff,
* killing innocent civilians (never uw's) and damaging commodities.
* if che are outnumbered by more than 5 to 1, they try to leave the
* sector for a nearby sector with fewer military.
*
* if the military lose any attacks, the pop loyalty in the sector
* gets worse, representing military defeat.
* military can "catch" che's after bombing attacks, or after they move.
* If military catch them, then they get to shoot it out with a portion
* of the che's depending on the # of mil in the sector. Chance to contact
* is around 10% per every equal number of mil:che ratio in the sector.
* "contact" is by 20% of the military in the sector, and odds are equal.
*
* Without a doubt this routine should be broken up, if only for readabilty.
*/
void
guerrilla(struct sctstr *sp)
{
extern s_char *effadv();
struct sctstr *nsp;
int recruit;
int move;
int ratio;
int che;
int mil;
int cc, mc;
double odds;
int civ;
int n;
int uw;
natid target;
struct natstr *tnat;
int convert;
natid actor;
natid victim;
u_short che_combo;
int vec[I_MAX+1];
int tmp;
int min_mil;
int val;
int oldmob;
struct lndstr *lp;
s_char *nxtitemp(struct nstr_item *np, int owner);
struct nstr_item ni;
extern double hap_fact();
mc = cc = 0;
recruit = 0;
convert = 0;
move = 0;
if ((n = getvar(V_CHE, (s_char *)sp, EF_SECTOR)) <= 0)
return;
che_combo = n;
if (getvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR) <= 0)
return;
civ = vec[I_CIVIL];
uw = vec[I_UW];
victim = sp->sct_own;
actor = sp->sct_oldown;
che = get_che_value(che_combo);
mil = vec[I_MILIT];
snxtitem_xy(&ni, EF_LAND, sp->sct_x,sp->sct_y);
while (NULL != (lp=(struct lndstr *)nxtitemp(&ni, 0))){
if (lp->lnd_own != sp->sct_own)
continue;
mil += lnd_getmil(lp);
/* Security troops can now kill up to 1/2 their complement each
update, before doing anything else. */
if (lchr[(int)lp->lnd_type].l_flags & L_SECURITY){
int che_kill, r;
struct lchrstr *lcp;
lcp = &lchr[(int)lp->lnd_type];
mil += lnd_getmil(lp);
r = (((float)(lp->lnd_effic / 100) * (float)(lnd_getmil(lp))) / 2);
if (r < 2)
r = 2;
che_kill = (roll(r) - 1);
if (che_kill > che)
che_kill = che;
if (che_kill) {
wu(0, sp->sct_own,
"%s kills %d guerrilla%s in raid at %s!\n",
prland(lp),
che_kill, splur(che_kill),
ownxy(sp));
che -= che_kill;
}
}
}
/* Security forces killed all the che */
if (che <= 0) {
putvar(V_CHE, 0, (s_char *)sp, EF_SECTOR);
return;
}
target = get_che_cnum(che_combo);
if (target == 0) {
/* the deity can't be a target! */
return;
}
tnat = getnatp(target);
if ((tnat->nat_stat & STAT_INUSE) == 0) {
/* target nation has dissolved: che's retire. */
logerror("%d Che targeted at country %d retiring", che, target);
civ += che;
putvar(V_CHE, 0, (s_char *)sp, EF_SECTOR);
putvar(V_CIVIL, civ, (s_char *)sp, EF_SECTOR);
return;
}
if (sp->sct_own != target) {
/*logerror("own %d != target %d", sp->sct_own, target);*/
move++;
goto domove;
}
ratio = mil / che;
odds = (double) che / (mil+che);
odds /= hap_fact(tnat,getnatp(sp->sct_oldown));
if (mil == 0) {
wu(0, sp->sct_own, "Revolutionary subversion reported in %s!\n",
ownxy(sp));
recruit++;
convert++;
} else if (che > mil && mil > 0) {
/*logerror("guerrilla shootout with military");*/
/*
* shoot it out with the military, and kill them off.
* If loyalty bad enough, then take the sector over,
* and enlist 5% of civ as military force.
*/
while (che > 0 && mil > 0) {
if (chance(odds)) {
mc++;
mil--;
} else {
cc++;
che--;
}
}
if (mil > 0) {
/* military won. */
n = sp->sct_loyal - (random() % 15);
if (n < 0)
n = 0;
sp->sct_loyal = n;
/*logerror("(#%d) mil beat che in %s", sp->sct_own,*/
/*ownxy(sp));*/
} else {
convert++;
recruit++;
/*logerror("(#%d) che beat mil in %s", sp->sct_own,*/
/*ownxy(sp));*/
}
take_casualties(sp,mc);
} else if (ratio < 5) {
/*
* guerrillas have to resort to blowing things up.
* Note this disrupts work in the sector.
*/
n = 0;
n = (random() % 10) + (random() % che);
if (n > 100)
n = 100;
tmp = sp->sct_work - n;
if (tmp < 0)
tmp = 0;
sp->sct_work = tmp;
wu(0, sp->sct_own,
"Production %s disrupted by terrorists in %s\n",
effadv(n), ownxy(sp));
sect_damage(sp, n/10, 0);
/*logerror("(#%d) che blew up %s for %d", sp->sct_own,*/
/*ownxy(sp), n);*/
recruit++;
} else {
/* ratio >= 5 */
/*logerror("(#%d) %d che fleeing %d mil in %s", sp->sct_own,*/
/*che, mil, ownxy(sp));*/
move++;
}
if (mil > 0 && che > 0) {
/*
* we only get here if we haven't had combat previously.
* Chance to catch them.
* 20% of mil involved in attacking the che's.
*/
if (chance(ratio*0.10)) {
n = (mil/5) + 1;
if ((n+che) == 0){
logerror("n=%d che=%d\n",n,che);
if (che == 0)
return;
}
odds = (double) che / (n + che);
odds /= hap_fact(tnat,getnatp(sp->sct_oldown));
while (che > 0 && n > 0) {
if (chance(odds)) {
mc++;
n--;
} else {
cc++;
che--;
}
}
take_casualties(sp,mc);
recruit = 0;
/*logerror("Caught che; mc: %d, cc: %d", cc, mc);*/
}
}
if (convert && sp->sct_loyal >= 50) {
register int n;
/* new owner gets to keep the mobility there */
oldmob = sp->sct_mobil;
/* che won, and sector converts. */
if (sp->sct_own == sp->sct_oldown)
sp->sct_oldown = 0;
else
takeover(sp, sp->sct_oldown);
sp->sct_mobil = oldmob;
civ += uw;
uw = 0;
/*
* so we can't keep losing money by having
* our cap retaken
*/
if (sp->sct_type == SCT_CAPIT &&
sp->sct_newtype == SCT_CAPIT)
sp->sct_newtype = SCT_AGRI;
n = civ / 20;
civ -= n;
putvar(V_CIVIL, civ, (s_char *)sp, EF_SECTOR);
putvar(V_UW, uw, (s_char *)sp, EF_SECTOR);
putvar(V_MILIT, n, (s_char *)sp, EF_SECTOR);
move++;
recruit = 0;
if (sp->sct_own)
wu(0, sp->sct_own, "Sector %s has been retaken!\n",
xyas(sp->sct_x, sp->sct_y, sp->sct_own));
}
if (recruit && che > 0) {
/* loyalty drops during recruitment efforts */
n = sp->sct_loyal;
if (n < 30)
n += (random() % 5) + 1;
else if (n < 70)
n += (random() % 10) + 4;
if (n > 127)
n = 127;
sp->sct_loyal = n;
if (sp->sct_oldown != sp->sct_own || n > 100) {
n = civ * (random() % 3) / 200;
n /= hap_fact(tnat,getnatp(sp->sct_oldown));
if (n + che > CHE_MAX)
n = CHE_MAX - che;
che += n;
civ -= n;
putvar(V_CIVIL, civ, (s_char *)sp, EF_SECTOR);
}
n = uw * (random() % 3) / 200;
if (n + che > CHE_MAX)
n = CHE_MAX - che;
che += n;
uw -= n;
putvar(V_UW, uw, (s_char *)sp, EF_SECTOR);
}
domove:
if (move && che > 0) {
struct sctstr *maybe_sp = 0;
if (convert)
min_mil = 999;
else
min_mil = mil;
for (n=1; n<=6; n++) {
nsp = getsectp(sp->sct_x+diroff[n][0],
sp->sct_y+diroff[n][1]);
if (dchr[nsp->sct_type].d_mcst == 0)
continue;
if (nsp->sct_own != target)
continue;
if ((val = getvar(V_CHE, (s_char *)nsp, EF_SECTOR)) > 0) {
che_combo = val;
if (get_che_cnum(che_combo) != target)
continue;
if (get_che_value(che_combo) + che > CHE_MAX)
continue;
}
val = getvar(V_MILIT, (s_char *)nsp, EF_SECTOR);
if (val >= min_mil)
continue;
maybe_sp = nsp;
min_mil = val;
}
/*
* if n <= 6, we found a sector owned by TARGET which
* is a nice sector. Otherwise, we move to the first
* one we find ("maybe_sp").
*/
if (maybe_sp != 0) {
che_combo = getvar(V_CHE, (s_char *)maybe_sp, EF_SECTOR);
che += get_che_value(che_combo);
set_che_value(che_combo, che);
set_che_cnum(che_combo, target);
putvar(V_CHE, (int) che_combo, (s_char *)maybe_sp, EF_SECTOR);
che = 0;
}
}
if (che > 0) {
set_che_value(che_combo, che);
set_che_cnum(che_combo, target);
putvar(V_CHE, (int) che_combo, (s_char *)sp, EF_SECTOR);
} else
putvar(V_CHE, 0, (s_char *)sp, EF_SECTOR);
if (mc > 0 || cc > 0) {
/* don't tell who won just to be mean */
wu(0, target,
"Guerrilla warfare in %s\n",
xyas(sp->sct_x, sp->sct_y, target));
wu(0, target, " body count: troops: %d, rebels: %d\n", mc, cc);
nreport(actor, N_FREEDOM_FIGHT, victim, 1);
}
}
void
take_casualties(struct sctstr *sp, int mc)
{
int orig_mil;
int cantake;
int nunits=0, each, deq;
struct lndstr *lp;
s_char *nxtitemp(struct nstr_item *np, int owner);
struct nstr_item ni;
/* casualties come out of mil first */
orig_mil = getvar(V_MILIT, (s_char *)sp, EF_SECTOR);
if (mc <= orig_mil){
putvar(V_MILIT, (orig_mil-mc), (s_char *)sp, EF_SECTOR);
return;
}
putvar(V_MILIT, 0, (s_char *)sp, EF_SECTOR);
/* remaining casualites */
mc -= orig_mil;
/*
* Need to take total_casualties and divide
* them amongst the land units in the sector
* Do security troops first, then others.
* Try not to kill any unit.
*/
snxtitem_xy(&ni, EF_LAND, sp->sct_x,sp->sct_y);
while(NULL != (lp=(struct lndstr *)nxtitemp(&ni, 0))){
nunits++;
if (lchr[(int)lp->lnd_type].l_flags & L_SECURITY)
nunits++;
}
if (nunits==0)
return;
each = (mc/nunits)+2;
/* kill some security troops */
snxtitem_xy(&ni, EF_LAND, sp->sct_x,sp->sct_y);
while(NULL != (lp=(struct lndstr *)nxtitemp(&ni, 0))){
if (!(lchr[(int)lp->lnd_type].l_flags & L_SECURITY))
continue;
cantake = (((float)(lp->lnd_effic-40)/100.0)*
(float)lnd_getmil(lp))*2;
/* (float)lchr[lp->lnd_type].l_mil)*2;*/
if (cantake >= each){
/* deq = (((float)each/(float)(lchr[lp->lnd_type].l_mil*2))*/
deq = (((float)each/(float)(lnd_getmil(lp)*2))
*100.0);
mc -= each;
}else if (cantake > 0){
deq = (((float)cantake/
(float)(lnd_getmil(lp)*2)) * 100.0);
/* (float)(lchr[lp->lnd_type].l_mil*2)) * 100.0);*/
mc -= (((float)deq/100.0)*
(float)lnd_getmil(lp))*2;
/* (float)lchr[lp->lnd_type].l_mil)*2;*/
}else
deq = 0;
lp->lnd_effic -= deq;
lp->lnd_mobil -= deq/2;
deq = (double)lchr[(int)lp->lnd_type].l_mil * (deq / 100.0);
lnd_submil(lp, deq);
if (mc<=0) return;
}
/* kill some normal troops */
snxtitem_xy(&ni, EF_LAND, sp->sct_x,sp->sct_y);
while(NULL != (lp=(struct lndstr *)nxtitemp(&ni, 0))){
if (lchr[(int)lp->lnd_type].l_flags & L_SECURITY)
continue;
cantake = (((float)(lp->lnd_effic-40)/100.0)*
(float)lnd_getmil(lp));
if (cantake >= each){
deq = (((float)each/(float)(lnd_getmil(lp)*2))
*100.0);
mc -= each;
}else if (cantake > 0){
deq = (((float)cantake/(float)lnd_getmil(lp))
* 100.0);
mc -= (((float)deq/100.0)*
(float)lnd_getmil(lp));
}else
deq = 0;
lp->lnd_effic -= deq;
lp->lnd_mobil -= deq/2;
deq = (double)lchr[(int)lp->lnd_type].l_mil * (deq / 100.0);
lnd_submil(lp, deq);
if (mc<=0) return;
}
/* Hmm.. still some left.. kill off units now */
/* kill some normal troops */
snxtitem_xy(&ni, EF_LAND, sp->sct_x,sp->sct_y);
while(NULL != (lp=(struct lndstr *)nxtitemp(&ni, 0))){
if (lchr[(int)lp->lnd_type].l_flags & L_SECURITY)
continue;
mc -= (((float)lp->lnd_effic/100.0) *
(float)lnd_getmil(lp));
lp->lnd_effic = 0;
lnd_submil(lp, 1000); /* Remove 'em all */
wu(0,lp->lnd_own,"%s dies fighting guerrillas in %s\n",
prland(lp),
xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
makelost(EF_LAND, lp->lnd_own, lp->lnd_uid, lp->lnd_x, lp->lnd_y);
lp->lnd_own = 0;
if (mc<=0) return;
}
/* Hmm.. still some left.. kill off units now */
/* kill some security troops */
snxtitem_xy(&ni, EF_LAND, sp->sct_x,sp->sct_y);
while(NULL != (lp = (struct lndstr *)nxtitemp(&ni, 0))){
if (!(lchr[(int)lp->lnd_type].l_flags & L_SECURITY))
continue;
mc -= (((float)lp->lnd_effic / 100.0) * (float)lnd_getmil(lp)) * 2;
lp->lnd_effic = 0;
lnd_submil(lp, 1000); /* Kill 'em all */
wu(0, lp->lnd_own, "%s dies fighting guerrillas in %s\n",
prland(lp),
xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
makelost(EF_LAND, lp->lnd_own, lp->lnd_uid, lp->lnd_x, lp->lnd_y);
lp->lnd_own = 0;
if (mc <= 0)
return;
}
/* Hmm.. everyone dead.. too bad */
}

352
src/lib/update/sail.c Normal file
View file

@ -0,0 +1,352 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* sail.c: Sail ships during the update
*
* Known contributors to this file:
* Doug Hay
* Robert Forsman
* Ken Stevens, 1995
* Steve McClure, 1998-2000
*/
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "path.h"
#include "ship.h"
#include "var.h"
#include "news.h"
#include "file.h"
#include "nat.h"
#include "xy.h"
#include "nsc.h"
#include "update.h"
#include "subs.h"
#include "common.h"
#include <stdlib.h>
static void
cost_ship(struct shpstr *sp, struct fltelemstr *ep, struct fltheadstr *fp)
{
double mobcost,ceil(double);
int howfar;
mobcost = 0.0;
if (sp->shp_effic > 0) {
mobcost = sp->shp_effic * sp->shp_speed * 0.01;
mobcost = 480.0 / ( mobcost*(1 + (50+sp->shp_tech)/
(double)(200+sp->shp_tech)));
}
/* the next two lines are not necessary since shp_mobquota is unsigned
and therefore cannot be less than 0.
if (sp->shp_mobquota<0)
sp->shp_mobquota=0;
*/
howfar = 0;
if (mobcost > 0) {
howfar = (int)sp->shp_mobil - (int)sp->shp_mobquota;
howfar = ceil((howfar / mobcost));
}
if (howfar<0)
howfar=0;
#ifdef SAILDEBUG
wu(0,fp->own,
"Ship #%d can move %d spaces on mobility %d (cost/sect %f)\n",
sp->shp_uid, howfar, sp->shp_mobil, mobcost);
#endif
if ((unsigned int)howfar < fp->maxmoves)
fp->maxmoves = howfar;
ep->mobil = sp->shp_mobil;
ep->mobcost = mobcost;
}
static int
sail_find_fleet(struct fltheadstr **head, struct shpstr *sp)
{
struct fltheadstr *fltp;
struct shpstr *ap;
struct fltelemstr *this;
int len=0;
int follow = -1;
int stop;
s_char *cp;
if (sp->shp_own==0)
return(0);
/* If this ship is following, find the head of the follow list. */
for (ap=sp; ap; len++, ap=getshipp(follow)) {
follow = ap->shp_follow;
/* Not same owner */
if (ap->shp_own != sp->shp_own) {
wu(0, sp->shp_own,
"Ship #%d, following #%d, which you don't own.\n",
sp->shp_uid, ap->shp_uid);
return(0);
}
/* Not a follower. */
if (ap->shp_path[0] != 'f')
break;
/* Following itself */
if (follow==ap->shp_uid ||
follow==sp->shp_uid)
break;
}
if (!ap) {
wu(0, sp->shp_own,
"Ship #%d, following #%d, which you don't own.\n",
sp->shp_uid, follow);
return(0);
}
/* This should prevent infinite loops. */
if (len>=10) {
wu(0,sp->shp_own,
"Ship #%d, too many follows (circular follow?).\n",
sp->shp_uid);
return(0);
}
for (stop=0,cp=ap->shp_path; (!stop) && (*cp); cp++) {
switch (*cp) {
case 'y':
case 'u':
case 'g':
case 'j':
case 'b':
case 'n':
case 'h':
case 't':
break;
default:
stop=1;
}
}
/* we found a non-valid char in the path. */
if (*cp) {
wu(0,ap->shp_own, "invalid char '\\%03o' in path of ship %d\n",
(unsigned char)*cp, ap->shp_uid);
*cp=0;
}
/* if this ship is not sailing anywhere then ignore it. */
if (!*ap->shp_path)
return(0);
/* Find the fleet structure we belong to. */
for (fltp=(*head); (fltp && fltp->leader != follow); fltp = fltp->next)
;
if (!fltp) {
fltp = (struct fltheadstr *) malloc(sizeof(*fltp));
bzero((s_char *)fltp, sizeof(*fltp));
/* Fix the links. */
fltp->next = (*head);
*head = fltp;
/* Set the leader. */
fltp->leader = ap->shp_uid;
fltp->real_q = LEADER_REAL;
fltp->x = ap->shp_x;
fltp->y = ap->shp_y;
fltp->own = ap->shp_own;
fltp->maxmoves = 500;
}
/* If the fleet is not in the same sector as us, no go. */
if ( ( fltp->x!=sp->shp_x ) || ( fltp->y!=sp->shp_y ) ) {
wu(0,sp->shp_own,
"Ship %d not in same sector as its sailing fleet\n",
sp->shp_uid);
fltp->real_q = LEADER_WRONGSECT;
return(0);
}
this = (struct fltelemstr *) malloc(sizeof(*this));
bzero((s_char *)this, sizeof(*this));
this->num = sp->shp_uid;
this->own = sp->shp_own;
this->next = fltp->head;
fltp->head = this;
cost_ship(sp, this, fltp);
return 1;
}
static int
sail_nav_fleet(struct fltheadstr *fltp)
{
struct fltelemstr *fe;
struct shpstr *sp, ship;
int vec[I_MAX+1];
struct sctstr *sectp;
int error=0;
s_char *s, *p;
natid own;
struct emp_qelem ship_list;
int dir;
#ifdef SAILDEBUG
switch (fltp->real_q) {
case LEADER_VIRTUAL:
s = "leaderless";
break;
case LEADER_REAL:
s = "real";
break;
case LEADER_WRONGSECT:
s = "scattered";
break;
default:
s = "inconsistent";
}
wu(0,fltp->own,
"Fleet lead by %d is %s, can go %d spaces\n contains ships:",
fltp->leader, s, fltp->maxmoves);
for (fe=fltp->head; fe; fe = fe->next)
wu(0, fltp->own, " %d", fe->num);
wu(0, fltp->own, "\n");
#endif
sectp = getsectp(fltp->x, fltp->y);
switch (check_nav(sectp)) {
case CN_NAVIGABLE:
break;
case CN_CONSTRUCTION:
case CN_LANDLOCKED:
default:
wu(0,fltp->own, "Your fleet lead by %d is trapped by land.\n",
fltp->leader);
return(0);
}
for (fe=fltp->head; fe; fe = fe->next) {
sp = getshipp(fe->num);
getvec(VT_ITEM, vec, (s_char *)sp, EF_SHIP);
if (vec[I_MILIT]==0 && vec[I_CIVIL]==0) {
wu(0,fltp->own,
" ship #%d (%s) is crewless and can't go on\n",
fe->num, cname(fe->own));
error = 1;
}
}
if (error)
return(0);
sp = getshipp(fltp->leader);
own = sp->shp_own;
fltp_to_list(fltp, &ship_list); /* hack -KHS 1995 */
for (s=sp->shp_path; (*s) && (fltp->maxmoves>0); s++) {
dir = chkdir(*s, DIR_STOP, DIR_LAST);
if (0 != (error = shp_nav_one_sector(&ship_list, dir, own, 0)))
fltp->maxmoves = 1;
--(fltp->maxmoves);
}
shp_put(&ship_list, own);
getship(sp->shp_uid, &ship);
fltp->x = ship.shp_x;
fltp->y = ship.shp_y;
for (p=&ship.shp_path[0]; *s; p++,s++)
*p = *s;
*p = 0;
putship(ship.shp_uid, &ship);
#ifdef SAILDEBUG
if (sp->shp_path[0]) {
wu(0,fltp->own,
"Fleet lead by #%d nav'd to %s, path left = %s\n",
fltp->leader, xyas(fltp->x,fltp->y,fltp->own),
&sp->shp_path);
} else
wu(0,fltp->own,
"Fleet lead by #%d nav'd to %s, finished.\n",
fltp->leader, xyas(fltp->x,fltp->y,fltp->own));
wu(0,sp->shp_own, "Ship #%d has %d mobility now.\n",
fe->num, (int)fe->mobil);
#endif
return 1;
}
void
sail_ship(natid cn)
{
struct shpstr *sp;
struct fltheadstr *head=0;
struct fltheadstr *fltp;
int n;
for (n=0; NULL != (sp = getshipp(n)); n++) if (sp->shp_own==cn) {
sail_find_fleet(&head, sp);
}
/* see what the fleets fall out into */
for (fltp=head; fltp; fltp = fltp->next) {
sail_nav_fleet(fltp);
wu(0,fltp->own, "Your fleet lead by ship #%d has reached %s.\n",
fltp->leader,xyas(fltp->x,fltp->y,fltp->own));
}
/* Free up the memory, 'cause I want to. */
for (fltp=head; fltp!=0; ) {
struct fltelemstr *fe;
struct fltheadstr *saveh;
saveh = fltp->next;
for (fe=fltp->head; fe!=0; ) {
struct fltelemstr *saveel;
saveel = fe->next;
free(fe);
fe = saveel;
}
free(fltp);
fltp = saveh;
}
}
/* The following is a total hack by Ken Stevens to cut down dramatically on repeated code 1995 */
void
fltp_to_list(struct fltheadstr *fltp, struct emp_qelem *list)
{
struct fltelemstr *fe;
struct mlist *mlp;
struct shpstr *sp;
emp_initque(list);
for (fe=fltp->head; fe; fe = fe->next) {
mlp = (struct mlist *) malloc(sizeof(struct mlist));
sp = getshipp(fe->num);
mlp->mcp = mchr + sp->shp_type;
bcopy((s_char *)sp, (s_char *)&mlp->ship,
sizeof(struct shpstr));
mlp->mobil = fe->mobil;
emp_insque(&mlp->queue, list);
}
}

510
src/lib/update/sect.c Normal file
View file

@ -0,0 +1,510 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* sect.c: Do production for sectors
*
* Known contributors to this file:
* Dave Pare, 1986
* Steve McClure, 1996
*/
#include <math.h>
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "nat.h"
#include "item.h"
#include "news.h"
#include "file.h"
#include "xy.h"
#include "path.h"
#include "product.h"
#include "distribute.h"
#include "optlist.h"
#include "budg.h"
#include "player.h"
#include "land.h"
#include "ship.h"
#include "update.h"
#include "subs.h"
#include "common.h"
#include "lost.h"
#include "gen.h"
extern float levels[MAXNOC][4];
int
dodeliver(struct sctstr *sp, int *vec)
{
register int i;
int del[I_MAX+1];
int thresh;
int dir;
int plague;
int n;
int changed;
if (sp->sct_mobil <= 0)
return 0;
if (getvec(VT_DEL, del, (s_char *)sp, EF_SECTOR) <= 0)
return 0;
changed = 0;
plague = getvar(V_PSTAGE, (s_char *)sp, EF_SECTOR);
for (i=1; i<=I_MAX; i++) {
if (del[i] == 0)
continue;
thresh = del[i] & ~0x7;
dir = del[i] & 0x7;
n = deliver(sp, &ichr[i], dir, thresh, vec[i], plague);
if (n > 0) {
vec[i] -= n;
changed++;
if (sp->sct_mobil <= 0)
break;
}
}
return changed;
}
/*
* Increase sector efficiency if old type == new type.
* decrease sector efficiency if old type != new type.
* Return amount of work used.
*/
int
upd_buildeff(struct natstr *np, register struct sctstr *sp, int *workp, int *vec, int etu, int *desig, int sctwork, int *cost)
{
register int work_cost = 0;
int buildeff_work = (int)(*workp / 2);
int n, hcms, lcms, neweff;
u_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 (opt_BIG_CITY) {
if (!n && dchr[old_type].d_pkg == UPKG &&
dchr[*desig].d_pkg != UPKG) {
int maxpop = max_pop(np->nat_level[NAT_RLEV], sp);
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 (np->nat_priorities[*desig]) {
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/2 + buildeff_work;
return neweff;
}
/*
* enlistment sectors are special; they require military
* to convert civ into mil in large numbers.
* Conversion will happen much more slowly without
* some mil initially.
*/
int
enlist(register int *vec, int etu, int *cost)
{
int maxmil;
int enlisted;
/* Need to check treaties here */
enlisted = 0;
maxmil = (vec[I_CIVIL] / 2) - vec[I_MILIT];
if (maxmil > 0) {
enlisted = (etu * (10 + vec[I_MILIT]) * 0.05);
if (enlisted > maxmil)
enlisted = maxmil;
vec[I_CIVIL] -= enlisted;
vec[I_MILIT] += enlisted;
}
*cost = enlisted * 3;
return enlisted;
}
/* Fallout is calculated here. */
extern int melt_item_denom[];
void
meltitems(int etus, int fallout, int own, int *vec, int type, int x, int y, int uid)
{
int n;
int melt;
for (n = 1; n <= I_MAX; n++) {
melt = roundavg(vec[n] * etus * (long)fallout /
(1000.0 * melt_item_denom[n]));
if (melt > 5 && own) {
if (type == EF_SECTOR)
wu(0, own, "Lost %d %s to radiation in %s.\n",
(melt < vec[n] ? melt : vec[n]), 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 < vec[n] ? melt : vec[n]), 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 < vec[n] ? melt : vec[n]), ichr[n].i_name,
xyas(x, y, own));
}
if (melt < vec[n])
vec[n] -= melt;
else
vec[n] = 0;
}
}
/*
* do_fallout - calculate fallout for sectors.
*
* This is etu based. But, do limit HUGE kill offs in large ETU
* games, the melting etus rate is limited to 24 etus.
*/
void
do_fallout(register struct sctstr *sp, register int etus)
{
int vec[I_MAX+1];
int cvec[I_MAX+1];
int tvec[I_MAX+1];
struct shpstr *spp;
struct lndstr *lp;
int i;
getvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
getvec(VT_COND, cvec, (s_char *)sp, EF_SECTOR);
/* This check shouldn't be needed, but just in case. :) */
if (!cvec[C_FALLOUT] || !sp->sct_updated)
return;
if (etus > 24)
etus = 24;
#if 0
wu(0,0,"Running fallout in %d,%d\n", sp->sct_x, sp->sct_y);
#endif
meltitems(etus, cvec[C_FALLOUT], sp->sct_own, vec, EF_SECTOR,
sp->sct_x, sp->sct_y, 0);
putvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
for (i = 0; NULL != (lp = getlandp(i)); i++) {
if (!lp->lnd_own)
continue;
if (lp->lnd_x != sp->sct_x || lp->lnd_y != sp->sct_y)
continue;
getvec(VT_ITEM, tvec, (s_char *)lp, EF_LAND);
meltitems(etus, cvec[C_FALLOUT], lp->lnd_own, tvec, EF_LAND,
lp->lnd_x, lp->lnd_y, lp->lnd_uid);
putvec(VT_ITEM, tvec, (s_char *)lp, EF_LAND);
}
for (i = 0; NULL != (spp = getshipp(i)); i++) {
if (!spp->shp_own)
continue;
if (spp->shp_x != sp->sct_x || spp->shp_y != sp->sct_y)
continue;
if (mchr[(int)spp->shp_type].m_flags & M_SUB)
continue;
getvec(VT_ITEM, tvec, (s_char *)spp, EF_SHIP);
meltitems(etus, cvec[C_FALLOUT], spp->shp_own, tvec, EF_SHIP,
spp->shp_x, spp->shp_y, spp->shp_uid);
putvec(VT_ITEM, tvec, (s_char *)spp, EF_SHIP);
}
#ifdef GODZILLA
if ((cvec[C_FALLOUT] > 20) && chance(100))
do_godzilla(sp);
#endif /* GODZILLA */
}
void
spread_fallout(struct sctstr *sp, int etus)
{
extern double fallout_spread;
struct sctstr *ap;
int tvec[I_MAX+1];
int cvec[I_MAX+1];
int n;
register int inc;
if (etus > 24)
etus = 24;
getvec(VT_COND, cvec, (s_char *)sp, EF_SECTOR);
for (n = DIR_FIRST; n <= DIR_LAST; n++) {
ap = getsectp(sp->sct_x+diroff[n][0], sp->sct_y+diroff[n][1]);
getvec(VT_COND, tvec, (char *)ap, EF_SECTOR);
if (ap->sct_type == SCT_SANCT)
continue;
inc = roundavg(etus * fallout_spread * (cvec[C_FALLOUT])) - 1;
#if 0
if (cvec[C_FALLOUT]) {
wu(0,0,"Fallout from sector %d,%d to %d,%d is %d=%d*%e*%d\n",
sp->sct_x,sp->sct_y,sp->sct_x+diroff[n][0],
sp->sct_y+diroff[n][1], inc, etus,
fallout_spread, cvec[C_FALLOUT]);
}
#endif
if (inc < 0)
inc = 0;
tvec[C_FALLOUT] += inc;
putvec(VT_COND, tvec, (char *)ap, EF_SECTOR);
}
}
void
decay_fallout(struct sctstr *sp, int etus)
{
extern double decay_per_etu;
extern double fallout_spread;
int cvec[I_MAX+1];
int decay;
if (etus > 24)
etus = 24;
getvec(VT_COND, cvec, (char *)sp, EF_SECTOR);
decay = roundavg(((decay_per_etu + 6.0) * fallout_spread) *
(double)etus * (double)cvec[C_FALLOUT]);
#if 0
if (decay || cvec[C_FALLOUT])
wu(0,0,"Fallout decay in %d,%d is %d from %d\n", sp->sct_x, sp->sct_y, decay, cvec[C_FALLOUT]);
#endif
cvec[C_FALLOUT] = (decay < cvec[C_FALLOUT]) ? (cvec[C_FALLOUT] - decay) : 0;
if (cvec[C_FALLOUT] < 0)
cvec[C_FALLOUT] = 0;
putvec(VT_COND, cvec, (s_char *)sp, EF_SECTOR);
}
#define SHOULD_PRODUCE(sp,t) (((sp->sct_type == t) || (t == -1)) ? 1 : 0)
/*
* Produce only a set sector type for a specific nation
* (or all, if sector_type == -1)
*
*/
void
produce_sect(int natnum, int etu, int *bp, long int (*p_sect)[2], int sector_type)
{
register struct sctstr *sp;
register struct natstr *np;
int vec[I_MAX+1];
int work, cost, ecost, pcost, sctwork;
int n, desig, maxpop, neweff, amount;
for (n=0; NULL != (sp = getsectid(n)); n++) {
if (sp->sct_type == SCT_WATER)
continue;
if (sp->sct_own != natnum)
continue;
if (sp->sct_updated != 0)
continue;
if (!SHOULD_PRODUCE(sp,sector_type))
continue;
if ((sp->sct_type == SCT_CAPIT) && (sp->sct_effic > 60)) {
p_sect[SCT_CAPIT][0]++;
p_sect[SCT_CAPIT][1] += etu;
}
if (getvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR) <= 0)
continue;
/* If everybody is dead, the sector reverts to unowned.
* This is also checked at the end of the production in
* they all starved or were plagued off.
*/
if (vec[I_CIVIL] == 0 && vec[I_MILIT] == 0 &&
!has_units(sp->sct_x,sp->sct_y,sp->sct_own,0)) {
makelost(EF_SECTOR, sp->sct_own, 0, sp->sct_x, sp->sct_y);
sp->sct_own = 0;
sp->sct_oldown = 0;
continue;
}
sp->sct_updated = 1;
work = 0;
np = getnatp(natnum);
/* do_feed trys to supply. So, we need to enable cacheing
here */
bp_enable_cachepath();
sctwork = do_feed(sp, np, vec, &work, bp, etu);
bp_disable_cachepath();
bp_clear_cachepath();
if (sp->sct_off || np->nat_money < 0) {
if (!player->simulation) {
putvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
sp->sct_off = 0;
}
continue;
}
if ((np->nat_priorities[sp->sct_type] == 0) &&
(sp->sct_type == sp->sct_newtype) &&
((pchr[dchr[sp->sct_type].d_prd].p_cost != 0) ||
(sp->sct_type == SCT_ENLIST))){
if (!player->simulation) {
putvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
logerror("Skipping %s production for country %s\n",
dchr[sp->sct_type].d_name,np->nat_cnam);
}
continue;
}
neweff = sp->sct_effic;
amount = 0;
pcost = cost = ecost = 0;
desig = sp->sct_type;
if ((sp->sct_effic < 100 || sp->sct_type != sp->sct_newtype) &&
np->nat_money > 0) {
neweff = upd_buildeff(np, sp, &work, vec, etu, &desig, sctwork, &cost);
pt_bg_nmbr(bp, sp, I_LCM, vec[I_LCM]);
pt_bg_nmbr(bp, sp, I_HCM, vec[I_HCM]);
p_sect[SCT_EFFIC][0]++;
p_sect[SCT_EFFIC][1] += cost;
if (!player->simulation) {
np->nat_money -= cost;
/* No longer tear down infrastructure
if (sp->sct_type != desig) {
sp->sct_road = 0;
sp->sct_defense = 0;
} else if (neweff < sp->sct_effic) {
sp->sct_road -= (sp->sct_road * (sp->sct_effic - neweff) / 100.0);
sp->sct_defense -= (sp->sct_defense * (sp->sct_effic - neweff) / 100.0);
if (sp->sct_road < 0)
sp->sct_road = 0;
if (sp->sct_defense < 0)
sp->sct_defense = 0;
}
*/
sp->sct_type = desig;
sp->sct_effic = neweff;
if (!opt_DEFENSE_INFRA)
sp->sct_defense = sp->sct_effic;
}
}
if ((np->nat_priorities[desig] == 0) &&
((pchr[dchr[desig].d_prd].p_cost != 0) ||
(desig == SCT_ENLIST))) {
if (!player->simulation) {
putvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
logerror("Skipping %s production for country %s\n",
dchr[sp->sct_type].d_name,np->nat_cnam);
}
continue;
}
if (desig == SCT_ENLIST && neweff >= 60 &&
sp->sct_own == sp->sct_oldown) {
p_sect[desig][0] += enlist(vec, etu, &ecost);
p_sect[desig][1] += ecost;
if (!player->simulation)
np->nat_money -= ecost;
}
/*
* now do the production (if sector effic >= 60%)
*/
if (neweff >= 60) {
if (np->nat_money > 0 && dchr[desig].d_prd)
work -= produce(np, sp, vec, work, sctwork, desig, neweff, &pcost, &amount);
}
pt_bg_nmbr(bp, sp, I_MAX+1, work);
p_sect[desig][0] += amount;
p_sect[desig][1] += pcost;
if (!player->simulation) {
maxpop = max_pop(np->nat_level[NAT_RLEV], sp);
if (vec[I_CIVIL] > maxpop)
vec[I_CIVIL] = maxpop;
if (vec[I_UW] > maxpop)
vec[I_UW] = maxpop;
putvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
sp->sct_avail = work;
np->nat_money -= pcost;
}
}
}

529
src/lib/update/ship.c Normal file
View file

@ -0,0 +1,529 @@
/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2000, 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.
*
* ---
*
* ship.c: Do production for ships
*
* Known contributors to this file:
* Dave Pare, 1986
* Steve McClure, 1996
*/
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "nat.h"
#include "ship.h"
#include "var.h"
#include "news.h"
#include "file.h"
#include "product.h"
#include "land.h"
#include "xy.h"
#include "nsc.h"
#include "optlist.h"
#include "player.h"
#include "update.h"
#include "common.h"
#include "subs.h"
#include "gen.h"
#include "lost.h"
#ifndef MIN
#define MIN(x,y) ((x) > (y) ? (y) : (x))
#endif
int
prod_ship(int etus, int natnum, int *bp, int build)
/* build = 1, maintain = 0 */
{
register struct shpstr *sp;
struct natstr *np;
int n, k=0;
extern long sea_money[MAXNOC];
int start_money;
int lastx = 9999, lasty = 9999;
bp_enable_cachepath();
for (n=0; NULL != (sp = getshipp(n)); n++) {
if (sp->shp_own == 0)
continue;
if (sp->shp_own != natnum)
continue;
np = getnatp(sp->shp_own);
start_money = np->nat_money;
if (lastx == 9999 || lasty == 9999) {
lastx = sp->shp_x;
lasty = sp->shp_y;
}
if (lastx != sp->shp_x || lasty != sp->shp_y) {
/* Reset the cache */
bp_disable_cachepath();
bp_clear_cachepath();
bp_enable_cachepath();
}
upd_ship(sp, n, etus, np, bp, build);
if (build && !player->simulation) /* make sure to only autonav once */
nav_ship(sp); /* autonav the ship */
sea_money[sp->shp_own] += np->nat_money - start_money;
if ((build && (np->nat_money != start_money)) || (!build))
k++;
if (player->simulation)
np->nat_money = start_money;
}
bp_disable_cachepath();
bp_clear_cachepath();
if (opt_SAIL) {
if (build && !player->simulation) /* make sure to only sail once */
sail_ship(natnum);
}
return k;
}
void
upd_ship(register struct shpstr *sp, int shipno, register int etus, struct natstr *np, int *bp, int build)
/* build = 1, maintain = 0 */
{
extern long pops[];
struct sctstr *sectp;
struct mchrstr *mp;
int vec[I_MAX+1];
int cvec[I_MAX+1];
int oil_gained;
int max_oil;
int max_food;
struct pchrstr *product;
s_char *resource;
int n;
int mult;
extern double money_ship;
int needed;
int cost;
int eff;
mp = &mchr[(int)sp->shp_type];
getvec(VT_ITEM, vec, (s_char *)sp, EF_SHIP);
if (build == 1){
if (np->nat_priorities[PRI_SBUILD] == 0 ||
np->nat_money < 0)
return;
if (sp->shp_effic < SHIP_MINEFF ||
!shiprepair(sp, vec, np, bp, etus)) {
makelost(EF_SHIP, sp->shp_own, sp->shp_uid, sp->shp_x, sp->shp_y);
sp->shp_own = 0;
return;
}
}else{
mult = 1;
if (np->nat_level[NAT_TLEV] < sp->shp_tech * 0.85)
mult = 2;
cost = -(mult * etus * dmin(0.0, money_ship * mp->m_cost));
if ((np->nat_priorities[PRI_SMAINT] == 0 ||
np->nat_money < cost) && !player->simulation){
if ((eff = sp->shp_effic - etus/5) < SHIP_MINEFF) {
wu(0, sp->shp_own,
"%s lost to lack of maintenance\n",
prship(sp));
makelost(EF_SHIP, sp->shp_own, sp->shp_uid, sp->shp_x, sp->shp_y);
sp->shp_own = 0;
return;
}
wu(0, sp->shp_own,
"%s lost %d%% to lack of maintenance\n",
prship(sp), sp->shp_effic - eff);
sp->shp_effic = eff;
} else {
np->nat_money -= cost;
}
sectp = getsectp(sp->shp_x, sp->shp_y);
if (((mp->m_flags & M_OIL) && (sectp->sct_type == SCT_WATER))
&& !player->simulation){
/*
* take care of oil production
*/
oil_gained = roundavg((vec[I_CIVIL] * etus / 10000.0)
* sectp->sct_oil);
vec[I_OIL] += oil_gained;
max_oil = vl_find(V_OIL,mp->m_vtype,mp->m_vamt,mp->m_nv);
if (vec[I_OIL] > max_oil)
vec[I_OIL] = max_oil;
product = &pchr[P_OIL];
if (product->p_nrdep != 0 && oil_gained > 0) {
resource = ((s_char *)sectp) + product->p_nrndx;
*resource -= roundavg(oil_gained *
product->p_nrdep / 100.0);
}
} else if (((mp->m_flags&M_FOOD)&&(sectp->sct_type==SCT_WATER)) && !player->simulation){
sectp = getsectp(sp->shp_x, sp->shp_y);
vec[I_FOOD] += ((vec[I_CIVIL] * etus) / 1000.0)
* sectp->sct_fertil;
}
/* Military costs are now part of regular military costs, not ship costs */
/* np->nat_money += (int) (etus * vec[I_MILIT] * money_mil);*/
if (!player->simulation){
if ((n = feed_ship(sp,vec,etus, &needed, 1)) > 0) {
wu(0, sp->shp_own, "%d starved on %s\n",
n, prship(sp));
if (n > 10)
nreport(sp->shp_own, N_DIE_FAMINE, 0, 1);
}
max_food = vl_find(V_FOOD, mp->m_vtype, mp->m_vamt, mp->m_nv);
if (vec[I_FOOD] > max_food)
vec[I_FOOD] = max_food;
/*
* do plague stuff. plague can't break out on ships,
* but it can still kill people.
*/
getvec(VT_COND, cvec, (s_char *)sp, EF_SHIP);
if (cvec[C_PSTAGE] > 0) {
n = plague_people(np, vec, cvec, etus);
switch (n) {
case PLG_DYING:
wu(0, sp->shp_own,
"PLAGUE deaths reported on %s\n",
prship(sp));
nreport(sp->shp_own, N_DIE_PLAGUE, 0, 1);
break;
case PLG_INFECT:
wu(0, sp->shp_own, "%s battling PLAGUE\n",
prship(sp));
break;
case PLG_INCUBATE:
/* Are we still incubating? */
if (n == cvec[C_PSTAGE]) {
/* Yes. Will it turn "infectious" next time? */
if (cvec[C_PTIME] <= etus) {
/* Yes. Report an outbreak. */
wu(0, sp->shp_own,
"Outbreak of PLAGUE on %s!\n",
prship(sp));
nreport(sp->shp_own, N_OUT_PLAGUE, 0, 1);
}
} else {
/* It has already moved on to "infectious" */
wu(0, sp->shp_own,
"%s battling PLAGUE\n", prship(sp));
}
break;
case PLG_EXPOSED:
/* Has the plague moved to "incubation" yet? */
if (n != cvec[C_PSTAGE]) {
/* Yes. Will it turn "infectious" next time? */
if (cvec[C_PTIME] <= etus) {
/* Yes. Report an outbreak. */
wu(0, sp->shp_own,
"Outbreak of PLAGUE on %s!\n",
prship(sp));
nreport(sp->shp_own, N_OUT_PLAGUE, 0, 1);
}
}
break;
default:
break;
}
putvec(VT_COND, cvec, (s_char *)sp, EF_SHIP);
}
putvec(VT_ITEM, vec, (s_char *)sp, EF_SHIP);
pops[sp->shp_own] += vec[I_CIVIL];
}
}
}
/*
* idea is: a sector full of workers can fix up eight
* battleships +8 % eff each etu. This will cost around
* 8 * 8 * $40 = $2560!
*/
int
shiprepair(register struct shpstr *ship, int *vec, struct natstr *np, int *bp, int etus)
{
extern int ship_grow_scale;
register int delta;
struct sctstr *sp;
struct mchrstr *mp;
float leftp, buildp;
int left, build;
int lcm_needed, hcm_needed;
int wf;
int avail;
int w_p_eff;
int mult;
int svec[I_MAX+1];
int mvec[I_MAX+1];
int rel;
mp = &mchr[(int)ship->shp_type];
sp = getsectp(ship->shp_x, ship->shp_y);
if ((sp->sct_own != ship->shp_own) && (sp->sct_own != 0)) {
rel=getrel(getnatp(sp->sct_own),ship->shp_own);
if (rel < FRIENDLY)
return 1;
}
wf = 0;
/* only military can work on a military boat */
if (ship->shp_glim > 0)
wf = etus * vec[I_MILIT]/2;
else
wf = etus * (vec[I_CIVIL]/2 + vec[I_MILIT]/5);
if (sp->sct_type != SCT_HARBR){
wf /= 3;
avail = wf;
}else{
if (!player->simulation)
avail = wf + sp->sct_avail * 100;
else
avail = wf + gt_bg_nmbr(bp, sp, I_MAX+1) * 100;
}
w_p_eff = 20 + (mp->m_lcm + 2 * mp->m_hcm);
if (sp->sct_type != SCT_HARBR){
int abs_max, amt;
if (ship->shp_glim > 0){
abs_max = vl_find(V_MILIT, mp->m_vtype,
mp->m_vamt, (int) mp->m_nv);
amt = vec[I_MILIT];
}else{
abs_max = vl_find(V_CIVIL, mp->m_vtype,
mp->m_vamt, (int) mp->m_nv);
amt = vec[I_CIVIL];
if (abs_max==0) {
abs_max = vl_find(V_MILIT, mp->m_vtype, mp->m_vamt,
(int) mp->m_nv);
amt = vec[I_MILIT];
}
}
if (abs_max == 0){
logerror("Abs max of 0 for ship %d\n",ship->shp_uid);
abs_max = 1;
}
avail -= (etus * (100-((amt*100)/abs_max)))/7;
/* think of it as entropy in action */
}
if (avail <= 0){
if (!player->simulation) {
if (opt_SHIP_DECAY) {
ship->shp_effic += avail/w_p_eff;
}
return 1;
}
}
if ((sp->sct_off) && (sp->sct_own == ship->shp_own))
return 1;
getvec(VT_ITEM, svec, (s_char *)sp, EF_SECTOR);
mult = 1;
if (np->nat_level[NAT_TLEV] < ship->shp_tech * 0.85)
mult = 2;
if (ship->shp_effic == 100) {
/* ship is ok; no repairs needed */
return 1;
}
left = 100 - ship->shp_effic;
delta = roundavg((double)avail/w_p_eff);
if (delta <= 0)
return 1;
if (delta > etus*ship_grow_scale)
delta = etus*ship_grow_scale;
if (delta > left)
delta = left;
/* delta is the max amount we can grow */
left = 100 - ship->shp_effic;
if (left > delta)
left = delta;
leftp = ((float)left/100.0);
bzero((s_char *)mvec, sizeof(mvec));
mvec[I_LCM] = lcm_needed = ldround((double)(mp->m_lcm * leftp),1);
mvec[I_HCM] = hcm_needed = ldround((double)(mp->m_hcm * leftp),1);
get_materials(sp, bp, mvec, 0);
if (mvec[I_LCM]>=lcm_needed)
buildp=leftp;
else
buildp=((float)mvec[I_LCM]/(float)mp->m_lcm);
if (mvec[I_HCM] < hcm_needed)
buildp = MIN(buildp,((float)mvec[I_HCM]/(float)mp->m_hcm));
build=ldround((double)(buildp*100.0),1);
bzero((s_char *)mvec, sizeof(mvec));
mvec[I_LCM] = lcm_needed = roundavg((double)(mp->m_lcm * buildp));
mvec[I_HCM] = hcm_needed = roundavg((double)(mp->m_hcm * buildp));
get_materials(sp, bp, mvec, 1);
if (sp->sct_type != SCT_HARBR)
build = delta;
wf -= build * w_p_eff;
if (wf < 0) {
/*
* I didn't use roundavg here, because I want to penalize
* the player with a large number of ships.
*/
if (!player->simulation)
avail = (sp->sct_avail * 100 + wf) / 100;
else
avail = (gt_bg_nmbr(bp,sp,I_MAX+1) * 100 + wf) / 100;
if (avail < 0)
avail = 0;
if (!player->simulation)
sp->sct_avail = avail;
else
pt_bg_nmbr(bp, sp, I_MAX+1, avail);
}
if (sp->sct_type != SCT_HARBR)
if ((build+ship->shp_effic)>80){
build = 80 - ship->shp_effic;
if (build < 0)
build = 0;
}
np->nat_money -= mult * mp->m_cost * build / 100.0;
if (!player->simulation)
ship->shp_effic += (s_char)build;
return 1;
}
/*
* returns the number who starved, if any.
*/
int
feed_ship(struct shpstr *sp, register int *vec, int etus, int *needed, int doit)
{
extern double eatrate;
double food_eaten, land_eaten;
double people_left;
int ifood_eaten;
int can_eat, need;
int total_people;
int to_starve;
int starved, lvec[I_MAX+1];
struct nstr_item ni;
struct lndstr *lp;
s_char *nxtitemp(struct nstr_item *np, int owner);
if (opt_NOFOOD) return 0; /* no food no work to do */
food_eaten = (etus * eatrate) * (vec[I_CIVIL]+vec[I_MILIT]+vec[I_UW]);
ifood_eaten = (int)food_eaten;
if ((food_eaten-ifood_eaten) > 0)
ifood_eaten++;
starved = 0;
*needed = 0;
if (!player->simulation &&
food_eaten > vec[I_FOOD])
vec[I_FOOD] += supply_commod(sp->shp_own,sp->shp_x,sp->shp_y,
I_FOOD,(ifood_eaten-vec[I_FOOD]));
if (food_eaten > vec[I_FOOD]) {
/* doit - only steal food from land units during the update */
if (sp->shp_nland > 0 && doit) {
snxtitem_all(&ni,EF_LAND);
while((lp=(struct lndstr *)nxtitemp(&ni, 0)) &&
(food_eaten > vec[I_FOOD])){
if (lp->lnd_ship != sp->shp_uid)
continue;
need = ifood_eaten - vec[I_FOOD];
getvec(VT_ITEM, lvec, (s_char *)lp, EF_LAND);
land_eaten = (etus * eatrate) *
(double)lnd_getmil(lp);
if (lvec[I_FOOD]-need > land_eaten){
vec[I_FOOD] += need;
lvec[I_FOOD] -= need;
}else if ((lvec[I_FOOD]-land_eaten) > 0){
vec[I_FOOD]+= (lvec[I_FOOD]-land_eaten);
lvec[I_FOOD]-=(lvec[I_FOOD]-land_eaten);
}
putvec(VT_ITEM, lvec, (s_char *)lp, EF_LAND);
}
}
}
if (food_eaten > vec[I_FOOD]){
*needed = food_eaten - vec[I_FOOD];
if (*needed < (food_eaten - vec[I_FOOD]))
(*needed)++;
if (opt_NEW_STARVE) {
can_eat = (vec[I_FOOD] / (etus * eatrate));
total_people = vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW];
/* only want to starve off at most 1/2 the populace. */
if (can_eat < (total_people/2))
can_eat = total_people/2;
to_starve = total_people - can_eat;
while(to_starve && vec[I_UW]){
to_starve--;
starved++;
vec[I_UW]--;
}
while(to_starve && vec[I_CIVIL]){
to_starve--;
starved++;
vec[I_CIVIL]--;
}
while(to_starve && vec[I_MILIT]){
to_starve--;
starved++;
vec[I_MILIT]--;
}
vec[I_FOOD] = 0;
}
else { /* ! opt_NEW_STARVE */
people_left = (vec[I_FOOD] + 0.01) / (food_eaten + 0.01);
starved = vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW];
/* only want to starve off at most 1/2 the populace. */
if (people_left < 0.5)
people_left = 0.5;
vec[I_CIVIL] = (int) (vec[I_CIVIL] * people_left);
vec[I_MILIT] = (int) (vec[I_MILIT] * people_left);
vec[I_UW] = (int) (vec[I_UW] * people_left);
starved -= vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW];
vec[I_FOOD] = 0;
}
} else {
vec[I_FOOD] -= (int)food_eaten;
}
return starved;
}