// Emacs style mode select -*- C++ -*-
//---------------------------------------------------------------------------
//
// $Id: swauto.c,v 1.2 2003/04/06 22:01:01 fraggle Exp $
//
// Copyright(C) 1984-2000 David L. Clark
// Copyright(C) 2001-2003 Simon Howard
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version. This program is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU General Public License for more details. You should have
// received a copy of the GNU General Public License along with this
// program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place - Suite 330, Boston, MA 02111-1307, USA.
//
//---------------------------------------------------------------------------
//
//        swauto   -      SW control of computer player
//
//---------------------------------------------------------------------------

#include "sw.h"
#include "swauto.h"
#include "swground.h"
#include "swinit.h"
#include "swmain.h"
#include "swutil.h"

static BOOL correction;		/*  Course correction flag        */
static BOOL goinghome;		/*  Going home flag               */
static OBJECTS obs;		/*  Saved computer object         */
static int courseadj;		/*  Course adjustment             */

int shoot(OBJECTS *obt)
{
	static OBJECTS obsp, obtsp;
	int obx, oby, obtx, obty;
	int nspeed, nangle;
	int rprev;
	register int r, i;

	obsp = obs;
	obtsp = *obt;
	nspeed = obsp.ob_speed + BULSPEED;
	setdxdy(&obsp, 
		nspeed * COS(obsp.ob_angle),
		nspeed * SIN(obsp.ob_angle));
	obsp.ob_x += SYM_WDTH / 2;
	obsp.ob_y -= SYM_HGHT / 2;

	nangle = obtsp.ob_angle;
	nspeed = obtsp.ob_speed;
	rprev = NEAR;

	for (i = 0; i < BULLIFE; ++i) {
		movexy(&obsp, &obx, &oby);
		if (obtsp.ob_state == FLYING || obtsp.ob_state == WOUNDED) {

			r = obtsp.ob_flaps;

			if (r) {
				if (obtsp.ob_orient)
					nangle -= r;
				else
					nangle += r;
				nangle = (nangle + ANGLES) % ANGLES;
				setdxdy(&obtsp, 
					nspeed * COS(nangle),
					nspeed * SIN(nangle));
			}
		}

		movexy(&obtsp, &obtx, &obty);
		r = range(obx, oby, obtx, obty);
		if (r < 0 || r > rprev)
			return 0;
		if (obx >= obtx
		    && obx <= (obtx + SYM_WDTH - 1)
		    && oby <= obty
		    && oby >= (obty - SYM_HGHT + 1))
			return 1 + (i > (BULLIFE / 3));

	}

	return 0;
}



/*  sdh -- this is standard c


    abs( x )
    int     x;
    {
    return( ( x < 0 ) ? -x : x );
    }
*/

static int tl, tr;

static void cleartargs()
{
	tl = -2;
}

static void testtargs(int x, int y)
{
	register int i, xl, xr;

	xl = x - 32 - gmaxspeed;
	xr = x + 32 + gmaxspeed;

	tl = -1;
	tr = 0;
	for (i = 0; i < (MAX_TARG + MAX_OXEN); ++i)
		if (targets[i] && targets[i]->ob_x >= xl) {
			tl = i;
			break;
		}

	if (tl == -1)
		return;

	for (; i < MAX_TARG + MAX_OXEN 
	       && targets[i]
	       && targets[i]->ob_x < xr; ++i);

	tr = i - 1;
}



// sdh: changed to tstcrash2 to stop conflicts with the other 
// function with the same name in swcollsn.c

static BOOL tstcrash2(OBJECTS *obp, int x, int y, int alt)
{
	register OBJECTS *ob;
	register int i, xl, xr, xt, yt;

	if (alt > 50)
		return FALSE;

	if (alt < 22)
		return TRUE;

	ob = obp;
	if (tl == -2)
		testtargs(ob->ob_x, ob->ob_y);

	xl = x - 32;
	xr = x + 32;

	for (i = tl; i <= tr; ++i) {
		ob = targets[i];
		xt = ob->ob_x;

		if (xt < xl)
			continue;
		if (xt > xr)
			return FALSE;
		yt = ob->ob_y + (ob->ob_state == STANDING ? 16 : 8);
		if (y <= yt)
			return TRUE;
	}
	return FALSE;
}

