//
// Copyright(C) 2014-2015 Samuel Villarreal
//
// 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.
//
// DESCRIPTION:
//      Weapon Actions
//

#include "scripts/animations.txt"

/*
==============================================================
TurokWeapon
==============================================================
*/

class TurokWeapon : ScriptObjectWeapon
{
    kWeapon @self;
    
    TurokWeapon(kWeapon @actor)
    {
        @self = actor;
    }
    
    ~TurokWeapon()
    {
    }
    
    /*
    ==============================================================
    OnTick
    ==============================================================
    */
    
    void OnTick(void)
    {
    }
    
    /*
    ==============================================================
    OnSpawn
    ==============================================================
    */
    
    void OnSpawn(void)
    {
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
    }
    
    /*
    ==============================================================
    OnFire
    ==============================================================
    */
    
    void OnFire(void)
    {
    }
    
    /*
    ==============================================================
    OnEndFire
    ==============================================================
    */
    
    void OnEndFire(void)
    {
    }
    
    /*
    ==============================================================
    OnLower
    ==============================================================
    */
    
    void OnLower(void)
    {
    }
    
    /*
    ==============================================================
    OnRaise
    ==============================================================
    */
    
    void OnRaise(void)
    {
    }
    
    /*
    ==============================================================
    OnHoldster
    ==============================================================
    */
    
    void OnHoldster(void)
    {
    }
}

//-----------------------------------------------------------------------------
//
// Knife
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokKnife
==============================================================
*/

final class TurokKnife : TurokWeapon
{   
    TurokKnife(kWeapon @actor)
    {
        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        kPuppet @src = self.Owner().Actor();
    
        if(src.InWater())
        {
            self.AnimState().Blend(anim_weaponAttackUnderwater, 4.0f, 4.0f, 0);
            self.PlaySound("sounds/shaders/underwater_swim_2.ksnd");
            return;
        }
        
        int rnd = Math::RandMax(100);
        
        if(rnd <= 32)
        {
            self.AnimState().Blend(anim_weaponAttack1, 4.0f, 4.0f, 0);
            self.PlaySound("sounds/shaders/knife_swish_2.ksnd");
        }
        else if(rnd <= 64)
        {
            self.AnimState().Blend(anim_weaponAttack2, 4.0f, 4.0f, 0);
            self.PlaySound("sounds/shaders/knife_swish_1.ksnd");
        }
        else
        {
            self.AnimState().Blend(anim_weaponAttack3, 4.0f, 4.0f, 0);
            self.PlaySound("sounds/shaders/knife_swish_3.ksnd");
        }
    }
    
    /*
    ==============================================================
    KnifeAttack1
    ==============================================================
    */
    
    void KnifeAttack1(kActor @instigator, const float w, const float x, const float y, const float z)
    {
        kPuppet @src = self.Owner().Actor();
        
        TurokPlayer @p = cast<TurokPlayer@>(src.ScriptObject().obj);
        p.m_vBloodVector = kVec3(0, (w * GAME_SCALE), 0);
        p.m_vBloodVector.z += (GAME_SCALE * 3);
        
        p.m_vStabVector = (kVec3(0, (w * GAME_SCALE), 0) * src.Rotation());
        p.m_vStabVector += src.Origin();
        p.m_vStabVector.z += (GAME_SCALE * 3);
        
        src.InteractActorsAtPosition(p.m_vStabVector, "KnifeAttack", 0, w);
    }
    
    /*
    ==============================================================
    KnifeAttack2
    ==============================================================
    */
    
    void KnifeAttack2(kActor @instigator, const float w, const float x, const float y, const float z)
    {
        kPuppet @src = self.Owner().Actor();
        
        TurokPlayer @p = cast<TurokPlayer@>(src.ScriptObject().obj);
        p.m_vBloodVector = kVec3(0, (w * GAME_SCALE), 0);
        p.m_vBloodVector.z += (GAME_SCALE * 3);
        
        p.m_vStabVector = (kVec3(0, (w * GAME_SCALE), 0) * src.Rotation());
        p.m_vStabVector += src.Origin();
        p.m_vStabVector.z += (GAME_SCALE * 3);
        
        src.InteractActorsAtPosition(p.m_vStabVector, "KnifeAttack", 1, w);
    }
    
    /*
    ==============================================================
    KnifeAttack3
    ==============================================================
    */
    
