//Copyright Paul Reiche, Fred Ford. 1992-2002

/*
 *  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.
 */

#include "ships/ship.h"
#include "ships/yehat/resinst.h"

#include "libs/mathlib.h"


#define MAX_CREW 20
#define MAX_ENERGY 10
#define ENERGY_REGENERATION 2
#define WEAPON_ENERGY_COST 1
#define SPECIAL_ENERGY_COST 3
#define ENERGY_WAIT 6
#define MAX_THRUST 30
#define THRUST_INCREMENT 6
#define TURN_WAIT 2
#define THRUST_WAIT 2
#define WEAPON_WAIT 0
#define SPECIAL_WAIT 2

#define SHIP_MASS 3
#define MISSILE_SPEED DISPLAY_TO_WORLD (20)
#define MISSILE_LIFE 10

static RACE_DESC yehat_desc =
{
	{
		FIRES_FORE | SHIELD_DEFENSE,
		23, /* Super Melee cost */
		750 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */
		MAX_CREW, MAX_CREW,
		MAX_ENERGY, MAX_ENERGY,
		{
			4970, 40,
		},
		(STRING)YEHAT_RACE_STRINGS,
		(FRAME)YEHAT_ICON_MASK_PMAP_ANIM,
		(FRAME)YEHAT_MICON_MASK_PMAP_ANIM,
	},
	{
		MAX_THRUST,
		THRUST_INCREMENT,
		ENERGY_REGENERATION,
		WEAPON_ENERGY_COST,
		SPECIAL_ENERGY_COST,
		ENERGY_WAIT,
		TURN_WAIT,
		THRUST_WAIT,
		WEAPON_WAIT,
		SPECIAL_WAIT,
		SHIP_MASS,
	},
	{
		{
			(FRAME)YEHAT_BIG_MASK_PMAP_ANIM,
			(FRAME)YEHAT_MED_MASK_PMAP_ANIM,
			(FRAME)YEHAT_SML_MASK_PMAP_ANIM,
		},
		{
			(FRAME)YEHAT_CANNON_BIG_MASK_PMAP_ANIM,
			(FRAME)YEHAT_CANNON_MED_MASK_PMAP_ANIM,
			(FRAME)YEHAT_CANNON_SML_MASK_PMAP_ANIM,
		},
		{
			(FRAME)SHIELD_BIG_MASK_ANIM,
			(FRAME)SHIELD_MED_MASK_ANIM,
			(FRAME)SHIELD_SML_MASK_ANIM,
		},
		{
			(FRAME)YEHAT_CAPTAIN_MASK_PMAP_ANIM,
			(FRAME)0,
			(FRAME)0,
			(FRAME)0,
			(FRAME)0,
		},
		(SOUND)YEHAT_VICTORY_SONG,
		(SOUND)YEHAT_SHIP_SOUNDS,
	},
	{
		0,
		MISSILE_SPEED * MISSILE_LIFE / 3,
		NULL_PTR,
	},
	(UNINIT_FUNC *) NULL,
	(PREPROCESS_FUNC *) NULL,
	(POSTPROCESS_FUNC *) NULL,
	(INIT_WEAPON_FUNC *) NULL,
	0,
};

static COUNT
initialize_standard_missiles (PELEMENT ShipPtr, HELEMENT MissileArray[])
{
#define YEHAT_OFFSET 16
#define LAUNCH_OFFS DISPLAY_TO_WORLD (8)
#define MISSILE_HITS 1
#define MISSILE_DAMAGE 1
#define MISSILE_OFFSET 1
	SIZE offs_x, offs_y;
	STARSHIPPTR StarShipPtr;
	MISSILE_BLOCK MissileBlock;

	GetElementStarShip (ShipPtr, &StarShipPtr);
	MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon;
	MissileBlock.face = MissileBlock.index = StarShipPtr->ShipFacing;
	MissileBlock.sender = (ShipPtr->state_flags & (GOOD_GUY | BAD_GUY))
			| IGNORE_SIMILAR;
	MissileBlock.pixoffs = YEHAT_OFFSET;
	MissileBlock.speed = MISSILE_SPEED;
	MissileBlock.hit_points = MISSILE_HITS;
	MissileBlock.damage = MISSILE_DAMAGE;
	MissileBlock.life = MISSILE_LIFE;
	MissileBlock.preprocess_func = NULL_PTR;
	MissileBlock.blast_offs = MISSILE_OFFSET;

	offs_x = -SINE (FACING_TO_ANGLE (MissileBlock.face), LAUNCH_OFFS);
	offs_y = COSINE (FACING_TO_ANGLE (MissileBlock.face), LAUNCH_OFFS);

	MissileBlock.cx = ShipPtr->next.location.x + offs_x;
	MissileBlock.cy = ShipPtr->next.location.y + offs_y;
	MissileArray[0] = initialize_missile (&MissileBlock);

	MissileBlock.cx = ShipPtr->next.location.x - offs_x;
	MissileBlock.cy = ShipPtr->next.location.y - offs_y;
	MissileArray[1] = initialize_missile (&MissileBlock);

	return (2);
}