int aim(OBJECTS *obo, int ax, int ay, OBJECTS *obt, BOOL longway)
{
	register OBJECTS *ob;
	register int r, rmin, i, n=0;
	int x, y, dx, dy, nx, ny;
	int nangle, nspeed;
	static int cflaps[3] = { 0, -1, 1 };
	static int crange[3], ccrash[3], calt[3];

	ob = obo;

	correction = FALSE;

	if ((ob->ob_state == STALLED || ob->ob_state == WOUNDSTALL)
	    && ob->ob_angle != (3 * ANGLES / 4)) {
		ob->ob_flaps = -1;
		ob->ob_accel = MAX_THROTTLE;
		return 0;
	}

	x = ob->ob_x;
	y = ob->ob_y;

	dx = x - ax;

	if (abs(dx) > 160) {
		if (ob->ob_dx && (dx < 0 == ob->ob_dx < 0)) {
			if (!ob->ob_hitcount)
				ob->ob_hitcount = (y > (MAX_Y - 50)) ? 2 : 1;
			return (aim(ob, x, ob->ob_hitcount == 1
				    ? (y + 25) : (y - 25), NULL, YES));
		}
		ob->ob_hitcount = 0;
		return (aim(ob, x + (dx < 0 ? 150 : -150),
			    (y + 100 > MAX_Y - 50 - courseadj)
		 		? MAX_Y - 50 - courseadj 
				: y + 100, 
			    NULL, YES));
	} else {
		if (!longway)
			ob->ob_hitcount = 0;
	}

	if (ob->ob_speed) {

		correction = dy = y - ay;

		if (correction && abs(dy) < 6) {
			if (dy < 0) 
				++y;
			else
				--y;
			ob->ob_y = y;
		} else {
			correction = dx;
			if (correction && abs(dx) < 6) {
				if (dx < 0)
					++x;
				else
					--x;
				ob->ob_x = x;
			}
		}
	}

	// sdh 16/11/2001: removed movmem

	obs = *ob;

	nspeed = obs.ob_speed + 1;
	if (nspeed > gmaxspeed && obs.ob_type == PLANE)
		nspeed = gmaxspeed;
	else if (nspeed < gminspeed)
		nspeed = gminspeed;

	cleartargs();
	for (i = 0; i < 3; ++i) {
		nangle = (obs.ob_angle
			  + (obs.ob_orient ? -cflaps[i] : cflaps[i])
			  + ANGLES) % ANGLES;
		setdxdy(&obs, nspeed * COS(nangle), nspeed * SIN(nangle));
		movexy(&obs, &nx, &ny);
		crange[i] = range(nx, ny, ax, ay);
		calt[i] = ny - orground[nx + 8];
		ccrash[i] = tstcrash2(ob, nx, ny, calt[i]);

		// sdh 16/11/2001: removed movmem
		obs = *ob;
	}


	if (obt) {
		i = shoot(obt);

		if (i) {
			if (ob->ob_missiles && i == 2)
				ob->ob_mfiring = obt->ob_athome ? ob : obt;
			else
				ob->ob_firing = obt;
		}
	}

	rmin = 32767;
	for (i = 0; i < 3; ++i) {
		r = crange[i];
		if (r >= 0 && r < rmin && !ccrash[i]) {
			rmin = r;
			n = i;
		}
	}

	if (rmin == 32767) {
		rmin = -32767;
		for (i = 0; i < 3; ++i) {
			r = crange[i];
			if (r < 0 && r > rmin && !ccrash[i]) {
				rmin = r;
				n = i;
			}
		}
	}

	if (ob->ob_speed < gminspeed)
		ob->ob_accel = MAX_THROTTLE;

	if (rmin == -32767) {
		if (ob->ob_accel)
			--ob->ob_accel;

		n = 0;

		dy = calt[0];

		if (calt[1] > calt[0]) {
			dy = calt[1];
			n = 1;
		}
		if (calt[2] > dy)
			n = 2;
	} else {
		if (ob->ob_accel < MAX_THROTTLE)
			++ob->ob_accel;
	}

	ob->ob_flaps = cflaps[n];
	if (ob->ob_type == PLANE && !ob->ob_flaps)
		if (ob->ob_speed)
			ob->ob_orient = ob->ob_dx < 0;

	return 0;
}



