#ifndef lint
static char *RCSid = "$Header: /sequent2/empire/EMP/player/commands/RCS/buil.c,v 1.32 89/09/17 21:58:04 mr-frog Exp $";
#endif /* not lint */

/*
 * buil.c
 *
 * version 3.0
 * build ships, nukes, bridges, planes.
 *
 * from PSL Empire, 1985
 */

#include "misc.h"
#include "var.h"
#include "sect.h"
#include "nat.h"
#include "ship.h"
#include "nuke.h"
#include "plane.h"
#include "xy.h"
#include "nsc.h"
#include "treaty.h"
#include "deity.h"
#include "file.h"
#include "path.h"

static	int build_nuke();
static	int build_ship();
static	int build_bridge();
static	int build_plane();

static	int cash;

/*
 * build <WHAT> <SECTS> <TYPE|DIR|MEG> [NUMBER]
 */
buil()
{
	extern	char *argp[];
	extern  double buil_bt;
	extern	double dolcost;
	struct	sctstr sect;
	struct	nstr_sect nstr;
	struct	natstr *natp;
	int	rqtech;
	int	tlev;
#ifdef DRNUKE
	int	rlev;
#endif /* DRNUKE */
	int	n;
	int	type;
	int	what;
	struct	mchrstr *mp;
	struct	plchrstr *pp;
	struct	nchrstr *np;
	char	*p;
	int	vec[I_MAX+1];
	char	*buildtech;
	int	gotsect = 0;
	int	built;
	int	hold,found,number=1,x;
#ifdef DRNUKE
	extern	int drnuke_const;
#endif /* DRNUKE */

	natp = getnatp(cnum);
	cash = natp->nat_money;
	if ((p = getstarg(argp[1], "Build (ship, nuke, bridge, plane)? ")) == 0)
		return RET_SYN;
	what = *p;
	buildtech = argp[4];
ask_again:
	tlev = (int) natp->nat_level[NAT_TLEV];
#ifdef DRNUKE
	rlev = (int) natp->nat_level[NAT_RLEV];
#endif /* DRNUKE */

	if (argp[5])
		number=atoi(argp[5]);

for(x=0;x<number;x++){
	if (!snxtsct(&nstr, argp[2])) {
		pr("Bad sector specification.\n");
		return RET_SYN;
	}
	switch (what) {
	case 'p':
		argp[3] = p = getstarg(argp[3], "Plane type? ");
		if (p == 0 || *p == 0)
			return RET_SYN;
		n = strlen(p);
		for (found=0,type=0,pp=plchr; type <= pln_maxno; type++,pp++) {
			if (pp->pl_tech > tlev)
				continue;
#ifdef MERC
			if(pp->pl_name && strncmp(p, pp->pl_name, n) == 0) {
				found++;
				hold = type;
				break;
			}
#else
			if (strscan(p, pp->pl_name) == 0) {
				found++;
				hold = type;
			}
#endif
		}
		if (found != 1) {
			pr("Possible plane types are:\n");
			show_plane_build (tlev);
			argp[3] = 0;
			goto ask_again;
		}
		type = hold;
		pp = &(plchr[type]);
		rqtech = pp->pl_tech;
		break;
	case 's':
		argp[3] = p = getstarg(argp[3], "Ship type? ");
		if (p == 0 || *p == 0)
			return RET_SYN;
		n = strlen(p);
		for (found=0,mp=mchr,type=0; type <= shp_maxno; type++, mp++) {
			if (mp->m_tech > tlev)
				continue;
#ifdef MERC
			if(mp->m_name && strncmp(p, mp->m_name, n) == 0) {
				found++;
				hold = type;
				break;
			}
#else
			if (strscan(p, mp->m_name) == 0) {
				found++;
				hold = type;
			}
#endif
		}
		if (found != 1) {
			pr("Possible ship types are:\n");
			show_ship_build (tlev);
			argp[3] = 0;
			goto ask_again;
		}
		type = hold;
		mp = &(mchr[type]);
		rqtech = mp->m_tech;
		break;
	case 'b':
#ifdef MERC
		if (natp->nat_level[NAT_TLEV]+0.005 < buil_bt) {
			pr(fmt("Building a span requires a tech of %.0f\n",
				buil_bt));
			return 2;
		}
#else
		if (tlev < buil_bt) {
			pr(fmt("Building a span requires a tech of %.0f\n",
				buil_bt));
			return 2;
		}
#endif
		break;
	case 'n':
		argp[3] = p = getstarg(argp[3], "Nuke type? ");
		if (p == 0 || *p == 0)
			return RET_SYN;
		n = strlen(p);
		for (found=0,np=nchr,type=0; type < N_MAXNUKE; type++, np++) {
#ifdef DRNUKE
                        if ((np->n_tech > tlev) || ((np->n_tech/drnuke_const) > rlev))
#else
			if (np->n_tech > tlev)
#endif /* DRNUKE */
				continue;
#ifdef MERC
			if(np->n_name && strncmp(p, np->n_name, n) == 0) {
				found++;
				hold = type;
				break;
			}
#else
			if (strscan(p, np->n_name) == 0) {
				found++;
				hold = type;
			}
#endif
		}
		if (found != 1) {
			pr("Possible nuke types are:\n");
#ifdef DRNUKE
			show_nuke_build((tlev < (rlev*drnuke_const) ? tlev : (rlev*drnuke_const)));
#else
			show_nuke_build(tlev);
#endif /* DRNUKE */
			argp[3] = 0;
			goto ask_again;
		}
		type = hold;
		np = &(nchr[type]);
		rqtech = np->n_tech;
		break;
	default:
		pr("You can't build that!\n");
		return RET_FAIL;
	}
	if (what != 'b' && what != 'n') {
		char bstr[45];
		(void) sprintf(bstr,"Build at what tech (%d)? ",
			(int) natp->nat_level[NAT_TLEV]);
		p = getstarg(buildtech, bstr);
		if (p == 0)
			return RET_FAIL;
		if (*p != '\0') {
			tlev = atopi(p);
			if (tlev > natp->nat_level[NAT_TLEV] && !god) {
				pr(fmt("Your tech level is only %d.\n",
					(int)natp->nat_level[NAT_TLEV]));
				buildtech = (char *)0;
				goto ask_again;
			}
			if (rqtech > tlev) {
				pr(fmt("Required tech is %d.\n",rqtech));
				buildtech = (char *)0;
				goto ask_again;
			}
			pr(fmt("building with tech level %d.\n", tlev));
		}
	}
	while (nxtsct(&nstr, &sect)) {
		gotsect++;
		if (!owner)
			continue;
		if (sect.sct_effic < 60 && !god)
			continue;
		getvec(VT_ITEM, vec, (char *)&sect, EF_SECTOR);
		switch (what) {
		case 's':
			built = build_ship(&sect, mp, vec, tlev);
			break;
		case 'b':
			built = build_bridge(&sect, vec);
			break;
		case 'n':
			built = build_nuke(&sect, np, vec);
			break;
		case 'p':
			built = build_plane(&sect, pp, vec, tlev);
			break;
		default:
			pr(fmt("internal error in build (%d)\n", what));
			return RET_FAIL;
		}
		if (built) {
			putvec(VT_ITEM, vec, (char *)&sect, EF_SECTOR);
			putsect(&sect);
		}
	}
}
	if (!gotsect) {
		pr("Bad sector specification.\n");
	}
	return RET_OK;
}