    void KnifeAttack3(kActor @instigator, const float w, const float x, const float y, const float z)
    {
        kPuppet @src = self.Owner().Actor();
        
        TurokPlayer @p = cast<TurokPlayer@>(src.ScriptObject().obj);
        p.m_vBloodVector = kVec3(0, (w * GAME_SCALE), 0);
        p.m_vBloodVector.z += (GAME_SCALE * 3);
        
        p.m_vStabVector = (kVec3(0, (w * GAME_SCALE), 0) * src.Rotation());
        p.m_vStabVector += src.Origin();
        p.m_vStabVector.z += (GAME_SCALE * 3);
        
        src.InteractActorsAtPosition(p.m_vStabVector, "KnifeAttack", 2, w);
    }
}

//-----------------------------------------------------------------------------
//
// Tek Bow
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokBow
==============================================================
*/

final class TurokBow : TurokWeapon
{   
    bool m_bArrowFlashed;
    
    TurokBow(kWeapon @actor)
    {
        super(actor);
        m_bArrowFlashed = false;
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        self.PlaySound("sounds/shaders/bow_stretch.ksnd");
        self.AnimState().Blend(anim_weaponFire, 4.0f, 20.0f, ANF_LOOP);
        m_bArrowFlashed = false;
    }
    
    /*
    ==============================================================
    OnFire
    ==============================================================
    */
    
    void OnFire(void)
    {
        float time = self.AnimState().PlayTime();
        
        // firing super arrow?
        if(time >= 1.4f && time <= 2.15f)
        {
            if(!m_bArrowFlashed)
            {
                m_bArrowFlashed = true;
                
                // turok has enabled the super arrow, add special flash to arrow to indicate this
                self.FireProjectile(
                    "fx/super_arrow_flash.kfx",
                    0.07f*GAME_SCALE,
                     2.9f*GAME_SCALE,
                    -0.6f*GAME_SCALE,
                    true);
            }
        }
    }
    
    /*
    ==============================================================
    OnEndFire
    ==============================================================
    */
    
    void OnEndFire(void)
    {
        float time = self.AnimState().PlayTime();
        kPuppet @src = self.Owner().Actor();
        kVec3 origin = src.Origin();
        kQuat rotation = src.Rotation();
        kVec3 velocity;
        
        origin.z += (5*GAME_SCALE);
        origin += (kVec3(0.07f*GAME_SCALE, 2.9f*GAME_SCALE, -0.6f*GAME_SCALE) * rotation);
        
        m_bArrowFlashed = false;
        
        // fired super arrow?
        if(time >= 1.4f && time <= 2.15f)
        {
            velocity = kVec3(0, 512 * 15, 0) * rotation;
        }
        else
        {
            if(time > 0.7f)
            {
                time = 0.7f;
            }
            
            velocity = kVec3(0, (512 * time / 1.4f) * 15, 0) * rotation;
        }
        
        velocity *= GAME_DELTA_TIME;
        
        if(self.Owner().HasAltAmmo())
        {
            Game.SpawnFx("fx/arrow_explosive.kfx", src, velocity, origin, rotation);
            self.PlaySound("sounds/shaders/arrow_fly_tek.ksnd");
        }
        else
        {
            Game.SpawnFx("fx/arrow.kfx", src, velocity, origin, rotation);
            self.PlaySound("sounds/shaders/arrow_fly_normal.ksnd");
        }
        
        self.PlaySound("sounds/shaders/bow_twang.ksnd");
        self.AnimState().Set(anim_weaponFireCharged, 4.0f, ANF_NOINTERRUPT);
        
        self.Owner().ConsumeAmmo(1);
    }
}

//-----------------------------------------------------------------------------
//
// Pistol
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokPistol
==============================================================
*/

final class TurokPistol : TurokWeapon
{   
	bool just_fired = false;
    TurokPistol(kWeapon @actor)
    {
        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
		if (just_fired)
			{
				return;
			}
		else
			{			
			int rnd = Math::RandMax(100); //used for randomizeed firing animations
				
			if(rnd <= 32)
				{
					 self.AnimState().Set(5005, 4.0f, 0); //2nd Fire Anim
				}			
			else if(rnd <= 64)
				{
					self.AnimState().Set(5006, 4.0f, 0); // 3rd Fire Anim
				}
			else			
				{
					self.AnimState().Set(anim_weaponFire, 4.0f, 0);
				}
					{
						just_fired = true;
						self.FireProjectile("fx/bullet_shell_deagle.kfx", 10.24f, 27.64f, -10.24f, true);
						self.FireProjectile("fx/weffect_deagle.kfx", 6.656f-0.5f, 29.69f, -3.58f-0.5f, true);
						self.FireProjectile("fx/deagle_bullet.kfx", 13.107f, 25.6f, -10.24f);
						self.PlaySound("sounds/shaders/deagle_shot.ksnd");
						self.RunFxEvent("GunFire");
						self.Owner().Actor().LoudNoiseAlert();
						self.Owner().Actor().RecoilPitch() = -0.175;
						self.Owner().ConsumeAmmo(1);
					}
		}
	}
	void OnTick(void)
	{
		if((self.Owner().Buttons() & (BC_ATTACK)) == 0)
			{ 
				just_fired = false;
			}
	        //self.RenderModel().HideSection(3, 1, true);		
	}
	
