//=============================================================================
// ChainsawFire
//=============================================================================
// Looping chainsaw fire class
//=============================================================================
// Killing Floor Source
// Copyright (C) 2009 Tripwire Interactive LLC
// - John "Ramm-Jaeger" Gibson
//=============================================================================
class ChainsawFire extends KFMeleeFire;

// sound
var 	sound   				FireStartSound;				// The sound to play at the beginning of the ambient fire sound
var 	sound   				FireEndSound;				// The sound to play at the end of the ambient fire sound
var 	float   				AmbientFireSoundRadius;		// The sound radius for the ambient fire sound
var		sound					AmbientFireSound;           // The ambient fire sound
var		sound					AmbientIdleSound;           // The ambient idle sound
var		byte					AmbientFireVolume;          // How loud to play the looping ambient fire sound

var		string			FireStartSoundRef;
var		string			FireEndSoundRef;
var		string			AmbientFireSoundRef;
var		string			AmbientIdleSoundRef;

var int maxAdditionalDamage;

static function PreloadAssets(optional KFMeleeFire Spawned)
{
	super.PreloadAssets(Spawned);

	default.FireStartSound = sound(DynamicLoadObject(default.FireStartSoundRef, class'sound', true));
	default.FireEndSound = sound(DynamicLoadObject(default.FireEndSoundRef, class'sound', true));
	default.AmbientFireSound = sound(DynamicLoadObject(default.AmbientFireSoundRef, class'sound', true));
	default.AmbientIdleSound = sound(DynamicLoadObject(default.AmbientIdleSoundRef, class'sound', true));

	if ( ChainsawFire(Spawned) != none )
	{
		ChainsawFire(Spawned).FireStartSound = default.FireStartSound;
		ChainsawFire(Spawned).FireEndSound = default.FireEndSound;
		ChainsawFire(Spawned).AmbientFireSound = default.AmbientFireSound;
		ChainsawFire(Spawned).AmbientIdleSound = default.AmbientIdleSound;
	}
}

static function bool UnloadAssets()
{
	super.UnloadAssets();

	default.FireStartSound = none;
	default.FireEndSound = none;
	default.AmbientFireSound = none;
	default.AmbientIdleSound = none;

	return true;
}

// Sends the fire class to the looping state
function StartFiring()
{
   GotoState('FireLoop');
}

// Handles toggling the weapon attachment's ambient sound on and off
function PlayAmbientSound(Sound aSound)
{
	local WeaponAttachment WA;

	WA = WeaponAttachment(Weapon.ThirdPersonActor);

    if ( Weapon == none || (WA == none))
        return;

	if(aSound == None)
	{
		WA.SoundVolume = WA.default.SoundVolume;
		WA.SoundRadius = WA.default.SoundRadius;
	}
	else
	{
		WA.SoundVolume = AmbientFireVolume;
		WA.SoundRadius = AmbientFireSoundRadius;
	}

    WA.AmbientSound = aSound;
}

function PlayDefaultAmbientSound()
{
	local WeaponAttachment WA;

	WA = WeaponAttachment(Weapon.ThirdPersonActor);

    if ( Weapon == none || (WA == none))
        return;

	WA.SoundVolume = WA.default.SoundVolume;
	WA.SoundRadius = WA.default.SoundRadius;
	WA.AmbientSound=WA.default.AmbientSound;
}