static void
yehat_intelligence (PELEMENT ShipPtr, PEVALUATE_DESC ObjectsOfConcern, COUNT ConcernCounter)
{
	SIZE ShieldStatus;
	STARSHIPPTR StarShipPtr;
	PEVALUATE_DESC lpEvalDesc;

	ShieldStatus = -1;
	lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX];
	if (lpEvalDesc->ObjectPtr && lpEvalDesc->MoveState == ENTICE)
	{
		ShieldStatus = 0;
		if (!(lpEvalDesc->ObjectPtr->state_flags & (FINITE_LIFE | CREW_OBJECT)))
			lpEvalDesc->MoveState = PURSUE;
		else if (lpEvalDesc->ObjectPtr->mass_points
				|| (lpEvalDesc->ObjectPtr->state_flags & CREW_OBJECT))
		{
			if (!(lpEvalDesc->ObjectPtr->state_flags & FINITE_LIFE))
				lpEvalDesc->which_turn <<= 1;
			else
			{
				if ((lpEvalDesc->which_turn >>= 1) == 0)
					lpEvalDesc->which_turn = 1;

				if (lpEvalDesc->ObjectPtr->mass_points)
					lpEvalDesc->ObjectPtr = 0;
				else
					lpEvalDesc->MoveState = PURSUE;
			}
			ShieldStatus = 1;
		}
	}

	GetElementStarShip (ShipPtr, &StarShipPtr);
	if (StarShipPtr->special_counter == 0)
	{
		StarShipPtr->ship_input_state &= ~SPECIAL;
		if (ShieldStatus)
		{
			if (ShipPtr->life_span <= NORMAL_LIFE + 1
					&& (ShieldStatus > 0 || lpEvalDesc->ObjectPtr)
					&& lpEvalDesc->which_turn <= 2
					&& (ShieldStatus > 0
					|| (lpEvalDesc->ObjectPtr->state_flags
					& PLAYER_SHIP) /* means IMMEDIATE WEAPON */
					|| PlotIntercept (lpEvalDesc->ObjectPtr,
					ShipPtr, 2, 0))
					&& (TFB_Random () & 3))
				StarShipPtr->ship_input_state |= SPECIAL;

			if (lpEvalDesc->ObjectPtr
					&& !(lpEvalDesc->ObjectPtr->state_flags & CREW_OBJECT))
				lpEvalDesc->ObjectPtr = 0;
		}
	}

	if ((lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX])->ObjectPtr)
	{
		STARSHIPPTR EnemyStarShipPtr;

		GetElementStarShip (lpEvalDesc->ObjectPtr, &EnemyStarShipPtr);
		if (!(EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags
				& IMMEDIATE_WEAPON))
			lpEvalDesc->MoveState = PURSUE;
	}
	ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter);
/*
	if (StarShipPtr->RaceDescPtr->ship_info.energy_level <= SPECIAL_ENERGY_COST)
		StarShipPtr->ship_input_state &= ~WEAPON;
*/
}

static void
yehat_postprocess (PELEMENT ElementPtr)
{
	if (!(ElementPtr->state_flags & NONSOLID))
	{
		STARSHIPPTR StarShipPtr;

		GetElementStarShip (ElementPtr, &StarShipPtr);
				/* take care of shield effect */
		if (StarShipPtr->special_counter > 0)
		{
			if (ElementPtr->life_span == NORMAL_LIFE)
				StarShipPtr->special_counter = 0;
			else
			{
#ifdef OLD
				SetPrimColor (
						&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex],
						BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F)
						);
				SetPrimType (
						&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex],
						STAMPFILL_PRIM
						);
#endif /* OLD */

				ProcessSound (SetAbsSoundIndex (
								/* YEHAT_SHIELD_ON */
						StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr);
				DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST);
			}
		}