int gohome(OBJECTS *obpt)
{
	register OBJECTS *ob, *obp = obpt;

	if (obp->ob_athome)
		return 0;

	ob = &oobjects[currobx];

	courseadj = ((countmove & 0x001F) < 16) << 4;
	if (abs(obp->ob_x - ob->ob_x) < HOME
	    && abs(obp->ob_y - ob->ob_y) < HOME) {
		if (plyrplane) {
			initplyr(obp);
			initdisp(YES);
		} else if (compplane) {
			initcomp(obp);
		} else {
			initpln(obp);
		}
		return 0;
	}
	goinghome = TRUE;

	return aim(obp, ob->ob_x, ob->ob_y, NULL, NO);
}




static void cruise(OBJECTS *ob)
{
	register int orgx;

	courseadj = ((countmove & 0x001F) < 16) << 4;
	orgx = oobjects[currobx].ob_x;
	aim(ob, courseadj +
		(orgx < (MAX_X / 3) ? (MAX_X / 3) :
		 orgx > (2 * MAX_X / 3) ? (2 * MAX_X / 3) : orgx),
		MAX_Y - 50 - (courseadj >> 1), NULL, NO);
}

void attack(OBJECTS *obp, OBJECTS *obt)
{
	register OBJECTS *ob;

	courseadj = ((countmove & 0x001F) < 16) << 4;
	ob = obt;
	if (ob->ob_speed)
		aim(obp,
		    ob->ob_x - ((CLOSE * COS(ob->ob_angle)) >> 8),
		    ob->ob_y - ((CLOSE * SIN(ob->ob_angle)) >> 8), ob, NO);
	else
		aim(obp, ob->ob_x, ob->ob_y + 4, ob, NO);
}


void swauto(OBJECTS *ob)
{
	goinghome = FALSE;

	if (compnear[currobx])
		attack(ob, compnear[currobx]);
	else if (!ob->ob_athome)
		cruise(ob);

	compnear[currobx] = NULL;
}


int range(int x, int y, int ax, int ay)
{
	register int dx, dy;
	register int t;

	dy = abs(y - ay);
	dy += dy >> 1;
	dx = abs(x - ax);

	if (dx < 125 && dy < 125)
		return dx * dx + dy * dy;

	if (dx < dy) {
		t = dx;
		dx = dy;
		dy = t;
	}

	return -((7 * dx + (dy << 2)) >> 3);
}



//---------------------------------------------------------------------------
//
// $Log: swauto.c,v $
// Revision 1.2  2003/04/06 22:01:01  fraggle
// Fix compile warnings
//
// Revision 1.1.1.1  2003/02/14 19:03:08  fraggle
// Initial Sourceforge CVS import
//
//
// sdh 14/2/2003: change license header to GPL
// sdh 21/10/2001: rearranged file headers, added cvs tags
// sdh 21/10/2001: reformatted with indent, adjusted some code by 
// 		   hand to make more readable
// sdh 19/10/2001: removed all externs, this is now in headers
// 		   some static functions shuffled around to shut
//                 up the compiler
// sdh 18/10/2001: converted all functions to ANSI-style arguments
//
// 87-04-09        Don't attack until closer.
// 87-04-06        Computer plane avoiding oxen.
// 87-04-05        Missile and starburst support
// 87-03-31        Missiles.
// 87-03-12        Smarter shooting.
// 87-03-12        Wounded airplanes.
// 87-03-09        Microsoft compiler.
// 84-10-31        Atari
// 84-06-12        PCjr Speed-up
// 84-03-05        Development
//
//---------------------------------------------------------------------------