// Make sure we are in the fire looping state when we fire
event ModeDoFire()
{
	local float Rec;

	if( AllowFire() && IsInState('FireLoop'))
	{
    	Rec = GetFireSpeed();

    	FireRate = default.FireRate/Rec;
    	FireAnimRate = default.FireAnimRate*Rec;
    	ReloadAnimRate = default.ReloadAnimRate*Rec;

    	if (MaxHoldTime > 0.0)
    		HoldTime = FMin(HoldTime, MaxHoldTime);

    	// server
    	if (Weapon.Role == ROLE_Authority)
    	{
    		Weapon.ConsumeAmmo(ThisModeNum, Load);
    		DoFireEffect();

    		HoldTime = 0;   // if bot decides to stop firing, HoldTime must be reset first
    		if ( (Instigator == None) || (Instigator.Controller == None) )
    			return;

    		if ( AIController(Instigator.Controller) != None )
    			AIController(Instigator.Controller).WeaponFireAgain(BotRefireRate, true);

    		Instigator.DeactivateSpawnProtection();
    	}

    	// client
    	if (Instigator.IsLocallyControlled())
    	{
    		ShakeView();
    		PlayFiring();
    		FlashMuzzleFlash();
    		StartMuzzleSmoke();
    		ClientPlayForceFeedback(FireForce);
    	}
    	else // server
    		ServerPlayFiring();

    	Weapon.IncrementFlashCount(ThisModeNum);

    	// set the next firing time. must be careful here so client and server do not get out of sync
    	if (bFireOnRelease)
    	{
    		if (bIsFiring)
    			NextFireTime += MaxHoldTime + FireRate;
    		else
    			NextFireTime = Level.TimeSeconds + FireRate;
    	}
    	else
    	{
    		NextFireTime += FireRate;
    		NextFireTime = FMax(NextFireTime, Level.TimeSeconds);
    	}

    	Load = AmmoPerFire;
    	HoldTime = 0;

    	if (Instigator.PendingWeapon != Weapon && Instigator.PendingWeapon != None)
    	{
    		bIsFiring = false;
    		Weapon.PutDown();
    	}


    	if( Weapon.Owner != none && Weapon.Owner.Physics != PHYS_Falling )
    	{
            Weapon.Owner.Velocity.x *= KFMeleeGun(Weapon).ChopSlowRate;
        	Weapon.Owner.Velocity.y *= KFMeleeGun(Weapon).ChopSlowRate;
    	}
	}
}

function DoFireEffect()
{
	local KFMeleeGun kf;
	local int damage ;
	local Actor HitActor;
	local vector StartTrace, EndTrace, HitLocation, HitNormal;
	local rotator PointRot;
	local int MyDamage;
	local bool bBackStabbed;

	if(KFMeleeGun(Weapon) == none)
		return;

	kf = KFMeleeGun(Weapon);
	damage = MeleeDamage + Rand(MaxAdditionalDamage) ;

	MyDamage = MeleeDamage + Rand(MaxAdditionalDamage);

	If( !KFWeapon(Weapon).bNoHit )
	{
		MyDamage = MeleeDamage + Rand(MaxAdditionalDamage);
		StartTrace = Instigator.Location + Instigator.EyePosition();

		if( Instigator.Controller!=None && PlayerController(Instigator.Controller)==None && Instigator.Controller.Enemy!=None )
		{
        	PointRot = rotator(Instigator.Controller.Enemy.Location-StartTrace); // Give aimbot for bots.
        }
		else
        {
            PointRot = Instigator.GetViewRotation();
        }

		EndTrace = StartTrace + vector(PointRot)*weaponRange;
		HitActor = Instigator.Trace( HitLocation, HitNormal, EndTrace, StartTrace, true);

		if (HitActor!=None)
		{
			//ImpactShakeView();

			if( HitActor.IsA('ExtendedZCollision') && HitActor.Base != none &&
                HitActor.Base.IsA('KFMonster') )
            {
                HitActor = HitActor.Base;
            }

			if ( (HitActor.IsA('KFMonster') || HitActor.IsA('KFHumanPawn')) && KFMeleeGun(Weapon).BloodyMaterial!=none )
			{
				Weapon.Skins[KFMeleeGun(Weapon).BloodSkinSwitchArray] = KFMeleeGun(Weapon).BloodyMaterial;
				Weapon.texture = Weapon.default.Texture;
			}
			if( Level.NetMode==NM_Client )
            {
                Return;
            }

			if( HitActor.IsA('Pawn') && !HitActor.IsA('Vehicle')
			 && (Normal(HitActor.Location-Instigator.Location) Dot vector(HitActor.Rotation))>0 )
			{
				bBackStabbed = true;
				MyDamage*=2; // Backstab >:P
			}

			if( (KFMonster(HitActor)!=none) )
			{
			//	log(VSize(Instigator.Velocity));

				KFMonster(HitActor).bBackstabbed = bBackStabbed;

                HitActor.TakeDamage(MyDamage, Instigator, HitLocation, vector(PointRot), hitDamageClass) ;

            	if(MeleeHitSounds.Length > 0)
            	{
            		Weapon.PlaySound(MeleeHitSounds[Rand(MeleeHitSounds.length)],SLOT_None,MeleeHitVolume,,,,false);
            	}

				if(VSize(Instigator.Velocity) > 300 && KFMonster(HitActor).Mass <= Instigator.Mass)
				{
				    KFMonster(HitActor).FlipOver();
				}

			}
			else
			{
				HitActor.TakeDamage(MyDamage, Instigator, HitLocation, vector(PointRot), hitDamageClass) ;
				if( KFWeaponAttachment(Weapon.ThirdPersonActor)!=None )
                    KFWeaponAttachment(Weapon.ThirdPersonActor).UpdateHit(HitActor,HitLocation,HitNormal);
			}
		}
	}

}