static int
build_ship(sp, mp, vec, tlev)
	register struct sctstr *sp;
	register struct mchrstr *mp;
	register int *vec;
	int	tlev;
{
	struct	shpstr ship;
	struct	nstr_item nstr;
	int	cost;
	int	w_p_eff;
	int	points;

	if (sp->sct_type != SCT_HARBR)
		return 0;
	if (vec[I_LCM] < mp->m_lcm || vec[I_HCM] < mp->m_hcm) {
		pr(fmt("Not enough materials in %s\n",
			xyas(sp->sct_x, sp->sct_y, cnum)));
		return 0;
	}
	w_p_eff = (mp->m_lcm + (mp->m_hcm * 2));
	points = sp->sct_avail * 100 / w_p_eff;
	if (points < 20) {
		pr(fmt("Not enough available work in %s to build a %s\n",
			xyas(sp->sct_x, sp->sct_y, cnum), mp->m_name));
		pr(fmt(" (%d available work required)\n",
			1 + (w_p_eff * 20)/100));
		return 0;
	}
	cost = mp->m_cost / 5;
	if (cash < cost) {
		pr(fmt("Not enough money left to build a %s\n", mp->m_name));
		return 0;
	}
	if (!trechk(cnum, 0, NEWSHP))
		return 0;
	sp->sct_avail = (sp->sct_avail * 100 - w_p_eff * 20) / 100;
	dolcost += cost;
	cash -= cost;
	snxtitem_all(&nstr, EF_SHIP);
	while (nxtitem(&nstr, (char *)&ship))
		if (ship.shp_own == 0)
			break;
	ship.shp_x = sp->sct_x;
	ship.shp_y = sp->sct_y;
#ifdef        AUTONAV
        ship.shp_destx[0] = sp->sct_x;
        ship.shp_desty[0] = sp->sct_y;
        ship.shp_destx[1] = sp->sct_x;
        ship.shp_desty[1] = sp->sct_y;
        ship.shp_autonav = 0;
#endif        AUTONAV
	ship.shp_own = cnum;
	ship.shp_type = mp - mchr;
	ship.shp_effic = 20;
	ship.shp_mobil = 0;
	ship.shp_uid = nstr.cur;
	ship.shp_nplane = 0;
#ifdef XLIGHT
	ship.shp_nxlight = 0;
#endif /* XLIGHT */
#ifdef SHIPCHOPPERS
	ship.shp_nchoppers = 0;
#endif /* SHIPCHOPPERS */
	ship.shp_fleet = ' ';
	ship.shp_nv = 0;
	ship.shp_sell = 0;
	ship.shp_tech = tlev;
#ifdef	SAIL
	ship.shp_mobquota = 0;
	*ship.shp_path = 0;
	ship.shp_follow = nstr.cur;
#endif	SAIL
#ifdef	SHIPNAMES
	ship.shp_name[0] = 0;
#endif	SHINAMES
#ifdef TRADESHIPS
	ship.shp_orig_own = cnum;
	ship.shp_orig_x = sp->sct_x;
	ship.shp_orig_y = sp->sct_y;
#endif /* TRADESHIPS */
#ifdef FUEL
	ship.shp_fuel = 0;
#endif /* FUEL */
#ifdef RETREAT
	ship.shp_rflags = 0;
	bzero(ship.shp_rpath,10);
#endif /* RETREAT */
	vec[I_LCM] -= mp->m_lcm;
	if (getvar(V_PSTAGE, (char *)sp, EF_SECTOR) == PLG_INFECT)
		putvar(V_PSTAGE, PLG_EXPOSED, (char *)&ship, EF_SHIP);
	putship(nstr.cur, &ship);
	pr(fmt("%s #%d", mp->m_name, nstr.cur));
	pr(fmt(" built in sector %s\n", xyas(sp->sct_x, sp->sct_y, cnum)));
	vec[I_HCM] -= mp->m_hcm;
	return 1;
}