	void OnHoldster(void)
		{just_fired = false;}

	void OnRaise(void)
		{just_fired = false;}	
}

//-----------------------------------------------------------------------------
//
// Shotgun
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokShotgun
==============================================================
*/

final class TurokShotgun : TurokWeapon
{   
    bool bShotgunReload;
    bool bEjectShotgunShell;
    bool bFiredExpslosiveShells;

    TurokShotgun(kWeapon @actor)
    {
        bShotgunReload = false;
        bEjectShotgunShell = false;
        bFiredExpslosiveShells = false;

        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        bFiredExpslosiveShells = Player.HasAltAmmo();
    
        self.FireProjectile("fx/weffect_newshotgun.kfx", 6.656f-1.0f, 29.69f, -2.7648f+0.85f);
        
        if(bFiredExpslosiveShells)
        {
            self.FireProjectile("fx/shotgun_explosive.kfx", 12.28f, 25.6f, -7.168f);
        }
        else
        {
            self.FireProjectile("fx/combat_shotgun.kfx", 12.28f, 25.6f, -7.168f);
        }
        		
        self.PlaySound("sounds/shaders/combat_shotgun_shot.ksnd");
        self.RunFxEvent("GunFire");
		
        int rnd = Math::RandMax(100); //used for randomizeed firing animations
        
        if(rnd <= 32)
        {
		        self.AnimState().Set(5005, 4.0f, 0); //2nd Fire Anim
		}			
		else if(rnd <= 64)
		{
				self.AnimState().Set(5006, 4.0f, 0); // 3rd Fire Anim
		}
		else
		{
		        self.AnimState().Set(anim_weaponFire, 4.0f, 0);
		}
        
        bShotgunReload = true;
        bEjectShotgunShell = true;
        
        self.Owner().Actor().LoudNoiseAlert();
        self.Owner().Actor().RecoilPitch() = -0.105;
        self.Owner().ConsumeAmmo(1);
    }
    
    /*
    ==============================================================
    OnFire
    ==============================================================
    */
    
    void OnFire(void)
    {
        if(bShotgunReload && self.AnimState().PlayTime() >= 0.6f)
        {
            self.PlaySound("sounds/shaders/ready_combat_shotgun.ksnd");
            bShotgunReload = false;
        }
        
        if(bEjectShotgunShell && self.AnimState().PlayTime() >= 0.6f)
        {
            if(bFiredExpslosiveShells)
            {
                self.FireProjectile("fx/combat_shotgun_shell_explosive.kfx", 11.26f, 27.648f, -8.192f, true);
            }
            else
            {
                self.FireProjectile("fx/combat_shotgun_shell.kfx", 11.26f, 27.648f, -8.192f, true);
            }
            
            bFiredExpslosiveShells = false;
            bEjectShotgunShell = false;
        }
    }
    void OnTick(void) //DoomMarine23 swap out Shell texture depending on alternative ammo or not.
    {
	
        if(self.Owner().HasAltAmmo())
		{
		self.RenderModel().SetTexture(0,1);
		}
	else
		{
			self.RenderModel().SetTexture(0,0);
		}
    }		
	
}

//-----------------------------------------------------------------------------
//
// Auto Shotgun
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokAutoShotgun
==============================================================
*/

final class TurokAutoShotgun : TurokWeapon
{   
    float   delayTime;
    bool bShotgunReload;
    bool bEjectShotgunShell;
    bool bFiredExpslosiveShells;
    bool bCycleBarrel;
    float spinBarrelAngle;
	int magazine = 4;

