#ifndef lint
static char *RCSid = "$Header: /usr/brule/guest/empire/empire/emprcs/lib/update/nat.c,v 2.3 1995/10/22 21:07:37 empire Exp $";
#endif

/*
 * nat.c
 *
 * Accumulate tech, edu, research, and happiness.
 * Share them among allies.
 * 
 * and Dave Pare, 1989
 */

#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"

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(d, base)
	double	d;
	double	base;
{
	if (base == 1.0)
		return d;
	return log10(d) / log10(base);
}

double
limit_level(level, type, flag)
	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);
		return ((above) < 0) ? easy : (easy + above);
	} else
		return level;
}

prod_nat(etu)
	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;
	double	etu_factor;
#ifdef LOSE_CONTACT 
	int	cn,cont;
#endif /* LOSE_CONTACT */

	etu_factor = (float)etu / 12;
	for (n=0; 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) /
			((float)pop / (hap_cons * etu_factor));
		edu = levels[n][NAT_ELEV] /
			((float)pop / (edu_cons * etu_factor));
		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(res, sizeof(res));
		bzero(tech, sizeof(tech));
	}
	for (n=0; 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]);
#ifdef 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); 
			}
                }
#endif /* LOSE_CONTACT */
	}
}

/*
 * find out everyones increment
 */
share_incr(res, tech)
	register double *res;
	register double *tech;
{
	register struct natstr *np;
	register struct natstr *other;
	register natid i;
	register natid j;
	register int nc;

	for (i=0; np = getnatp(i); i++) {
		if ((np->nat_stat & STAT_INUSE) == 0)
			continue;
		nc = 0;
		res[i] = tech[i] = 0.0;
		for (j=0; other = getnatp(j); j++) {
			if (j == i)
				continue;
			if (opt_ALL_BLEED) {
				if ((other->nat_stat & STAT_INUSE) == 0)
					continue;
				if (!j)
					continue;
				if (levels[j][NAT_TLEV] <= 0.001)
					continue;
			}
			else {	/* ! ALL_BLEED */
				if (!j)
					continue;
				if (getrel(np, j) != ALLIED)
					continue;
				if (getrel(other, i) != ALLIED)
					continue;
			} /* end ALL_BLEED */
#ifdef HIDDEN
                        if (!getcontact(np, j))
                                continue;
#endif /* HIDDEN */
			res[i] += levels[j][NAT_RLEV];
			tech[i] += levels[j][NAT_TLEV];
			nc++;
		}
		if (nc == 0)
			continue;
		if (opt_ALL_BLEED)
			nc++;
		res[i] /= nc * ally_factor;
		tech[i] /= nc * ally_factor;
/*		logerror("Country #%d gets %g res and %g tec from %d allies",
			i, res[i], tech[i], nc - 1);*/
	}
}