static
int
build_bridge(sp, vec)
	register struct sctstr *sp;
	register int *vec;
{
	extern  int buil_bh;
	extern	double buil_bc;
	struct	sctstr sect;
	int	val;
	int	newx, newy;
	int	w_p_eff;
	int	points;

#ifndef EASY_BRIDGES
	if (sp->sct_type != SCT_BHEAD)
		return 0;
	if (sp->sct_newtype != SCT_BHEAD)
		return 0;
#else
        int     nx,ny,i,j,good=0,nx2,ny2;

        for (i = 1; i <= 6; i++) {
                struct sctstr s2;
                nx = sp->sct_x + diroff[i][0];
                ny = sp->sct_y + diroff[i][1];
                getsect(nx, ny, &sect);
        	for (j = 1; j <= 6; j++) {
                	nx2 = sect.sct_x + diroff[j][0];
                	ny2 = sect.sct_y + diroff[j][1];
                	getsect(nx2, ny2, &s2);
                	if ((s2.sct_type != SCT_WATER) && (s2.sct_type != SCT_BSPAN))
                        	good=1;
        	}

        }

	if (!good){
		pr(fmt("Bridges must be built adjacent to land.\n"));
		pr(fmt("No eligible sectors adjacent to this sector.\n"));
		return 0;
	}
#endif /* EASY_BRIDGES */
	if (vec[I_HCM] < buil_bh) {
		pr(fmt("%s only has %d unit%s of hcm,\n",
			xyas(sp->sct_x, sp->sct_y, cnum),
			vec[I_HCM], vec[I_HCM] > 1 ? "s" : ""));
		pr(fmt("(a bridge span requires %d)\n", buil_bh));
		return 0;
	}
	if (cash < buil_bc) {
		pr(fmt("A span costs $%f to build; ", buil_bc));
		pr(fmt("you only have %d.\n", cash));
		return 0;
	}
	w_p_eff = buil_bh * 2;
	points = sp->sct_avail * 100 / w_p_eff;
	if (points < 20) {
		pr(fmt("Not enough available work in %s to build a bridge\n",
			xyas(sp->sct_x, sp->sct_y, cnum)));
		pr(fmt(" (%d available work required)\n",
			1 + (w_p_eff * 20)/100));
		return 0;
	}
	pr(fmt("Bridge head at %s; ", xyas(sp->sct_x, sp->sct_y, cnum)));
	if ((val = getdir("build span in what direction? ",
		(char *)0, (char *)0, (char *)0)) <= 0)
		return 0;
	newx = sp->sct_x + diroff[val][0];
	newy = sp->sct_y + diroff[val][1];
	if (getsect(newx, newy, &sect) == 0 || sect.sct_type != SCT_WATER) {
		pr(fmt("%s is not a water sector\n",
			xyas(newx, newy, cnum)));
		return 0;
	}
#ifdef EASY_BRIDGES
        good=0;

        for (i = 1; i <= 6; i++) {
                struct sctstr s2;
                nx = sect.sct_x + diroff[i][0];
                ny = sect.sct_y + diroff[i][1];
                getsect(nx, ny, &s2);
                if ((s2.sct_type != SCT_WATER) && (s2.sct_type != SCT_BSPAN))
                        good=1;
        }

	if (!good){
		pr(fmt("Bridges must be built adjacent to land.\n"));
		pr(fmt("That sector is not adjacent to land.\n"));
		return 0;
	}
#endif /* EASY_BRIDGES */
	sp->sct_avail = (sp->sct_avail * 100 - w_p_eff * 20) / 100;
	dolcost += buil_bc;
	cash -= buil_bc;
	sect.sct_type = SCT_BSPAN;
	sect.sct_newtype = SCT_BSPAN;
	sect.sct_effic = 20;
	putsect(&sect);
	pr(fmt("Bridge span built over %s\n",
		xyas(sect.sct_x, sect.sct_y, cnum)));
	vec[I_HCM] -= buil_bh;
	return 1;
}