    TurokAutoShotgun(kWeapon @actor)
    {
        bShotgunReload = false;
        bEjectShotgunShell = false;
        bFiredExpslosiveShells = false;
        bCycleBarrel = false;
        spinBarrelAngle = 0;
		delayTime = 200.0f;
        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        if(magazine <= 0)  //Reload    
        {            
            self.AnimState().Set( 5005, 4.0f, ANF_LOOP );
            Reload();
        }
        else
        {
            self.FireProjectile("fx/weffect_riotshotgun.kfx", 6.656f-0.5f, 29.69f, -1.9456f-0.75f);
        
            if(self.Owner().HasAltAmmo())
            {
                self.FireProjectile("fx/shotgun_explosive.kfx", 12.28f, 25.6f, -7.168f);
                self.FireProjectile("fx/shotgun_shell_explosive.kfx", 14.336f, 27.648f, -12.288f, true);
            }
            else
            {
                self.FireProjectile("fx/shotgun.kfx", 12.28f, 25.6f, -7.168f);
                self.FireProjectile("fx/shotgun_shell.kfx", 14.336f, 27.648f, -12.288f, true);
            }
            self.PlaySound("sounds/shaders/riot_shotgun_shot.ksnd");
            self.RunFxEvent("GunFire");
            self.AnimState().Set(anim_weaponFire, 4.0f, 0);
          //  spinBarrelAngle = Math::Deg2Rad(36.0f);
            self.Owner().Actor().LoudNoiseAlert();
            self.Owner().Actor().RecoilPitch() = -0.02617993950843811f;
            self.Owner().ConsumeAmmo(1);
            magazine --;
		//        bShotgunReload = true;
        //bCycleBarrel = true;     	
        }
    }
    
void Reload(void)
    {
      //  spinBarrelAngle = Math::Deg2Rad(36.0f);
        bShotgunReload = true;
        bCycleBarrel = true;                
        self.PlaySound("sounds/shaders/reload_riot_shotgun.ksnd"); 
    }
    /*
    ==============================================================
    OnFire
    ==============================================================
    */
    
    void OnFire(void)
    {
        if(bShotgunReload && self.AnimState().PlayTime() >= 0.0125f)
        {
            self.PlaySound("sounds/shaders/auto_shotgun_cylinder.ksnd");
            bShotgunReload = false;
        }
    }
    
    /*
    ==============================================================
    OnTick
    ==============================================================
    */
    
    void OnTick(void)
    {
        // end of a cocking cycle
        if ( self.AnimState().IsPlaying(5005) && self.AnimState().flags & ANF_CYCLECOMPLETED != 0 )
        {
            // magazine is full, stop cocking
            if ( ++magazine >= 4 )
                self.AnimState().Stop();
            else
            {
                Reload();
                self.AnimState().flags &= ~ANF_CYCLECOMPLETED;
            }
        }

        if(bCycleBarrel)
        {
            if(spinBarrelAngle > 0)
            {
                spinBarrelAngle -= (0.1f*GAME_FRAME_TIME);
            }
            else
            {
                spinBarrelAngle = 0;
                bCycleBarrel = true;
            }
            
            self.RenderModel().SetRotationOffset(1, spinBarrelAngle, 1, 0, 0);
        }
    }
}

//-----------------------------------------------------------------------------
//
// Assault Rifle
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokRifle
==============================================================
*/

final class TurokRifle : TurokWeapon
{   
      /*  kVec3 gun_pos, offset;
		kVec3 new_position, offset;

		
	    gun_pos.x = self.Origin().x;
        gun_pos.y = self.Origin().y;
        gun_pos.z = self.Origin().z;
		
		new_position.x = gun_pos.x + 2;
        new_position.y = gun_pos.y + 2;
        new_position.z = gun_pos.z + 2;*/
			bool begin_tail = false;	

    TurokRifle(kWeapon @actor)
    {
        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        int rnd = Math::RandMax(100); //used for randomizeed firing animations
        
        if(rnd <= 16)
        {
		        self.AnimState().Set(5005, 1.65f, 0); //2nd Fire Anim
				self.Owner().Actor().RecoilPitch() = -0.020;
		}			
		else if(rnd <= 32)
		{
				self.AnimState().Set(5006, 1.65f, 0); // 3rd Fire Anim
				self.Owner().Actor().RecoilPitch() = -0.040;
		}
		else if(rnd <= 64)
		{
				self.AnimState().Set(5007, 1.65f, 0); // 4rd Fire Anim
				self.Owner().Actor().RecoilPitch() = -0.034;
		}
		else if (rnd <= 80)
		{
						self.AnimState().Set(5008, 1.65f, 0); // 5th Fire Anim
				self.Owner().Actor().RecoilPitch() = -0.030;
		}
		else
		{
		        self.AnimState().Set(anim_weaponFire, 1.65f, 0);
				self.Owner().Actor().RecoilPitch() = -0.028;
		}
		        self.PlaySound("sounds/shaders/sub_machine_rifle_shot.ksnd");
                self.FireProjectile("fx/bullet_shell_rifle.kfx", 11.26f, 27.64f, -8.192f, true);
                self.FireProjectile("fx/weffect_assaultrifle.kfx", 5.12f+0.35f, 39.69f, -3.584f-0.5f);
                self.FireProjectile("fx/rifle_bullet.kfx", 10.24f, 25.6f, -10.24f);
                self.RunFxEvent("GunFire");
                self.Owner().Actor().LoudNoiseAlert();
                self.Owner().ConsumeAmmo(1);
				//self.RenderModel().Offset()(new_position);
    }  
/*	void OnEndFire(void)
	{
			self.PlaySound("sounds/shaders/sub_machine_rifle_shot_tail.ksnd");
	begin_tail = true;
	}*/
/*	void OnTick(void)
	{
		if (begin_tail)
				self.StopLoopingSounds();
		self.PlaySound("sounds/shaders/sub_machine_rifle_shot_tail.ksnd");
		begin_tail = false;
	}*/
    
}

