//=============================================================================
// Warlord.
//=============================================================================
class Warlord expands ScriptedPawn;

#exec MESH IMPORT MESH=Warlord ANIVFILE=MODELS\warlor_a.3D DATAFILE=MODELS\warlor_d.3D X=0 Y=0 Z=0
#exec MESH ORIGIN MESH=Warlord X=0 Y=-300 Z=0 YAW=64 Roll=-64

#exec MESH SEQUENCE MESH=warlord SEQ=All		STARTFRAME=0	NUMFRAMES=381
#exec MESH SEQUENCE MESH=warlord SEQ=Breath		STARTFRAME=0	NUMFRAMES=40
#exec MESH SEQUENCE MESH=warlord SEQ=Dead1		STARTFRAME=40   NUMFRAMES=51
#exec MESH SEQUENCE MESH=warlord SEQ=TakeHit	STARTFRAME=40   NUMFRAMES=1
#exec MESH SEQUENCE MESH=warlord SEQ=Fire		STARTFRAME=91   NUMFRAMES=30  Group=Attack
#exec MESH SEQUENCE MESH=warlord SEQ=Fighter	STARTFRAME=91	NUMFRAMES=1
#exec MESH SEQUENCE MESH=warlord SEQ=Fly		STARTFRAME=121  NUMFRAMES=30
#exec MESH SEQUENCE MESH=warlord SEQ=FlyFire	STARTFRAME=151  NUMFRAMES=30  Group=MovingAttack
#exec MESH SEQUENCE MESH=warlord SEQ=Land		STARTFRAME=181  NUMFRAMES=30
#exec MESH SEQUENCE MESH=warlord SEQ=Run		STARTFRAME=211  NUMFRAMES=20
#exec MESH SEQUENCE MESH=warlord SEQ=Strike		STARTFRAME=231  NUMFRAMES=30  Group=Attack
#exec MESH SEQUENCE MESH=warlord SEQ=TakeOff	STARTFRAME=261  NUMFRAMES=20
#exec MESH SEQUENCE MESH=warlord SEQ=Twirl		STARTFRAME=281  NUMFRAMES=40
#exec MESH SEQUENCE MESH=warlord SEQ=Walk		STARTFRAME=321  NUMFRAMES=30
#exec MESH SEQUENCE MESH=warlord SEQ=WalkFire	STARTFRAME=351  NUMFRAMES=30  Group=MovingAttack

#exec TEXTURE IMPORT NAME=JWarlord1 FILE=MODELS\warlord.PCX GROUP=Skins FLAGS=2
#exec MESHMAP SCALE MESHMAP=Warlord X=0.17 Y=0.17 Z=0.34
#exec MESHMAP SETTEXTURE MESHMAP=warlord NUM=1 TEXTURE=Jwarlord1

#exec MESH NOTIFY MESH=Warlord SEQ=Dead1 TIME=0.78 FUNCTION=LandThump
#exec MESH NOTIFY MESH=Warlord SEQ=Fly TIME=0.1 FUNCTION=Flap
#exec MESH NOTIFY MESH=Warlord SEQ=FlyFire TIME=0.1 FUNCTION=Flap
#exec MESH NOTIFY MESH=Warlord SEQ=TakeOff TIME=0.1 FUNCTION=Flap
#exec MESH NOTIFY MESH=Warlord SEQ=Run TIME=0.25 FUNCTION=Step
#exec MESH NOTIFY MESH=Warlord SEQ=Run TIME=0.75 FUNCTION=Step
#exec MESH NOTIFY MESH=Warlord SEQ=Walk TIME=0.33 FUNCTION=Step
#exec MESH NOTIFY MESH=Warlord SEQ=Walk TIME=0.66 FUNCTION=Step
#exec MESH NOTIFY MESH=Warlord SEQ=WalkFire TIME=0.33 FUNCTION=Step
#exec MESH NOTIFY MESH=Warlord SEQ=WalkFire TIME=0.66 FUNCTION=Step

#exec AUDIO IMPORT FILE="Sounds\WarLord\injur1W.WAV" NAME="injur1WL" GROUP="WarLord"
#exec AUDIO IMPORT FILE="Sounds\WarLord\injur2W.WAV" NAME="injur2WL" GROUP="WarLord"
#exec AUDIO IMPORT FILE="Sounds\WarLord\aquire1W.WAV" NAME="acquire1WL" GROUP="WarLord"
#exec AUDIO IMPORT FILE="Sounds\WarLord\DCry1W.WAV" NAME="DeathCry1WL" GROUP="WarLord"
#exec AUDIO IMPORT FILE="Sounds\WarLord\fly1W.WAV" NAME="fly1WL" GROUP="WarLord"
#exec AUDIO IMPORT FILE="Sounds\WarLord\roam1W.WAV" NAME="roam1WL" GROUP="WarLord"
#exec AUDIO IMPORT FILE="Sounds\WarLord\threat1W.WAV" NAME="threat1WL" GROUP="WarLord"
#exec AUDIO IMPORT FILE="Sounds\WarLord\breath1.WAV" NAME="breath1WL" GROUP="WarLord"
#exec AUDIO IMPORT FILE="Sounds\Titan\step1a.WAV" NAME="step1t" GROUP="Titan"