static
int
build_nuke(sp, np, vec)
	register struct sctstr *sp;
	register struct nchrstr *np;
	register int *vec;
{
	int	val;
	struct	nukstr nuke;
	struct	nstr_item nstr;
	int	old;
	int	free;
	int	w_p_eff;
	int	points;

	if (sp->sct_type != SCT_NUKE && !god)
		return 0;
	if (vec[I_HCM] < np->n_hcm || vec[I_LCM] < np->n_lcm ||
	    vec[I_OIL] < np->n_oil || vec[I_RAD] < np->n_rad) {
		pr(fmt("Not enough materials for a %s bomb in %s\n",
			np->n_name, xyas(sp->sct_x, sp->sct_y, cnum)));
		pr(fmt("(%d hcm, %d lcm, %d oil, & %d rads).\n",
			np->n_hcm, np->n_lcm, np->n_oil, np->n_rad));
		return 0;
	}
	if (cash < np->n_cost) {
		pr(fmt("You need $%d, you only have %d.\n", np->n_cost, cash));
		return 0;
	}
	w_p_eff = np->n_rad + np->n_oil + np->n_lcm + np->n_hcm * 2;
	points = sp->sct_avail * 100 / w_p_eff;
	/*
	 * XXX when nukes turn into units (or whatever), then
	 * make them start at 20%.  Since they don't have efficiency
	 * now, we choose 20% as a "big" number.
	 */
	if (points < 20) {
		pr(fmt("Not enough available work in %s to build a %s;\n",
			xyas(sp->sct_x, sp->sct_y, cnum), np->n_name));
		pr(fmt(" (%d available work required)\n",
			1 + w_p_eff*20/100));
		return 0;
	}
	if (!trechk(cnum, 0, NEWNUK))
		return 0;
	sp->sct_avail = (sp->sct_avail * 100 - w_p_eff * 20) / 100;
	dolcost += np->n_cost;
	cash -= np->n_cost;
	snxtitem_all(&nstr, EF_NUKE);
	free = -1;
	while (old = nxtitem(&nstr, (char *)&nuke)) {
		if (nuke.nuk_own != cnum)
			continue;
		if (nuke.nuk_x == sp->sct_x && nuke.nuk_y == sp->sct_y) {
			val = nstr.cur;
			break;
		}
		if (nuke.nuk_own == 0 && free < 0)
			free = nstr.cur;
	}
	if (old == 0) {
		/* not found; use a free slot, or expand file */
		if (free >= 0)
			val = free;
		else
			val = nstr.cur;
		bzero((char *)&nuke, sizeof(nuke));
	} else {
		if (!getnuke(val, &nuke)) {
			logerror("Couldn't get nuke #%d\n", val);
			return 0;
		}
	}
	if (nuke.nuk_own == 0) {
		nuke.nuk_x = sp->sct_x;
		nuke.nuk_y = sp->sct_y;
		nuke.nuk_n = 0;
		nuke.nuk_own = cnum;
		nuke.nuk_uid = val;
		nuke.nuk_ship = -1;
	}
	nuke.nuk_types[np - nchr]++;
	nuke.nuk_n++;
	putnuke(val, &nuke);
	vec[I_HCM] -= np->n_hcm;
	vec[I_LCM] -= np->n_lcm;
	vec[I_OIL] -= np->n_oil;
	vec[I_RAD] -= np->n_rad;
	pr(fmt("%s warhead created in stockpile #%d at %s\n", np->n_name,
		nuke.nuk_uid, xyas(sp->sct_x, sp->sct_y, cnum)));
	return 1;
}

