#ifndef lint
static char *RCSid = "$Header: /usr/brule/guest/empire/empire/emprcs/lib/update/sect.c,v 2.6 1995/10/11 03:05:54 empire Exp $";
#endif

/*
 * sect.c
 *
 * perform production updates of the sect and
 * ship files.
 * 
 * from PSL Empire, 1985
 * and Dave Pare, 1986
 */

#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"
#ifdef	FALLOUT
#include "path.h"
#endif	/* FALLOUT */
#include "product.h"
#include "distribute.h"
#include "optlist.h"
#include "budg.h"

extern  int update_pending;
extern	float levels[MAXNOC][4];

int
dodeliver(sp, vec)
	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_PTIME, (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(np, sp, workp, vec, etu, desig, sctwork, cost)
	struct	natstr *np;
	register struct sctstr *sp;
	int	*workp;
	int	vec[I_MAX+1];
	int	etu, *desig, sctwork, *cost;
{
	register int work_cost = 0;
	int	buildeff_work = (int)(*workp / 2);
	int	n, hcms, lcms, neweff;
#ifdef BIG_CITY
	u_char  old_type = *desig;
#endif

	*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;
#ifdef 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);
		}
#endif /* BIG_CITY */
	}

	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(vec, etu, cost)
	register int *vec;
	int	etu;
        int     *cost;
{
	int	maxmil;
	int	enlisted;

	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;
}

#ifdef	FALLOUT
/* Fallout is calculated here. */

extern int melt_item_denom[];

int do_fallout(sp,etus)
	register struct sctstr *sp;
	register int etus;

{
  extern	double decay_per_etu,fallout_spread;
  int	vec[I_MAX+1];
  int	cvec[I_MAX+1];
  int	melt,n; /* radiation doesn't really melt people :) */
  int	decay;

  getvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
  getvec(VT_COND, cvec, (s_char *)sp, EF_SECTOR);

  if (cvec[C_FALLOUT]) {
    for (n=1; n<=I_MAX; n++)
      {
	melt = roundavg(vec[n]*etus*(long)cvec[C_FALLOUT] /
			(1000.0*melt_item_denom[n]));
	if (melt>5)
	  wu(0,sp->sct_own, "Lost %d %s to radiation in %s.\n",
		melt,ichr[n].i_name,ownxy(sp));
	if (melt<vec[n])
	  vec[n] -= melt;
	else
	  vec[n] = 0;
      }
  }
  for (n=DIR_FIRST; n<=DIR_LAST; n++)
    {
      struct sctstr *ap;
      static int vec2[I_MAX+1];
      ap = getsectp(sp->sct_x+diroff[n][0],sp->sct_y+diroff[n][1]);
      getvec(VT_COND, vec2, (char *)ap, EF_SECTOR);
      {
	register int	inc;
	inc = roundavg(etus*fallout_spread*vec2[C_FALLOUT]);
#if 0
	if (vec2[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,vec2[C_FALLOUT]);
	  }
#endif
	cvec[C_FALLOUT] += inc;
      }
    }

  decay = roundavg((decay_per_etu+6*fallout_spread)*etus*cvec[C_FALLOUT]);
#if 0
  if (decay>cvec[C_FALLOUT])
    wu(0,0,"Fallout underflow in sector %s.\n\t(library routine error, situation under control)\n",ownxy(sp));
#endif
  cvec[C_FALLOUT] = (decay<cvec[C_FALLOUT]) ? cvec[C_FALLOUT]-decay : 0;

  putvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
  putvec(VT_COND, cvec, (s_char *)sp, EF_SECTOR);
#ifdef	GODZILLA
  if ((cvec[C_FALLOUT] > 20) && chance(100))
	do_godzilla(sp);
#endif	/* GODZILLA */
}
#endif	/* FALLOUT */

#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)
 *
 */
produce_sect(natnum,etu,bp,p_sect,sector_type)
	int	natnum;
	int	etu, *bp;
        long    p_sect[SCT_MAXDEF+1][2];
        int     sector_type;
{
	extern	long pops[];
	register struct sctstr *sp;
	register struct natstr *np;
	extern	double populace();
	extern	double eatrate;
	extern	double bankint;
	int	vec[I_MAX+1];
	int	work, cost, ecost, pcost, sctwork;
	int	n, spam, desig, maxpop, neweff, amount;

	for (n=0; 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 (sp->sct_off){
			sp->sct_updated = 1;
			if (update_pending)
			  sp->sct_off = 0;
			continue;
		}

		np = getnatp(natnum);
		if (np->nat_money < 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 (update_pending)
				  logerror("Skipping %s production for country %s\n",dchr[sp->sct_type].d_name,np->nat_cnam);
                                continue;
		}

       		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)) {
			sp->sct_own = 0;
			sp->sct_oldown = 0;
			continue;
		}

		sp->sct_updated = 1;
		neweff = sp->sct_effic;
		work = 0;
		amount = 0;
		pcost = cost = ecost = 0;

		sctwork = do_feed(sp, np, vec, &work, bp, etu);
		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 (update_pending) {
			  np->nat_money -= cost;
			  sp->sct_type = desig;
			  sp->sct_effic = neweff;
			}
		}

		if ((np->nat_priorities[desig] == 0) &&
			((pchr[dchr[desig].d_prd].p_cost != 0) ||
			(desig == SCT_ENLIST))){
				logerror("Skipping %s production for country %s\n",dchr[desig].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 (update_pending)
			  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 (update_pending) {
		  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;
		}
	}
}