//FIXME - use TakeOff animation (maybe for falling start)

var() byte	StrikeDamage;

function PreSetMovement()
{
	bCanJump = true;
	bCanWalk = true;
	bCanSwim = false;
	bCanFly = true;
	MinHitWall = -0.6;
	bCanOpenDoors = true;
	bCanDoSpecial = true;
}

event Landed(vector HitNormal)
{
	SetPhysics(PHYS_Walking);
	if ( !IsAnimating() )
		PlayLanded(Velocity.Z);
	if (Velocity.Z < -1.4 * JumpZ)
		MakeNoise(-0.5 * Velocity.Z/(FMax(JumpZ, 150.0)));
	bJustLanded = true;
}

function Step()
{
	PlaySound(sound'step1t', SLOT_Interact, 9.0);
}

function Flap()
{
	PlaySound(sound'fly1WL', SLOT_Interact, 9.0);
}

function SetMovementPhysics()
{
	if (Enemy != None)
	{
		if (Physics == PHYS_None)
			SetPhysics(PHYS_Walking);
		else if ( Region.Zone.bWaterZone || (Physics != PHYS_Walking) )
			SetPhysics(PHYS_Flying);
	} 
	else if (Physics != PHYS_Falling)
		SetPhysics(PHYS_Walking);
}

singular function Falling()
{
	SetPhysics(PHYS_Flying);
}

function PlayWaiting()
	{
	if (AnimSequence == 'Land')
	{
		TweenAnim('Breath', 0.3);
		return;
	}
	PlaySound(sound'breath1WL', SLOT_Interact, 9.0);
	if (FRand() < 0.9)
		LoopAnim('Breath', 0.2 + 0.7 * FRand());
	else
		LoopAnim('Twirl', 0.5 + 0.5 * FRand());
	}

function PlayPatrolStop()
{
	if (Physics == PHYS_Flying)
		LoopAnim('Fly', 0.4);
	else
		PlayWaiting();
}

function PlayWaitingAmbush()
{
	PlayWaiting();
}

function PlayChallenge()
{
	if (Physics == PHYS_Flying)
		PlayAnim('Fly', 0.7, 0.1);
	else
		TweenAnim('Fighter', 0.15);
}

function TweenToFighter(float tweentime)
{
	if (Physics == PHYS_Flying)
		TweenAnim('Fly', tweentime);
	else
		TweenAnim('Fighter', tweentime);
}

function TweenToRunning(float tweentime)
{
	if ( IsAnimating() && ((AnimSequence == 'WalkFire') || (AnimSequence == 'FlyFire')) )
		return;
	if (Physics == PHYS_Flying)
	{
		if ( (AnimSequence != 'Fly') || !bAnimLoop )
			TweenAnim('Fly', tweentime);
	}
	else if ( (AnimSequence != 'Run') || !bAnimLoop )
		TweenAnim('Run', tweentime);

}

function TweenToWalking(float tweentime)
{
	if (Physics == PHYS_Flying)
		TweenAnim('Fly', tweentime);
	else
		TweenAnim('Walk', tweentime);
}

function TweenToWaiting(float tweentime)
{
	PlayAnim('Land', 0.2 + 0.8 * FRand());
	SetPhysics(PHYS_Falling);
}

function TweenToPatrolStop(float tweentime)
{
	if (Physics == PHYS_Flying)
	{
		if (FRand() < 0.3)
		{
			SetPhysics(PHYS_Falling);
			PlayAnim('Land', 0.7);
		}
		else
			TweenAnim('Fly', tweentime);
	}
	else
		TweenAnim('Breath', tweentime);

}

function PlayRunning()
{
	if (Physics == PHYS_Walking)
		LoopAnim('Run', -1.0/GroundSpeed,, 0.4);
	else
		LoopAnim('Fly', -1.0/AirSpeed,, 0.4);
}

function PlayWalking()
{
	if (Physics == PHYS_Walking)
		LoopAnim('Walk', -1.0/GroundSpeed,, 0.4);
	else
		LoopAnim('Fly', -1.0/AirSpeed,, 0.4);
}

function PlayThreatening()
{
	if (Physics == PHYS_Walking)
		TweenAnim('Fighter', 0.3);
	else
		LoopAnim('Fly', -1.0/AirSpeed,, 0.4);
}

function PlayTurning()
{
	if (Physics == PHYS_Walking)
		TweenAnim('Walk', 0.3);
	else
		LoopAnim('Fly');
}

function PlayDying(name DamageType, vector HitLocation)
{
	PlaySound(Die, SLOT_Talk);
	PlayAnim('Dead1', 0.7, 0.15);
}

function PlayTakeHit(float tweentime, vector HitLoc, int damage)
{
	TweenAnim('TakeHit', tweentime);
}

function TweenToFalling()
{
	TweenAnim('Fly', 0.2);
}

function PlayInAir()
{
	LoopAnim('Fly');
}