static
int
build_plane(sp, pp, vec, tlev)
	register struct sctstr *sp;
	register struct plchrstr *pp;
	register int *vec;
	int	tlev;
{
	struct	plnstr plane;
	int	cost;
	int	n;
	struct	nstr_item nstr;
	int	points;
	int	w_p_eff;

	if (sp->sct_type != SCT_AIRPT && !god) {
		pr("Planes must be built in airports.\n");
		return 0;
	}
	if (vec[I_LCM] < pp->pl_lcm || vec[I_HCM] < pp->pl_hcm) {
		pr(fmt("Not enough materials in %s\n",
			xyas(sp->sct_x, sp->sct_y, cnum)));
		return 0;
	}
	w_p_eff = 5 * (pp->pl_lcm + (pp->pl_hcm * 2));
	points = sp->sct_avail * 100 / w_p_eff;
	if (points < 10) {
		pr(fmt("Not enough available work in %s to build a %s\n",
			xyas(sp->sct_x, sp->sct_y, cnum), pp->pl_name));
		pr(fmt(" (%d available work required)\n",
			1 + 10 * w_p_eff/100));
		return 0;
	}
	cost = pp->pl_cost / 10;
	if (cash < cost) {
		pr(fmt("Not enough money left to build a %s\n", pp->pl_name));
		return 0;
	}
	if (vec[I_MILIT] < pp->pl_crew) {
		pr(fmt("Not enough military for crew in %s\n",
			xyas(sp->sct_x, sp->sct_y, cnum)));
		return 0;
	}
	if (!trechk(cnum, 0, NEWPLN))
		return 0;
	sp->sct_avail = (sp->sct_avail * 100 - w_p_eff * 10) / 100;
	dolcost += cost;
	cash -= cost;
	snxtitem_all(&nstr, EF_PLANE);
	while (nxtitem(&nstr, (char *)&plane))
		if (plane.pln_own == 0)
			break;
	plane.pln_x = sp->sct_x;
	plane.pln_y = sp->sct_y;
	plane.pln_own = sp->sct_own;
	plane.pln_type = pp - plchr;
	plane.pln_effic = 10;
	plane.pln_mobil = 0;
	n = (int) (pp->pl_range * (0.75 + techfact(tlev - pp->pl_tech, 2.0)));
	if (n > 127)
		n = 127;
	plane.pln_range = n;
#ifdef	RANGEEDIT
	plane.pln_range_max = n;
#endif	RANGEEDIT
	n = (int) (pp->pl_att * (0.75 + techfact(tlev - pp->pl_tech, 2.0)));
	if (n > 127)
		n = 127;
	plane.pln_att = n;
	n = (int) (pp->pl_def * (0.75 + techfact(tlev - pp->pl_tech, 2.0)));
	if (n > 127)
		n = 127;
	if (n < pp->pl_def)
		n = pp->pl_def;
	plane.pln_def = n;
	plane.pln_wing = ' ';
	plane.pln_tech = tlev;
	plane.pln_ship = -1;
	plane.pln_uid = nstr.cur;
	plane.pln_nukeamt = 0;
	plane.pln_nuketype = 0;
	plane.pln_harden = 0;
	plane.pln_sell = 0;
	plane.pln_flags = 0;
	putplane(nstr.cur, &plane);
	pr(fmt("%s #%d built in sector %s\n", pp->pl_name, nstr.cur,
		xyas(sp->sct_x, sp->sct_y, cnum)));
	vec[I_LCM] -= pp->pl_lcm;
	vec[I_HCM] -= pp->pl_hcm;
	vec[I_MILIT] -= pp->pl_crew;
	return 1;
}