//-----------------------------------------------------------------------------
//
// Pulse Rifle
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokPulseRifle
==============================================================
*/

final class TurokPulseRifle : TurokWeapon
{   
    float pulseRifleFireTime;
    
    TurokPulseRifle(kWeapon @actor)
    {
        pulseRifleFireTime = 0;
        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        self.AnimState().Blend(anim_weaponFireLoop, 4.0f, 4.0f, ANF_LOOP);
        pulseRifleFireTime = -0.08f;
    }
    
    /*
    ==============================================================
    OnFire
    ==============================================================
    */
    
    void OnFire(void)
    {
        float playTime = self.AnimState().PlayTime();
    
        if((playTime - pulseRifleFireTime) >= 0.16f)
        {
            self.PlaySound("sounds/shaders/machine_gun_shot_2.ksnd");
            self.FireProjectile("fx/longhunter_gun_pulse.kfx", 10.24f, -40.96f, -9.216f);
            self.Owner().Actor().LoudNoiseAlert();
            self.Owner().Actor().RecoilPitch() = -0.01963495463132858f;
            self.Owner().ConsumeAmmo(1);
            
            pulseRifleFireTime = playTime;
        }
    }
    
    /*
    ==============================================================
    OnEndFire
    ==============================================================
    */
    
    void OnEndFire(void)
    {
        self.AnimState().Blend(anim_weaponIdle, 4.0f, 4.0f, ANF_LOOP);
        pulseRifleFireTime = 0;
    }
}

//-----------------------------------------------------------------------------
//
// Minigun
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokMinigun
==============================================================
*/

final class TurokMinigun : TurokWeapon
{   
    bool bCycleMiniBarrel;
    bool bMiniGunRampUp;
    float miniGunFireTime;
    float miniGunCycleSpeed;
    float miniGunBarrelAngle;
    
    TurokMinigun(kWeapon @actor)
    {
        bCycleMiniBarrel = false;
        bMiniGunRampUp = false;
        miniGunFireTime = 0;
        miniGunCycleSpeed = 0;
        miniGunBarrelAngle = 0;
        
        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        self.PlaySound("sounds/shaders/mini_gun_whir.ksnd");
        self.AnimState().Blend(anim_weaponFireLoop, 4.0f, 4.0f, ANF_LOOP);

        bCycleMiniBarrel = true;
        bMiniGunRampUp = true;
        miniGunFireTime = 0;
    }
    
    /*
    ==============================================================
    OnFire
    ==============================================================
    */
    
    void OnFire(void)
    {
        float playTime = self.AnimState().PlayTime();
    
        if((playTime - miniGunFireTime) >= 0.11f)
        {
            self.FireProjectile("fx/weffect_minigun.kfx", 4.608f, 25.696f, -3.1744f);
            self.FireProjectile("fx/minigun_bullet.kfx", 8.192f, 25.6f, -10.24f);
            self.FireProjectile("fx/minigun_bullet.kfx", 8.192f, 25.6f, -10.24f);
            self.FireProjectile("fx/bullet_shell.kfx", 11.26f, 27.648f, -8.192f, true);
            
            self.Owner().ConsumeAmmo(4);
            
            self.PlaySound("sounds/shaders/mini_gun_shot.ksnd");
            self.Owner().Actor().LoudNoiseAlert();
            self.Owner().Actor().RecoilPitch() = -0.02094395086169243f;
            
            miniGunFireTime = playTime;
        }
    }
    
    /*
    ==============================================================
    OnEndFire
    ==============================================================
    */
    