function PlayLanded(float impactVel)
{
	PlayAnim('Land');
}

function PlayVictoryDance()
{
	PlayAnim('Strike', 0.6, 0.1);
}
	
function PlayMeleeAttack()
{
	if (Physics == PHYS_Flying)
	{
		PlayRangedAttack();
		return;
	}
	PlayAnim('Strike');
	if ( MeleeDamageTarget(StrikeDamage, (StrikeDamage * 1000.0 * Normal(Target.Location - Location))) )
		PlaySound(Threaten, SLOT_Talk); 
}


function bool CanFireAtEnemy()
{
	local vector HitLocation, HitNormal,X,Y,Z, projStart;
	local actor HitActor;
	local rotation EnemyRot;
	
	if (!LineOfSightTo(Enemy))
		return false;
	
	EnemyRot = Rotation(Enemy.Location - Location);	
	GetAxes(EnemyRot,X,Y,Z);
	projStart = Location + 0.8 * CollisionRadius * X - 0.7 * CollisionRadius * Y;
	HitActor = Trace(HitLocation, HitNormal, 
				projStart + (MeleeRange + Enemy.CollisionRadius) * X,
				projStart , false);

	return (HitActor == None);
}

function PlayRangedAttack()
{
	local vector X,Y,Z, projStart;
	local rotation projRotation;
	if (Physics == PHYS_Flying)
		PlayAnim('FlyFire');
	else
		PlayAnim('Fire');
	 
	GetAxes(Rotation,X,Y,Z);
	projStart = Location - 0.5 * CollisionRadius * Y;
	projRotation = AdjustAim(ProjectileSpeed, projStart, 0, bLeadTarget, bWarnTarget); 
	spawn(RangedProjectile ,self,'',projStart,projRotation);

	projStart = projStart + 0.8 * CollisionRadius * X;
	projRotation.Yaw += 3072;
	spawn(RangedProjectile ,self,'',projStart, projRotation);

	projStart = projStart + 0.5 * CollisionRadius * X;
	projRotation.Yaw -= 6144;
	spawn(RangedProjectile ,self,'',projStart, projRotation);
}

function PlayMovingAttack()
{
	local vector X,Y,Z, projStart;
	local rotation projRotation;
	if (Physics == PHYS_Flying)
		PlayAnim('FlyFire');
	else
	{
		DesiredSpeed = 0.4;
		PlayAnim('WalkFire');
	}
	GetAxes(Rotation,X,Y,Z);
	projStart = Location - 0.5 * CollisionHeight * Y;
	projRotation = AdjustAim(ProjectileSpeed, projStart, 600, bLeadTarget, bWarnTarget); 
	spawn(RangedProjectile ,self,'',projStart,projRotation);

	projStart = Location - 0.5 * CollisionHeight * Y + CollisionRadius * X;
	if (FRand() < 0.5)
		projRotation.Yaw += 3072; 
	else
		projRotation.Yaw -= 3072; 
	
	spawn(RangedProjectile ,self,'',projStart,projRotation);
}

State Charging
{
	function HitWall(vector HitNormal, actor Wall)
	{
		if ( (Physics == PHYS_Flying) && (HitNormal.Z > 0.7) )
		{
			SetPhysics(PHYS_Walking);
			return;
		}
		CallParent.HitWall(HitNormal, Wall);
	}

	function BeginState()
	{
		local vector HitLocation, HitNormal;
		local actor HitActor;

		if ( (Enemy.Location.Z > Location.Z + MaxStepHeight) || (FRand() < 0.3) )
		{
			Velocity.Z = 400;
			SetPhysics(PHYS_Flying);
		}
		else if ( !Region.Zone.bWaterZone )
		{	
			HitActor = Trace(HitLocation, HitNormal, Location - 2 * CollisionHeight * vect(0,0,1), Location, true);
			if (HitActor == Level)
				SetPhysics(PHYS_Falling);
		}				
		CallParent.BeginState();
	}
}

State TacticalMove
{
	function HitWall(vector HitNormal, actor Wall)
	{
		if (HitNormal.Z > 0.7)
		{
			SetPhysics(PHYS_Walking);
			return;
		}
		Focus = Destination;
		if (PickWallAdjust())
			GotoState('TacticalMove', 'AdjustFromWall');
		else
		{
			DesiredRotation = Rotation(Enemy.Location - location);
			GotoState('Attacking');
		}
	}

	function BeginState()
	{
		local vector HitLocation, HitNormal;
		local actor HitActor;

		if ( (FRand() < 0.3) || 
				(Enemy.Location.Z - Location.Z) > MaxStepHeight + 2 * (CollisionHeight - Enemy.CollisionHeight) )
		{
			Velocity.Z = 400;
			SetPhysics(PHYS_Flying);
		}
		else if ( !Region.Zone.bWaterZone )
		{	
			HitActor = Trace(HitLocation, HitNormal, Location - 2 * CollisionHeight * vect(0,0,1), Location, true);
			if (HitActor == Level)
				SetPhysics(PHYS_Falling);
		}				
		CallParent.BeginState();
	}

}