#ifdef OLD
		if (ElementPtr->life_span > NORMAL_LIFE)
		{
			HELEMENT hShipElement;

			if (hShipElement = AllocElement ())
			{
				ELEMENTPTR ShipElementPtr;

				InsertElement (hShipElement, GetSuccElement (ElementPtr));
				LockElement (hShipElement, &ShipElementPtr);

				ShipElementPtr->state_flags =
							/* in place of APPEARING */
						(CHANGING | PRE_PROCESS | POST_PROCESS)
						| FINITE_LIFE | NONSOLID
						| (ElementPtr->state_flags & (GOOD_GUY | BAD_GUY));
				SetPrimType (
						&(GLOBAL (DisplayArray))[ShipElementPtr->PrimIndex],
						STAMP_PRIM
						);

				ShipElementPtr->life_span = 0; /* because preprocessing
													 * will not be done
													 */
				ShipElementPtr->current.location = ElementPtr->next.location;
				ShipElementPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.ship;
				ShipElementPtr->current.image.frame =
						SetAbsFrameIndex (StarShipPtr->RaceDescPtr->ship_data.ship[0],
						StarShipPtr->ShipFacing);
				ShipElementPtr->next = ShipElementPtr->current;
				ShipElementPtr->preprocess_func =
						ShipElementPtr->postprocess_func =
						ShipElementPtr->death_func = NULL_PTR;
				ZeroVelocityComponents (&ShipElementPtr->velocity);

				UnlockElement (hShipElement);
			}
		}
#endif /* OLD */
	}
}

static void
yehat_preprocess (PELEMENT ElementPtr)
{
	if (!(ElementPtr->state_flags & APPEARING))
	{
		STARSHIPPTR StarShipPtr;

		GetElementStarShip (ElementPtr, &StarShipPtr);
		if ((ElementPtr->life_span > NORMAL_LIFE
				/* take care of shield effect */
				&& --ElementPtr->life_span == NORMAL_LIFE)
				|| (ElementPtr->life_span == NORMAL_LIFE
				&& ElementPtr->next.image.farray
						== StarShipPtr->RaceDescPtr->ship_data.special))
		{
#ifdef NEVER
			SetPrimType (
					&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex],
					STAMP_PRIM
					);
#endif /* NEVER */

			ElementPtr->next.image.farray = StarShipPtr->RaceDescPtr->ship_data.ship;
			ElementPtr->next.image.frame =
					SetEquFrameIndex (StarShipPtr->RaceDescPtr->ship_data.ship[0],
					ElementPtr->next.image.frame);
			ElementPtr->state_flags |= CHANGING;
		}

		if ((StarShipPtr->cur_status_flags & SPECIAL)
				&& StarShipPtr->special_counter == 0)
		{
			if (StarShipPtr->RaceDescPtr->ship_info.energy_level < SPECIAL_ENERGY_COST)
				DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST); /* so text will flash */
			else
			{
#define SHIELD_LIFE 10
				ElementPtr->life_span = SHIELD_LIFE + NORMAL_LIFE;

				ElementPtr->next.image.farray = StarShipPtr->RaceDescPtr->ship_data.special;
				ElementPtr->next.image.frame =
						SetEquFrameIndex (StarShipPtr->RaceDescPtr->ship_data.special[0],
						ElementPtr->next.image.frame);
				ElementPtr->state_flags |= CHANGING;

				StarShipPtr->special_counter =
						StarShipPtr->RaceDescPtr->characteristics.special_wait;
			}
		}
	}
}

RACE_DESCPTR
init_yehat (void)
{
	RACE_DESCPTR RaceDescPtr;

	yehat_desc.preprocess_func = yehat_preprocess;
	yehat_desc.postprocess_func = yehat_postprocess;
	yehat_desc.init_weapon_func = initialize_standard_missiles;
	yehat_desc.cyborg_control.intelligence_func =
			(void (*) (PVOID ShipPtr, PVOID ObjectsOfConcern, COUNT
					ConcernCounter)) yehat_intelligence;

	RaceDescPtr = &yehat_desc;

	return (RaceDescPtr);
}