    void OnEndFire(void)
    {
        self.PlaySound("sounds/shaders/minigun_stop.ksnd");
        self.StopLoopingSounds();
        self.AnimState().Blend(anim_weaponIdle, 4.0f, 4.0f, ANF_LOOP);
        
        miniGunFireTime = 0;
        bMiniGunRampUp = false;
    }
    
    /*
    ==============================================================
    OnTick
    ==============================================================
    */
    
    void OnTick(void)
    {
        if(bCycleMiniBarrel)
        {
            float time = (0.05f * GAME_FRAME_TIME);
            
            if(bMiniGunRampUp)
            {
                miniGunCycleSpeed = (40.0f - miniGunCycleSpeed) * time + miniGunCycleSpeed;
            }
            else
            {
                miniGunCycleSpeed = (0 - miniGunCycleSpeed) * time + miniGunCycleSpeed;
            }
            
            if(miniGunCycleSpeed < 0.01f)
            {
                miniGunCycleSpeed = 0;
                bCycleMiniBarrel = false;
            }
            
            miniGunBarrelAngle += miniGunCycleSpeed * (1.0f / 60.0f);
            self.RenderModel().SetRotationOffset(1, miniGunBarrelAngle, 0, 1, 0);
        }
    }
    
    /*
    ==============================================================
    OnLower
    ==============================================================
    */
    
    void OnLower(void)
    {
        miniGunCycleSpeed = 0;
        bCycleMiniBarrel = false;
        self.RenderModel().SetRotationOffset(1, 0, 0, 1, 0);
    }
    
    /*
    ==============================================================
    OnHoldster
    ==============================================================
    */
    
    void OnHoldster(void)
    {
        bool bWasRampedUp = bMiniGunRampUp;
        
        miniGunCycleSpeed = 0;
        bCycleMiniBarrel = false;
        bMiniGunRampUp = false;
        self.RenderModel().SetRotationOffset(1, 0, 0, 1, 0);
        self.StopLoopingSounds();
        
        if(bWasRampedUp == true) // 20170909: only if actually spinning.
        {
            self.PlaySound("sounds/shaders/minigun_stop.ksnd");
        }
    }
}

//-----------------------------------------------------------------------------
//
// Grenade Launcher
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokGrenadeLauncher
==============================================================
*/

final class TurokGrenadeLauncher : TurokWeapon
{   
    TurokGrenadeLauncher(kWeapon @actor)
    {
        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        self.AnimState().Set(anim_weaponFire, 4.0f, 0);
        self.PlaySound("sounds/shaders/grenade_launch.ksnd");
        
        self.FireProjectile("fx/grenade.kfx", 18.432f, 25.696f, -5.12f);
        self.FireProjectile("fx/weffect_grenadelauncher.kfx", 10.3424f, 25.696f, -0.512f);
        
        self.Owner().Actor().LoudNoiseAlert();
        self.Owner().Actor().RecoilPitch() = -0.03490658476948738f;
        self.Owner().ConsumeAmmo(1);
    }
}

//-----------------------------------------------------------------------------
//
// Alien Rifle
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokAlienRifle
==============================================================
*/

final class TurokAlienRifle : TurokWeapon
{   
    TurokAlienRifle(kWeapon @actor)
    {
        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        self.AnimState().Set(anim_weaponFire, 4.0f, 0);
        self.PlaySound("sounds/shaders/tek_weapon_1.ksnd");
        
        self.FireProjectile("fx/plasma1.kfx", 4.096f, 25.696f, -14.336f);
        self.Owner().ConsumeAmmo(5);
    }
}

//-----------------------------------------------------------------------------
//
// Rocket Launcher
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokRocketLauncher
==============================================================
*/

final class TurokRocketLauncher : TurokWeapon
{   
    TurokRocketLauncher(kWeapon @actor)
    {
        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        self.AnimState().Set(anim_weaponFire, 4.0f, 0);
        self.PlaySound("sounds/shaders/missile_launch.ksnd");
        self.PlaySound("sounds/shaders/reload_missile_launcher.ksnd");
        
        self.FireProjectile("fx/rocket.kfx", 4.096f, 25.696f, -14.336f);
        
        self.Owner().Actor().LoudNoiseAlert();
        self.Owner().ConsumeAmmo(1);
    }
}


//-----------------------------------------------------------------------------
//
// Particle Accelerator
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokAccelerator
==============================================================
*/

final class TurokAccelerator : TurokWeapon
{   
    float acceleratorCycleSpeed;
    float acceleratorSpinAngle;
    int chargeStep;
    