function Timer()
{
    PlayDefaultAmbientSound();
}

/* =================================================================================== *
* FireLoop
* 	This state handles looping the firing animations and ambient fire sounds as well
*	as firing rounds.
*
* modified by: Ramm 1/17/05
* =================================================================================== */
state FireLoop
{
    function BeginState()
    {
		NextFireTime = Level.TimeSeconds - 0.1; //fire now!

        Weapon.LoopAnim(FireLoopAnim, FireLoopAnimRate, TweenTime);
        Weapon.PlayOwnedSound(FireStartSound,SLOT_Interact,AmbientFireVolume/127,,AmbientFireSoundRadius,,false);

        SetTimer(Weapon.GetSoundDuration(FireStartSound) / (1.1/Weapon.Level.TimeDilation), False);
    }

    function Timer()
    {
        PlayAmbientSound(AmbientFireSound);
    }

	// Overriden because we play an anbient fire sound
    function PlayFiring() {}
	function ServerPlayFiring() {}

    function EndState()
    {
        Weapon.AnimStopLooping();
        PlayAmbientSound(none);
        Weapon.PlayOwnedSound(FireEndSound,SLOT_Interact,AmbientFireVolume/127,,AmbientFireSoundRadius,,false);
        SetTimer(Weapon.GetSoundDuration(FireEndSound) / (1.1/Weapon.Level.TimeDilation), False);
        Weapon.StopFire(ThisModeNum);
    }

    function StopFiring()
    {
        GotoState('');
    }

    function ModeTick(float dt)
    {
	    Super.ModeTick(dt);

		if ( !bIsFiring ||  !AllowFire()  )  // stopped firing, magazine empty
        {
			GotoState('');
			return;
		}
    }
}

function float MaxRange()
{
    return weaponRange;
}

defaultproperties
{
     hitDamageClass=Class'KFMod.DamTypeChainsaw'
     TransientSoundVolume=2.000000
     FireSound=none
     FireRate=0.100000
     MeleeHitSoundRefs(0)="KF_AxeSnd.Axe_HitFlesh"

     FireStartSoundRef="KF_ChainsawSnd.Chainsaw_RevLong_Start"
     FireEndSoundRef="KF_ChainsawSnd.Chainsaw_RevLong_End"
     NoAmmoSoundRef="KF_FlamethrowerSnd.FT_DryFire"
     AmbientFireSoundRadius=500
     AmbientFireSoundRef="KF_ChainsawSnd.Chainsaw_RevLong_Loop"
     AmbientFireVolume=255
     FireLoopAnim=Fire
     FireEndAnim=Idle
     FireAnim=''
     HitEffectClass=class'ChainsawHitEffect'

     MeleeDamage=14 // Increased in Balance Round 2
     MaxAdditionalDamage=5
}
