/**
WVChameleon.ChameleonRailgun

Creation date: 2014-01-04 18:01
Last change: $Id$
Copyright (c) 2014, Wormbo
*/

class ChameleonRailgun extends ONSWeapon dependson(RailgunTraceHelper);


#exec texture import file=Textures\ChameleonTankTurretRed.dds
#exec texture import file=Textures\ChameleonTankTurretBlue.dds
#exec audio import file=Sounds\RailgunTankFire.wav


var float OuterTraceOffset;
var float TraceThickness;
var class<ShockBeamEffect> BeamEffectClass[2];


function TraceFire(Vector Start, Rotator Dir)
{
	local vector X, Y, Z, HitLocation, HitNormal, ImpactNormal, RefNormal;
	local vector TraceStart, TraceEnd;
	local float Dist, TraceDist, Damage;
	local Actor Other;
	local ONSWeaponPawn WeaponPawn;
	local int i, j;
	local array<RailgunTraceHelper.THitInfo> Hits;

	MaxRange();

	if (bDoOffsetTrace) {
		WeaponPawn = ONSWeaponPawn(Owner);
		if (WeaponPawn != None && WeaponPawn.VehicleBase != None) {
			if (!WeaponPawn.VehicleBase.TraceThisActor(HitLocation, HitNormal, Start, Start + vector(Dir) * (WeaponPawn.VehicleBase.CollisionRadius * 1.5)))
				Start = HitLocation;
		}
		else if (!Owner.TraceThisActor(HitLocation, HitNormal, Start, Start + vector(Dir) * (Owner.CollisionRadius * 1.5)))
			Start = HitLocation;
	}

	GetAxes(Dir + rot(0,0,1000), X, Y, Z);

	for (i = -1; i <= 1 && TraceDist < TraceRange; ++i) {
		for (j = -1; j <= 1; j++) {
			if (Abs(i) + Abs(j) >= 1) {
				TraceStart = Start + OuterTraceOffset * (i * Y + j * Z) / Sqrt(Max(i * i + j * j, 1));
				TraceEnd = TraceStart + TraceRange * X;
				Other = Trace(HitLocation, HitNormal, TraceEnd, TraceStart, false);
				if (Other == None) {
					TraceDist = TraceRange;
					ImpactNormal = vect(0,0,0);
					break;
				}
				Dist = VSize(HitLocation - TraceStart);
				if (Dist > TraceDist) {
					TraceDist = Dist;
					ImpactNormal = HitNormal;
				}
			}
		}
	}

	TraceStart = Start;
	TraceEnd = Start + TraceDist * X;
	LastHitLocation = TraceEnd;
	Hits = class'RailgunTraceHelper'.static.TraceHits(Self, TraceStart, TraceEnd, TraceThickness);
	for (i = 0; i < Hits.Length; i++)
	{
		Other = Hits[i].HitActor;

		if (Other.bBlockProjectiles || ONSPowerCoreShield(Other) != None)
			break;

		if (Other != Self && Other != Instigator && (Other.bWorldGeometry || Other.bProjTarget || Other.bBlockActors)) {
			SpawnHitEffects(Other, HitLocation, HitNormal);
			Damage = RandRange(DamageMin, DamageMax);
			if (Other.TraceThisActor(HitLocation, HitNormal, TraceEnd, TraceStart))
			{
				// grazing shot, reduce damage
				Damage *= 0.5;
			}
			HitLocation = Hits[i].HitLocation;
			HitNormal = Hits[i].Hitnormal;
			if (Pawn(Other) != None && Pawn(Other).Weapon != None && Pawn(Other).Weapon.CheckReflect(HitLocation, RefNormal, (DamageMin + DamageMax) / 3)) {
				// successfully blocked by shieldgun, apply reduced damage but increased momentum
				Other.TakeDamage(Damage * 0.3, Instigator, HitLocation, 1.5 * Momentum * Normal(HitLocation - Start), DamageType);
			}
			else {
				Other.TakeDamage(Damage, Instigator, HitLocation, Momentum * Normal(HitLocation - Start), DamageType);
			}
		}

	}

	if (ImpactNormal != vect(0,0,0))
	{
		HitCount++;
		SpawnHitEffects(Other, LastHitLocation, ImpactNormal);
	}
	SpawnBeamEffect(Start, Dir, LastHitLocation, ImpactNormal, int(TraceDist) + 50);

	NetUpdateTime = Level.TimeSeconds - 1;
}