    TurokAccelerator(kWeapon @actor)
    {
        acceleratorCycleSpeed = 2.0f;
        acceleratorSpinAngle = 0;
        chargeStep = 0;
        
        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        self.AnimState().Blend(anim_weaponFire, 4.0f, 40.0f, ANF_LOOP);
        chargeStep = 0;
    }
    
    /*
    ==============================================================
    OnEndFire
    ==============================================================
    */
    
    void OnEndFire(void)
    {
        float t = self.AnimState().PlayTime();
    
        if(t >= 4.0f)
        {
            self.PlaySound("sounds/shaders/generic_194.ksnd");
            self.FireProjectile("fx/shockwave_pulse_5_strongest.kfx", 4.096f, 25.696f, -14.336f);
            self.Owner().ConsumeAmmo(10);
        }
        else if(t >= 3.0f)
        {
            self.PlaySound("sounds/shaders/generic_193.ksnd");
            self.FireProjectile("fx/shockwave_pulse_4.kfx", 4.096f, 25.696f, -14.336f);
            self.Owner().ConsumeAmmo(8);
        }
        else if(t >= 2.0f)
        {
            self.PlaySound("sounds/shaders/generic_192.ksnd");
            self.FireProjectile("fx/shockwave_pulse_3.kfx", 4.096f, 25.696f, -14.336f);
            self.Owner().ConsumeAmmo(6);
        }
        else if(t >= 1.0f)
        {
            self.PlaySound("sounds/shaders/generic_191.ksnd");
            self.FireProjectile("fx/shockwave_pulse_2.kfx", 4.096f, 25.696f, -14.336f);
            self.Owner().ConsumeAmmo(4);
        }
        else
        {
            self.PlaySound("sounds/shaders/generic_190.ksnd");
            self.FireProjectile("fx/shockwave_pulse_1_weakest.kfx", 4.096f, 25.696f, -14.336f);
            self.Owner().ConsumeAmmo(2);
        }
        
        chargeStep = 0;
        
        self.StopLoopingSounds();
        self.Owner().Actor().LoudNoiseAlert();
        self.AnimState().Blend(anim_weaponFireCharged, 4.0f, 4.0f, ANF_NOINTERRUPT);
    }
    
    /*
    ==============================================================
    OnTick
    ==============================================================
    */
    
    void OnTick(void)
    {
        if(self.AnimState().PlayingID() == anim_weaponFire)
        {
            switch(chargeStep)
            {
            case 0:
                if(self.AnimState().PlayTime() >= 0.0f)
                {
                    self.PlaySound("sounds/shaders/generic_160.ksnd");
                    chargeStep++;
                }
                break;
            case 1:
                if(self.AnimState().PlayTime() >= 1.0f)
                {
                    self.PlaySound("sounds/shaders/generic_161.ksnd");
                    chargeStep++;
                }
                break;
            case 2:
                if(self.AnimState().PlayTime() >= 2.0f)
                {
                    self.PlaySound("sounds/shaders/generic_162.ksnd");
                    chargeStep++;
                }
                break;
            case 3:
                if(self.AnimState().PlayTime() >= 3.0f)
                {
                    self.PlaySound("sounds/shaders/generic_163.ksnd");
                    chargeStep++;
                }
                break;
            case 4:
                if(self.AnimState().PlayTime() >= 4.0f)
                {
                    self.PlaySound("sounds/shaders/generic_164.ksnd");
                    chargeStep++;
                }
                break;
            }
        }
        
        switch(self.AnimState().PlayingID())
        {
        case anim_weaponSwapOut:
            acceleratorCycleSpeed = 2;
            self.RenderModel().SetRotationOffset(1, 0, 0, 1, 0);
            break;
            
        case anim_weaponIdle:
        case anim_weaponWalk:
        case anim_weaponRun:
        case anim_weaponFireCharged:
            acceleratorCycleSpeed = (2 - acceleratorCycleSpeed) * 0.025f + acceleratorCycleSpeed;
            acceleratorSpinAngle += acceleratorCycleSpeed * (1.0f / 120.0f);
            self.RenderModel().SetRotationOffset(1, acceleratorSpinAngle, 0, 1, 0);
            break;
            
        case anim_weaponFire:
            acceleratorCycleSpeed = (20 - acceleratorCycleSpeed) * (0.01f*GAME_FRAME_TIME) + acceleratorCycleSpeed;
            acceleratorSpinAngle += acceleratorCycleSpeed * (1.0f / 120.0f);
            self.RenderModel().SetRotationOffset(1, acceleratorSpinAngle, 0, 1, 0);
            break;
        }
    }
    
