#ifndef lint
static char *RCSid = "$Header: torp.c,v 1.10 89/09/28 02:08:49 mr-frog Exp $";
#endif /* not lint */

/*
 * torp.c
 *
 * fire torpedoes at enemy shipping.
 *
 * from PSL Empire, 1985
 */

#include <stdio.h>
#include "misc.h"
#include "var.h"
#include "ship.h"
#include "file.h"
#include "xy.h"
#include "nat.h"
#include "nsc.h"
#include "news.h"

torp()
{
	extern	char *argp[];
	extern	int torpedo_damage;
	natid	vshipown;
	int	range;
	int	dam;
	int	shells;
	int	subno;
	int	victno;
	double	erange;
	double	hitchance;
	struct	shpstr vship;
	struct	shpstr sub;
	struct	shpstr dd;
	char 	*ptr;
#ifdef NEWSUBS
        double	mobcost;
	struct	mchrstr *mcp;
	int	x;
#endif /* NEWSUBS */
#ifdef MULTIFIRE
	struct	nstr_item nbst;
	char	buf[80];
	char 	*sav;
	int	ntorping=0;
#endif /* MULTIFIRE */

#ifndef MULTIFIRE
	if ((ptr = getstarg(argp[1], "Victim ship #? ")) == 0)
		return RET_SYN;
	if ((victno = atoi(ptr)) < 0)
		return RET_SYN;
	if (!getship(victno, &vship))
		return RET_FAIL;
#endif /* MULTIFIRE */
#ifdef MULTIFIRE
	if (!(sav = getstarg(argp[1], "From ship(s)? ")))
		return RET_SYN;
        if (!snxtitem(&nbst, EF_SHIP, sav))
                return RET_SYN;
#else
	if ((ptr = getstarg(argp[2], "From ship #? ")) == 0)
		return RET_SYN;
	if ((subno = atoi(ptr)) < 0)
		return RET_SYN;
	if (!getship(subno, &sub))
		return RET_FAIL;
	if (sub.shp_own != cnum) {
		pr("Not your sub!\n");
		return RET_FAIL;
	}
#endif /* MULTIFIRE */
#ifdef MULTIFIRE
while (nxtitem(&nbst, (char *)&sub)){
	if (sub.shp_own != cnum)
		continue;
	if ((mchr[sub.shp_type].m_flags & M_TORP) == 0)
		continue;
	shells = getvar(V_SHELL, (char *)&sub, EF_SHIP);
	if (getvar(V_GUN, (char *)&sub, EF_SHIP) == 0 || shells < 3)
		continue;
	if (sub.shp_effic < 60)
		continue;
	if (sub.shp_mobil <= 0)
		continue;
	ntorping++;
}
pr(fmt("%d ships are eligible to torp\n",ntorping));
snxtitem(&nbst, EF_SHIP, sav);
while (nxtitem(&nbst, (char *)&sub)) {
	if (!sub.shp_own)
		continue;
        if (sub.shp_own != cnum) {
                continue;
	}
#endif /* MULTIFIRE */
	if ((mchr[sub.shp_type].m_flags & M_TORP) == 0) {
		pr(fmt("Ship # %d: A %s can't fire torpedoes!\n", sub.shp_uid,
		       mchr[sub.shp_type].m_name));
#ifdef MULTIFIRE
		continue;
#else
		return RET_FAIL;
#endif /* MULTIFIRE */
	}
	shells = getvar(V_SHELL, (char *)&sub, EF_SHIP);
	if (getvar(V_GUN, (char *)&sub, EF_SHIP) == 0 || shells < 3) {
		pr(fmt("Ship #%d has insufficient armament\n",sub.shp_uid));
#ifdef MULTIFIRE
		continue;
#else
		return RET_FAIL;
#endif /* MULTIFIRE */
	}
	if (sub.shp_effic < 60) {
		pr(fmt("Ship #%d torpedo tubes inoperative.\n",sub.shp_uid));
#ifdef MULTIFIRE
		continue;
#else
		return RET_FAIL;
#endif /* MULTIFIRE */
	}
	if (sub.shp_mobil <= 0) {
		pr(fmt("Ship #%d has insufficient mobility\n",sub.shp_uid));
#ifdef MULTIFIRE
		continue;
#else
		return RET_FAIL;
#endif /* MULTIFIRE */
	}
#ifdef MULTIFIRE
	bzero(buf,80);
	subno=sub.shp_uid;
        if ((ptr = getstarg(argp[2],fmt("Ship %d, target? ",sub.shp_uid))) == 0)
                return RET_SYN;
        if ((victno = atoi(ptr)) < 0)
                return RET_SYN;
        if (!getship(victno, &vship))
                return RET_FAIL;
        if (!vship.shp_own)
                return RET_FAIL;
        vshipown=vship.shp_own;
#endif /* MULTIFIRE */
	if (victno == subno) {
		pr("Shooting yourself, eh?  How strange...\n");
#ifdef MULTIFIRE
		continue;
#else
		return RET_FAIL;
#endif /* MULTIFIRE */
	}
#ifdef NEWSUBS
        if (mchr[vship.shp_type].m_flags & M_SUB) {
                if (!(mchr[sub.shp_type].m_flags & M_SUBT)){
                	pr("You can't torpedo a submarine!\n");
#ifdef MULTIFIRE
			continue;
#else
			return RET_FAIL;
#endif /* MULTIFIRE */
		}
        }
#endif /* NEWSUBS */
#ifdef SHIPTORP
	if ((mchr[sub.shp_type].m_flags & M_SUB) == 0)
#ifdef MULTIFIRE
		anti_torp(sub.shp_uid,vship.shp_uid,ntorping,vshipown);
#else
		anti_torp(sub.shp_uid,vship.shp_uid,2,vshipown);
#endif /* MULTIFIRE */
	getship(sub.shp_uid,&sub);
	if (sub.shp_own == 0){
#ifdef MULTIFIRE
		continue;
#else
		return RET_FAIL;
#endif /* MULTIFIRE */
	}
#endif /* SHIPTORP */
#ifdef NEWSUBS
	erange = sub.shp_effic * techfact(sub.shp_tech, ((double)mchr[sub.shp_type].m_frnge)) / 100.0;
#else
	erange = sub.shp_effic * techfact(sub.shp_tech, 2.0) / 100.0;
#endif /* NEWSUBS */
	pr(fmt("Effective torpedo range is %.1f\n", erange));
	putvar(V_SHELL, shells - 3, (char *)&sub, EF_SHIP);
#ifndef NEWSUBS
	sub.shp_mobil -= 20;
#else
	mcp = &mchr[sub.shp_type];
	mobcost = sub.shp_effic * 0.01 * mcp->m_speed;
	mobcost = (480.0 / (mobcost + techfact(sub.shp_tech, mobcost)));

	/* Mob cost for a torp is equal to the cost of 1/2 sector of movement */
	mobcost /= 2.0;
	sub.shp_mobil -= mobcost;
#endif /* NEWSUBS */
	pr("Whooosh... ");
	getship(victno, &vship);
	vshipown = vship.shp_own;
	range = mapdist(sub.shp_x, sub.shp_y, vship.shp_x, vship.shp_y);
	hitchance = 0.90 / (range + 1);
	if (mchr[sub.shp_type].m_flags & M_SUB)
		hitchance += (5.0-(double)mchr[sub.shp_type].m_visib)*3.0;
	if (range > erange) {
		pr("Out of range\n");
	} else if (chance(hitchance)) {
		pr("BOOM!...\n");
#ifdef MERC
		if(vshipown != 0)
#endif
#ifdef	SHIPNAMES
		wu(0, vshipown, fmt("%s %s(#%d) @%s torpedoed %s %s(#%d)",
			mchr[sub.shp_type].m_name, sub.shp_name,
#else
		wu(0, vshipown, fmt("%s #%d @%s torpedoed %s %d",
			mchr[sub.shp_type].m_name,
#endif	SHIPNAMES
			subno, xyas(sub.shp_x, sub.shp_y, vshipown),
#ifdef	SHIPNAMES
			mchr[vship.shp_type].m_name, vship.shp_name, victno));
#else
			mchr[vship.shp_type].m_name, victno));
#endif	SHIPNAMES
		dam = torpedo_damage + (random() % torpedo_damage);
		dam = (100 * dam) / (mchr[vship.shp_type].m_armor + 50);
#ifdef RETREAT
		if (vship.shp_rflags & RET_TORPED){
			retreat(&vship, 't');
			shipdamage(&vship, dam);
		}else
			check_retreat_and_do_shipdamage(&vship, dam);
#else
		check_retreat_and_do_shipdamage(&vship, dam);
#endif /* RETREAT */
		putship(victno, &vship);
#ifdef SHIPTORP
		if (mchr[sub.shp_type].m_flags & M_SUB)
			nreport(vshipown, N_TORP_SHIP, sub.shp_own, 1);
		else
			nreport(vshipown, N_SHIP_TORP, sub.shp_own, 1);
#else
		nreport(vshipown, N_TORP_SHIP, sub.shp_own, 1);
#endif /* SHIPTORP */
	} else {
		pr("Missed\n");
#ifdef MERC
		if(vshipown != 0)
#endif
#ifdef	SHIPNAMES
		wu(0, vshipown, fmt("Torpedo sighted @%s by %s %s(#%d)",
#else
		wu(0, vshipown, fmt("Torpedo sighted @%s by %s #%d",
#endif	SHIPNAMES
			xyas(sub.shp_x, sub.shp_y, vshipown),
#ifdef	SHIPNAMES
			mchr[vship.shp_type].m_name, vship.shp_name, victno));
#else
			mchr[vship.shp_type].m_name, victno));
#endif	SHIPNAMES
	}
	putship(subno, &sub);
#ifdef SHIPTORP
	if (mchr[sub.shp_type].m_flags & M_SUB)
#ifdef MULTIFIRE
		anti_torp(sub.shp_uid,vship.shp_uid,ntorping,vshipown);
#else
		anti_torp(sub.shp_uid,vship.shp_uid,2,vshipown);
#endif /* MULTIFIRE */
#else
#ifdef MULTIFIRE
	anti_torp(sub.shp_uid,vship.shp_uid,ntorping,vshipown);
#else
	anti_torp(sub.shp_uid,vship.shp_uid,2,vshipown);
#endif /* MULTIFIRE */
#endif /* SHIPTORP */
#ifdef MULTIFIRE
}
#endif /* MULTIFIRE */
	return RET_OK;
}

