#ifndef lint
static char *RCSid = "$Header: /usr/brule/guest/empire/empire/emprcs/lib/common/damage.c,v 2.15 1995/10/24 04:36:22 empire Exp $";
#endif

/*
 * damage.c
 *
 * damage a sector, ship, or plane.
 *
 * Should probably do this in some regular fashion, but
 * we don't yet have a list of fields we can iterate through
 * and find the "damageable" ones.
 *
 * Dave Pare, 1989
 */

#include "misc.h"
#include "var.h"
#include "sect.h"
#include "ship.h"
#include "land.h"
#include "plane.h"
#include "nuke.h"
#include "xy.h"
#include "nsc.h"
#include <fcntl.h>
#include "file.h"
#include "optlist.h"
#include "damage.h"

void
ship_damage(sp, dam)
	struct	shpstr *sp;
	int	dam;
{

	if (dam <= 0)
		return;
	if (dam > 100)
		dam = 100;

	mpr(sp->shp_own, "\t%s takes %d\n", prship(sp), dam);

	sp->shp_effic = damage((int)sp->shp_effic, dam);
	if (sp->shp_mobil > 0)
		sp->shp_mobil = damage((int)sp->shp_mobil, dam);
	if (opt_FUEL && sp->shp_fuel)
		sp->shp_fuel = damage((int)sp->shp_fuel, dam);
	sp->shp_nv = vl_damage(dam, sp->shp_vtype, sp->shp_vamt,
		(int) sp->shp_nv);
}

void
shipdamage(sp, dam)
	struct	shpstr *sp;
	int	dam;
{
	ship_damage(sp, (int)( dam/(1.0 + mchr[sp->shp_type].m_armor / 100.0)));
}

void
land_damage(lp, dam)
	struct	lndstr *lp;
	int	dam;
{
	if (dam <= 0)
		return;
	if (dam > 100)
		dam = 100;

	mpr(lp->lnd_own, "\t%s takes %d\n", prland(lp), dam);
	lp->lnd_effic = damage((int)lp->lnd_effic, dam);
	if (lp->lnd_mobil > 0)
		lp->lnd_mobil = damage((int)lp->lnd_mobil, dam);
	if (opt_FUEL && lp->lnd_fuel)
		lp->lnd_fuel = damage((int)lp->lnd_fuel, dam);
	lp->lnd_nv = vl_damage(dam, lp->lnd_vtype, lp->lnd_vamt,
		(int) lp->lnd_nv);
}

void
landdamage(lp, dam)
	struct	lndstr *lp;
	int	dam;
{
	double	damage_factor, m;
	extern	int land_mob_max;

	m = (double)land_mob_max;

	/* fortification reduces damage */
	damage_factor = m / (m+((double)lp->lnd_harden));
	if (damage_factor == 0.0)
		damage_factor = 1.0;

	/* vulnerable units take more damage */
	damage_factor *= lchr[lp->lnd_type].l_vul / 100.0;

	land_damage(lp, ldround(damage_factor * dam,1));
}

void
planedamage(pp, dam)
	struct	plnstr *pp;
	int	dam;
{
	if (dam <= 0)
		return;
	if (dam > 100)
		dam = 100;

	pp->pln_effic = damage((int)pp->pln_effic, dam);
	if (pp->pln_mobil > 0)
		pp->pln_mobil = damage((int)pp->pln_mobil, dam);
}

/*
 * nukedamage() actually just calculates damage
 * rather than inflicting it.
 */
int
nukedamage(ncp, range, airburst)
	struct	nchrstr *ncp;
	int	range;
	int	airburst;
{
	int	dam;
	int	rad;

	rad = ncp->n_blast;
	if (airburst)
		rad = (int) (rad * 1.5);
	if (rad < range)
		return 0;
	if (airburst) {
		/* larger area, less center damage */
		dam = (int) ((ncp->n_dam * 0.75) - (range * 20));
	} else {
		/* smaller area, more center damage */
		dam = (int) (ncp->n_dam / (range + 1.0));
	}
	if (dam < 5)
		dam = 0;
	return dam;
}

int
damage(amt, pct)
	register int amt;
	int	pct;
{
	register int tmp;
	register int lost;

	if (amt <= 0)
		return 0;
	tmp = amt * pct;
	lost = tmp / 100;
	if ((random() % 100) < (tmp % 100))
		lost++;
	return amt - lost;
}

/* asymptotic damage to commodities, efficiency, and sectors */
int
effdamage(amt, dam)
	register int amt;
	int	dam;
{
	return damage(amt, PERCENT_DAMAGE(dam));
}

int
commdamage(amt, dam, vtype)
	register int amt;
	int	dam;
	int	vtype;
{
	extern	double people_damage;
	int	lost;

	if (vtype == V_BAR && opt_SUPER_BARS)
		return amt;

	lost = amt - effdamage(amt, dam);

	if (vtype == V_MILIT ||
	    vtype == V_CIVIL ||
	    vtype == V_UW)
		lost = ldround(people_damage * lost, 1);
	return amt - lost;
}