    /*
    ==============================================================
    OnLower
    ==============================================================
    */
    
    void OnLower(void)
    {
        acceleratorCycleSpeed = 2;
        acceleratorSpinAngle = 0;
        self.RenderModel().SetRotationOffset(1, 0, 0, 1, 0);
    }
    
    /*
    ==============================================================
    OnHoldster
    ==============================================================
    */
    
    void OnHoldster(void)
    {
        acceleratorCycleSpeed = 2;
        acceleratorSpinAngle = 0;
        self.RenderModel().SetRotationOffset(1, 0, 0, 1, 0);
        self.StopSound();
    }
}

//-----------------------------------------------------------------------------
//
// Fusion Cannon
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokFusionCannon
==============================================================
*/

final class TurokFusionCannon : TurokWeapon
{   
    bool bFiredFusion;
    
    TurokFusionCannon(kWeapon @actor)
    {
        bFiredFusion = false;
        super(actor);
    }
    
    /*
    ==============================================================
    OnRaise
    ==============================================================
    */
    
    void OnRaise(void)
    {
        self.RenderModel().HideSection(3, 1, false);
    }
    
    /*
    ==============================================================
    OnLower
    ==============================================================
    */
    
    void OnLower(void)
    {
        self.RenderModel().HideSection(3, 1, true);
    }
    
    /*
    ==============================================================
    OnPostBeginLevel
    ==============================================================
    */
    
    void OnPostBeginLevel(void)
    {
        self.RenderModel().HideSection(3, 1, true);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        self.AnimState().Set(anim_weaponFire, 4.0f, 0);
        self.PlaySound("sounds/shaders/tek_weapon_2.ksnd");
        
        bFiredFusion = false;
    }
    
    /*
    ==============================================================
    OnTick
    ==============================================================
    */
    
    void OnTick(void)
    {
        int animID = self.AnimState().PlayingID();
        
        if(animID == anim_weaponFire)
        {
            if(!bFiredFusion && self.AnimState().PlayTime() >= 1.1333f)
            {
                bFiredFusion = true;
                
                if(Game.GetCurrentMapID() == 0)
                {
                    self.FireProjectile("fx/projectile_fusionshot_defect.kfx", 4.096f, 25.6f, -14.336f);
                }
                else
                {
                    self.FireProjectile("fx/plasma2.kfx", 4.096f, 25.6f, -14.336f);
                }
                
                self.Owner().Actor().LoudNoiseAlert();
                self.Owner().ConsumeAmmo(1);
            }
        }
        else if(animID == anim_weaponSwapOut)
        {
            if(self.AnimState().TrackTime() >= 0.3f)
            {
                self.RenderModel().HideSection(3, 1, true);
            }
        }
    }
}

//-----------------------------------------------------------------------------
//
// ChronoScepter
//
//-----------------------------------------------------------------------------

/*
==============================================================
TurokChrono
==============================================================
*/

final class TurokChrono : TurokWeapon
{   
    float chronoChargeTime;
    
    TurokChrono(kWeapon @actor)
    {
        chronoChargeTime = 0.0f;
        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        self.AnimState().Blend(anim_weaponFire, 4.0f, 60.0f, ANF_LOOP);
        chronoChargeTime = 0;
    }
    
    /*
    ==============================================================
    OnEndFire
    ==============================================================
    */
    
    void OnEndFire(void)
    {
        float t = self.AnimState().PlayTime() + chronoChargeTime;
    
        if(t >= 1.0f)
        {
            self.FireProjectile("fx/chronscepter.kfx", 4.096f, 25.6f, -14.336f);
            self.PlaySound("sounds/shaders/shockwave_weapon_fire.ksnd");
            self.AnimState().Blend(anim_weaponFireCharged, 4.0f, 4.0f, 0);
            
            self.Owner().Actor().LoudNoiseAlert();
            self.Owner().ConsumeAmmo(1);
            chronoChargeTime = 0;
        }
        else
        {
            self.AnimState().Blend(anim_weaponIdle, 4.0f, 8.0f, 0);
        }
    }
    
    /*
    ==============================================================
    OnTick
    ==============================================================
    */
    
    void OnTick(void)
    {
        switch(self.AnimState().PlayingID())
        {
        case anim_weaponFireCharged:
            if((self.AnimState().flags & ANF_STOPPED) != 0)
            {
                self.AnimState().Blend(anim_weaponIdle, 4.0f, 8.0f, 0);
            }
            break;
        }
    }
}