anti_torp(f,v,ntorping,vshipown)
int	f,v,ntorping;
natid	vshipown;
{
	int	range;
	int	dam;
	int	shells;
	int	subno;
	int	victno;
	double	erange;
	double	hitchance;
	struct	shpstr vship;
	struct	shpstr sub;
	struct	shpstr dd;
	char 	*ptr;
#ifdef NEWSUBS
        double	mobcost;
	struct	mchrstr *mcp;
	int	x;
#endif /* NEWSUBS */
#ifdef MULTIFIRE
	struct	nstr_item nbst;
	char	buf[80];
#endif /* MULTIFIRE */
	struct	nstr_item ni;
	double	guneff;
	int	vdef;

	getship(f,&sub);
	getship(v,&vship);
	subno=sub.shp_uid;

	if (sub.shp_own == vship.shp_own)
		return;

#ifndef NEWSUBS
	if ((mchr[sub.shp_type].m_flags & M_SUB) == 0)
		pr("Starting our attack run...\n");
	snxtitem_dist(&ni, EF_SHIP, sub.shp_x, sub.shp_y, 0);
	while (nxtitem(&ni, (char *)&dd) && sub.shp_effic >= 20) {
		if (dd.shp_own != vshipown)
			continue;
		if ((mchr[dd.shp_type].m_flags & M_DCH) == 0)
			continue;
		if (dd.shp_x != sub.shp_x)
			continue;
		if (dd.shp_y != sub.shp_y)
			continue;
		if ((shells = getvar(V_SHELL, (char *)&dd, EF_SHIP)) < 2)
			continue;
		if (getvar(V_GUN, (char *)&dd, EF_SHIP) < 1)
			continue;
#ifdef SHIPTORP
		if ((mchr[sub.shp_type].m_flags & M_SUB) == 0){
			pr("\07Kaboom!!! Incoming shells!\07\n");
#ifdef MERC
			if(vshipown != 0)
#endif
			wu(0, vshipown,
			fmt("Ship #%d fired at ship #%d", dd.shp_uid, subno));
			putvar(V_SHELL, shells - 2, (char *)&dd, EF_SHIP);
			putship(dd.shp_uid, &dd);
			vdef = seadef(sub.shp_type);
			guneff = seagun(sub.shp_type, dd.shp_effic, 1);
			dam = shelldam((double)guneff, vdef);
			dam /= ((float)ntorping/2);
			pr(fmt("\07BLAM! %d%% damage!\n", dam));
			shipdamage(&sub, dam);
			putship(sub.shp_uid,&sub);
		}else{
			pr("\nCAPTAIN!  !!Depth charges!!...\n");
#ifdef MERC
			if(vshipown != 0)
#endif
			wu(0, vshipown,
			fmt("Destroyer #%d dropped a depth charge on sub #%d",
				dd.shp_uid, subno));
			putvar(V_SHELL, shells - 2, (char *)&dd, EF_SHIP);
			putship(dd.shp_uid, &dd);
			dam = (random() % 30) + 30;
			dam /= ((float)ntorping/2);
			pr(fmt("click...WHAM!  %d%% damage!\n", dam));
			shipdamage(&sub, dam);
			putship(sub.shp_uid,&sub);
		}
#else
		pr("\nCAPTAIN!  !!Depth charges!!...\n");
#ifdef MERC
		if(vshipown != 0)
#endif
		wu(0, vshipown,
			fmt("Destroyer #%d dropped a depth charge on sub #%d",
			dd.shp_uid, subno));
		putvar(V_SHELL, shells - 2, (char *)&dd, EF_SHIP);
		putship(dd.shp_uid, &dd);
		dam = (random() % 30) + 30;
		dam /= ((float)ntorping/2);
		pr(fmt("click...WHAM!  %d%% damage!\n", dam));
		shipdamage(&sub, dam);
		putship(sub.shp_uid,&sub);
#endif /* SHIPTORP */
	}
#else
	if ((mchr[sub.shp_type].m_flags & M_SUB) == 0)
		pr("Starting our attack run...\n");

	x=0;
	while (getship(x++,&dd) && sub.shp_effic >= 20){
		if (dd.shp_own == 0)
			continue;
		if (dd.shp_own != vshipown)
			continue;
#ifdef SHIPTORP
		if (mchr[sub.shp_type].m_flags & M_SUB)
			if ((mchr[dd.shp_type].m_flags & M_DCH) == 0)
				continue;
#else
		if ((mchr[dd.shp_type].m_flags & M_DCH) == 0)
			continue;
#endif /* SHIPTORP */
		erange = techfact(dd.shp_tech,((double)mchr[dd.shp_type].m_frnge))/ 2.0;
		range = mapdist(sub.shp_x, sub.shp_y, dd.shp_x, dd.shp_y);
		if (range > erange)
			continue;
		if ((shells = getvar(V_SHELL, (char *)&dd, EF_SHIP)) < 2)
			continue;
		if (getvar(V_GUN, (char *)&dd, EF_SHIP) < 1)
			continue;
#ifdef SHIPTORP
		if ((mchr[sub.shp_type].m_flags & M_SUB) == 0){
			pr("\07Kaboom!!! Incoming shells!\07\n");
#ifdef MERC
			if(vshipown != 0)
#endif
			wu(0, vshipown,
			fmt("Ship #%d fired at ship #%d", dd.shp_uid, subno));
			putvar(V_SHELL, shells - 2, (char *)&dd, EF_SHIP);
			putship(dd.shp_uid, &dd);
			dam = (random() % 30) + 30;
                	if (range)
                        	dam = (((float)dam) / ((float)(range+2.0)/2.0));
                	dam = (100 * dam) / (mchr[sub.shp_type].m_armor + 50);
			dam /= ((float)ntorping/2);
			pr(fmt("\07BLAM! %d%% damage!\n", dam));
			shipdamage(&sub, dam);
			putship(sub.shp_uid,&sub);
		}else{
			pr("\nCAPTAIN!  !!Depth charges!!...\n");
#ifdef MERC
			if(vshipown != 0)
#endif
			wu(0, vshipown,
			fmt("Destroyer #%d dropped a depth charge on sub #%d",
				dd.shp_uid, subno));
			putvar(V_SHELL, shells - 2, (char *)&dd, EF_SHIP);
			putship(dd.shp_uid, &dd);
			dam = (random() % 30) + 30;
                	if (range)
                        	dam = (((float)dam) / ((float)(range+2.0)/2.0));
                	dam = (100 * dam) / (mchr[sub.shp_type].m_armor + 50);
			dam /= ((float)ntorping/2);
			pr(fmt("click...WHAM!  %d%% damage!\n", dam));
			shipdamage(&sub, dam);
			putship(sub.shp_uid,&sub);
		}
#else
		pr("\nCAPTAIN!  !!Depth charges!!...\n");
#ifdef MERC
		if(vshipown != 0)
#endif
		wu(0, vshipown,
			fmt("Destroyer #%d dropped a depth charge on sub #%d",
			dd.shp_uid, subno));
		putvar(V_SHELL, shells - 2, (char *)&dd, EF_SHIP);
		putship(dd.shp_uid, &dd);
		dam = (random() % 30) + 30;
                if (range)
                        dam = (((float)dam) / ((float)(range+2.0)/2.0));
                dam = (100 * dam) / (mchr[sub.shp_type].m_armor + 50);
		dam /= ((float)ntorping/2);
		pr(fmt("click...WHAM!  %d%% damage!\n", dam));
		shipdamage(&sub, dam);
		putship(sub.shp_uid,&sub);
#endif /* SHIPTORP */
	}
#endif /* NEWSUBS */
}
