//
// 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
{   
    TurokPistol(kWeapon @actor)
    {
        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        self.FireProjectile("fx/bullet_shell.kfx", 10.24f, 27.64f, -10.24f, true);
        self.FireProjectile("fx/weffect_pistol.kfx", 6.656f-0.5f, 29.69f, -3.58f-0.5f, true);
        self.FireProjectile("fx/bullet.kfx", 13.107f, 25.6f, -10.24f);
            
        self.PlaySound("sounds/shaders/pistol_shot.ksnd");
        self.AnimState().Set(anim_weaponFire, 4.0f, 0);
        
        self.RunFxEvent("GunFire");
        
        self.Owner().Actor().LoudNoiseAlert();
        self.Owner().Actor().RecoilPitch() = -0.02094395086169243f;
        self.Owner().ConsumeAmmo(1);
    }
}

//-----------------------------------------------------------------------------
//
// 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_riotshotgun.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/shotgun.kfx", 12.28f, 25.6f, -7.168f);
        }
        
        self.PlaySound("sounds/shaders/riot_shotgun_shot.ksnd");
        self.RunFxEvent("GunFire");
        self.AnimState().Set(anim_weaponFire, 4.0f, 0);
        
        bShotgunReload = true;
        bEjectShotgunShell = true;
        
        self.Owner().Actor().LoudNoiseAlert();
        self.Owner().Actor().RecoilPitch() = -0.03926990926265717f;
        self.Owner().ConsumeAmmo(1);
    }
    
    /*
    ==============================================================
    OnFire
    ==============================================================
    */
    
    void OnFire(void)
    {
        if(bShotgunReload && self.AnimState().PlayTime() >= 0.5f)
        {
            self.PlaySound("sounds/shaders/ready_shotgun.ksnd");
            bShotgunReload = false;
        }
        
        if(bEjectShotgunShell && self.AnimState().PlayTime() >= 0.6f)
        {
            if(bFiredExpslosiveShells)
            {
                self.FireProjectile("fx/shotgun_shell_explosive.kfx", 11.26f, 27.648f, -8.192f, true);
            }
            else
            {
                self.FireProjectile("fx/shotgun_shell.kfx", 11.26f, 27.648f, -8.192f, true);
            }
            
            bFiredExpslosiveShells = false;
            bEjectShotgunShell = false;
        }
    }
}

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

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

final class TurokAutoShotgun : TurokWeapon
{   
    bool bShotgunReload;
    bool bEjectShotgunShell;
    bool bFiredExpslosiveShells;
    bool bCycleBarrel;
    float spinBarrelAngle;

    TurokAutoShotgun(kWeapon @actor)
    {
        bShotgunReload = false;
        bEjectShotgunShell = false;
        bFiredExpslosiveShells = false;
        bCycleBarrel = false;
        spinBarrelAngle = 0;

        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        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);
        
        bShotgunReload = true;
        bCycleBarrel = true;
        spinBarrelAngle = Math::Deg2Rad(36.0f);
        
        self.Owner().Actor().LoudNoiseAlert();
        self.Owner().Actor().RecoilPitch() = -0.02617993950843811f;
        self.Owner().ConsumeAmmo(1);
    }
    
    /*
    ==============================================================
    OnFire
    ==============================================================
    */
    
    void OnFire(void)
    {
        if(bShotgunReload && self.AnimState().PlayTime() >= 0.0125f)
        {
            self.PlaySound("sounds/shaders/reload_auto_shotgun.ksnd");
            bShotgunReload = false;
        }
    }
    
    /*
    ==============================================================
    OnTick
    ==============================================================
    */
    
    void OnTick(void)
    {
        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
{   
    //int rifleShotsFired;

    TurokRifle(kWeapon @actor)
    {
        //rifleShotsFired = 0;
        super(actor);
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        self.AnimState().Set(anim_weaponFire, 2.5f, 0);
        self.PlaySound("sounds/shaders/rifle_shot.ksnd");
        self.FireProjectile("fx/bullet_shell.kfx", 11.26f, 27.64f, -8.192f, true);
        self.FireProjectile("fx/weffect_assaultrifle.kfx", 5.12f+0.35f, 29.69f, -3.584f-0.5f);
        self.FireProjectile("fx/bullet.kfx", 10.24f, 25.6f, -10.24f);
        self.RunFxEvent("GunFire");
        self.Owner().Actor().LoudNoiseAlert();
        self.Owner().Actor().RecoilPitch() = -0.02416609786450863f;
        self.Owner().ConsumeAmmo(1);
        //rifleShotsFired++;	
		//rifleShotsFired = 0;				
    }
}

//-----------------------------------------------------------------------------
//
// 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;
        }
    }
}