function SpawnBeamEffect(Vector Start, Rotator Dir, Vector HitLocation, Vector HitNormal, int ReflectNum)
{
	local ShockBeamEffect Beam;

	Beam = Spawn(BeamEffectClass[Instigator.GetTeamNum() % ArrayCount(BeamEffectClass)],,, Start, Dir);
	Beam.Instigator = None; // prevents client side repositioning of beam start
	Beam.AimAt(HitLocation, HitNormal);
}


simulated event FlashMuzzleFlash()
{
	Super.FlashMuzzleFlash();

	if (Level.NetMode != NM_DedicatedServer) {
		PlayAnim('Fire', 0.5, 0);
		ShakeView();
	}
}


simulated function float ChargeBar()
{
	return FMin(1 - FireCountdown / FireInterval, 0.999);
}


function bool CanAttack(Actor Other)
{
	local vector X, Y, Z, Dir;
	local float UpperLimit, LowerLimit;
	const RAD_TO_UROT = 10430.37835;
	local float Dist;
	local vector HitLocation, HitNormal, projStart;
	local Actor HitActor;

	if (Instigator == None || Instigator.Controller == None || Other == None)
		return false;

	// check pitch limits
	GetAxes(Instigator.Rotation, X, Y, Z);
	Dir = Normal(Other.Location - Instigator.Location);

	UpperLimit = float(PitchUpLimit) / RAD_TO_UROT;
	if (UpperLimit > PI)
		UpperLimit -= 2 * PI;
	LowerLimit = float(PitchDownLimit) / RAD_TO_UROT;
	if (LowerLimit > PI)
		LowerLimit -= 2 * PI;

	if (Dir dot Z > Sin(FClamp(UpperLimit, -PI, PI)) || Dir dot Z < Sin(FClamp(LowerLimit, -PI, PI)))
		return false;

	// check that target is within range
	Dist = VSize(Instigator.Location - Other.Location);
	if (Dist > MaxRange())
		return false;

	// check that can see target
	if (!Instigator.Controller.LineOfSightTo(Other))
		return false;

	// check that would hit target, and not a friendly
	CalcWeaponFire();
	projStart = WeaponFireLocation;
	HitActor = Trace(HitLocation, HitNormal, Other.Location + Other.CollisionHeight * vect(0,0,0.8), projStart, true);

	if (HitActor == None || HitActor == Other || Pawn(HitActor) == None || Pawn(HitActor).Controller == None || !Instigator.Controller.SameTeamAs(Pawn(HitActor).Controller))
		return true;

	return false;
}

//=============================================================================
// Default values
//=============================================================================

defaultproperties
{
	Mesh     = Mesh'AS_VehiclesFull_M.IonTankTurretSimple'
	RedSkin  = Texture'ChameleonTankTurretRed'
	BlueSkin = Texture'ChameleonTankTurretBlue'

	SoundRadius        = 512
	BeamEffectClass[0] = class'RailgunBeamEffectRed'
	BeamEffectClass[1] = class'RailgunBeamEffect'
	FireSoundClass     = Sound'RailgunTankFire'
	EffectEmitterClass = None
	RotationsPerSecond = 0.25

	TraceRange       = 20000.0
	TraceThickness   =    15.0
	OuterTraceOffset =     5.0
	bInstantFire     = True
	FireInterval     = 2.0
	DamageMin  = 275
	DamageMax  = 275
	Momentum   = 50000.0
	DamageType = class'DamTypeChameleonRailgun'

	Spread    = 0.005
	AIInfo(0) = (bLeadTarget=false,bTrySplash=false,bInstantHit=true,WarnTargetPct=1.0,RefireRate=0.85)
}
