#include "scripts/animations.txt"
#include "scripts/bp_common.txt"

//============================================================================================================================
class TurokWeapon : ScriptObjectWeapon {
    kWeapon @self;
    int weaponType;
    TurokWeapon(kWeapon @actor)
    {
        @self = actor;
		weaponType = 0;
    }
    
    ~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)
    {
    }
	//------------------------------------------------------------------------------------------------------------------------
    void OnHoldster(void) {
    }
	//------------------------------------------------------------------------------------------------------------------------
	bool CanAttack() {
		return CanUseWeapon(weaponType) and CanPlayerMove();
	}
	//------------------------------------------------------------------------------------------------------------------------
	void DoNoAttack() {
		self.AnimState().Blend(anim_weaponIdle, 4.0f, 4.0f, ANF_LOOP);
	}
	//------------------------------------------------------------------------------------------------------------------------
	void ConsumeAmmo(int amount) {
		self.Owner().ConsumeAmmo(amount);
	}
	//------------------------------------------------------------------------------------------------------------------------
}
//============================================================================================================================
final class TurokKnife : TurokWeapon {
    TurokKnife(kWeapon @actor) {
        super(actor);
		weaponType = TW_WEAPON_KNIFE;
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
        kPuppet @src = self.Owner().Actor();
    
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
		
		// 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);
		if (HasUpgradeKnife()) {
			self.FireProjectile("fx/knife_slash.kfx", 0.0f, 25.6f, 10.24f);
		}
            
        // self.PlaySound("sounds/shaders/pistol_shot.ksnd");
        //self.AnimState().Set(anim_weaponFire, 3.0f, 0);
        
        // self.RunFxEvent("GunFire");
        
        // self.Owner().Actor().LoudNoiseAlert();
        // self.Owner().Actor().RecoilPitch() = -0.02094395086169243f;
		
		// self.FireProjectile("fx/knife_slash.kfx", 4.096f, 25.6f, -14.336f);
		// self.FireProjectile("fx/generic_252.kfx", 2.5f, 20.0f, 7.0f);
		//src.SpawnProjectile("fx/eyefire.kfx", kVec3(0.0f, 0.0f, 0.0f), src.Origin(), src.Yaw());
		//src.SpawnProjectile("fx/spellcast.kfx", kVec3(0.0f, 0.0f, 0.0f), self.Origin(), Math::Deg2Rad(45.0f));// src.Yaw());
		
        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();
        
		float newWeight = w; //is distance/radius
		//newWeight *= 40.0f;
		
        TurokPlayer @p = cast<TurokPlayer@>(src.ScriptObject().obj);
        p.m_vBloodVector = kVec3(0, (newWeight * GAME_SCALE) * KnifeRadiusMultiplier, 0);
        p.m_vBloodVector.z += (GAME_SCALE * 3);
        
        p.m_vStabVector = (kVec3(0, (newWeight * GAME_SCALE) * KnifeRadiusMultiplier, 0) * src.Rotation());
        p.m_vStabVector += src.Origin();
        p.m_vStabVector.z += (GAME_SCALE * 3);
        
        src.InteractActorsAtPosition(p.m_vStabVector, "KnifeAttack", 0, newWeight);
    }
    
    /*
    ==============================================================
    KnifeAttack2
    ==============================================================
    */
    
    void KnifeAttack2(kActor @instigator, const float w, const float x, const float y, const float z)
    {
        kPuppet @src = self.Owner().Actor();
		float newWeight = w;
		//newWeight *= 40.0f;

        TurokPlayer @p = cast<TurokPlayer@>(src.ScriptObject().obj);
        p.m_vBloodVector = kVec3(0, (newWeight * GAME_SCALE) * KnifeRadiusMultiplier, 0);
        p.m_vBloodVector.z += (GAME_SCALE * 3);
        
        p.m_vStabVector = (kVec3(0, (newWeight * GAME_SCALE) * KnifeRadiusMultiplier, 0) * src.Rotation());
        p.m_vStabVector += src.Origin();
        p.m_vStabVector.z += (GAME_SCALE * 3);
        
        src.InteractActorsAtPosition(p.m_vStabVector, "KnifeAttack", 1, newWeight);
    }
    
    /*
    ==============================================================
    KnifeAttack3
    ==============================================================
    */
    
    void KnifeAttack3(kActor @instigator, const float w, const float x, const float y, const float z)
    {
        kPuppet @src = self.Owner().Actor();
		float newWeight = w;
		//newWeight *= 40.0f;

        TurokPlayer @p = cast<TurokPlayer@>(src.ScriptObject().obj);
        p.m_vBloodVector = kVec3(0, (newWeight * GAME_SCALE) * KnifeRadiusMultiplier, 0);
        p.m_vBloodVector.z += (GAME_SCALE * 3);
        
        p.m_vStabVector = (kVec3(0, (newWeight * GAME_SCALE) * KnifeRadiusMultiplier, 0) * src.Rotation());
        p.m_vStabVector += src.Origin();
        p.m_vStabVector.z += (GAME_SCALE * 3);
        
        src.InteractActorsAtPosition(p.m_vStabVector, "KnifeAttack", 2, newWeight);
    }
}
//============================================================================================================================
final class TurokBow : TurokWeapon
{   
    bool m_bArrowFlashed;
    bool hasUpgrade = false;
    TurokBow(kWeapon @actor)
    {
        super(actor);
        m_bArrowFlashed = false;
		weaponType = TW_WEAPON_BOW;
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
		
		hasUpgrade = HasUpgradeBow();

        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? and has charge shot
        if (hasUpgrade and time >= 1.4f && time <= 2.15f)
        {
            if(!m_bArrowFlashed)
            {
                m_bArrowFlashed = true;
                
				self.RunFxEvent("SuperArrow");
                // 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();
		// kQuat rotation2 = kQuat(src.Yaw() - Math::Deg2Rad(10), src.Pitch(), src.Roll(), 1.0f);
		// kQuat rotation3 = kQuat(src.Yaw() + Math::Deg2Rad(10), src.Pitch(), src.Roll(), 1.0f);
        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? and has charge shot
        if (hasUpgrade and time >= 1.4f && time <= 2.15f)
        {
            velocity = kVec3(0, 512 * 14.0f, 0) * rotation;
            //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");
        }
		ConsumeAmmo(1);
        self.PlaySound("sounds/shaders/bow_twang.ksnd");
        self.AnimState().Set(anim_weaponFireCharged, 4.0f, ANF_NOINTERRUPT);
    }
}
//============================================================================================================================
final class TurokPistol : TurokWeapon {
	int shotsFired;
	//------------------------------------------------------------------------------------------------------------------------
    TurokPistol(kWeapon @actor) {
        super(actor);
		weaponType = TW_WEAPON_PISTOL;
		shotsFired = 0;
    }
	//------------------------------------------------------------------------------------------------------------------------
    void OnBeginFire(void) {
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
		
		shotsFired = 0;
		FireBullet(true);
    }
	//------------------------------------------------------------------------------------------------------------------------
	void FireBullet(bool consumeBullet) {
        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, 3.0f, 0);
        
        self.RunFxEvent("GunFire");
        
        self.Owner().Actor().LoudNoiseAlert();
        self.Owner().Actor().RecoilPitch() = -0.02094395086169243f;
		if (consumeBullet) {
			ConsumeAmmo(1);
		}
		shotsFired++;
	}
	//------------------------------------------------------------------------------------------------------------------------
    void OnFire(void) {
		if (HasUpgradePistol()) {
			if (shotsFired < 3 and self.AnimState().PlayTime() >= 0.075f) {
				FireBullet(shotsFired != 2);
			}
		}
    }
	//------------------------------------------------------------------------------------------------------------------------
}

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

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

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

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

        super(actor);
		weaponType = TW_WEAPON_SHOTGUN;
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
        bFiredExpslosiveShells = Player.HasAltAmmo();
    
        self.FireProjectile("fx/weffect_riotshotgun.kfx", 6.656f-1.0f, 29.69f, -2.7648f+0.85f);
        
        if(bFiredExpslosiveShells)
        {
			if (HasUpgradeShotgun()) {
				self.FireProjectile("fx/shotgun_explosive2.kfx", 12.28f, 25.6f, -7.168f);
			} else {
				self.FireProjectile("fx/shotgun_explosive.kfx", 12.28f, 25.6f, -7.168f);
			}
        }
        else
        {
			if (HasUpgradeShotgun()) {
				self.FireProjectile("fx/shotgun2.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, 3.0f, 0);
        
        bShotgunReload = true;
        bEjectShotgunShell = true;
        
        self.Owner().Actor().LoudNoiseAlert();
        self.Owner().Actor().RecoilPitch() = -0.03926990926265717f;
		ConsumeAmmo(1);
    }
    
    /*
    ==============================================================
    OnFire
    ==============================================================
    */
    
    void OnFire(void)
    {
        if(bShotgunReload && self.AnimState().PlayTime() >= 0.375f)
        {
            self.PlaySound("sounds/shaders/ready_shotgun.ksnd");
            bShotgunReload = false;
        }
        
        if(bEjectShotgunShell && self.AnimState().PlayTime() >= 0.45f)
        {
            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);
		weaponType = TW_WEAPON_ASHOTGUN;
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
        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;
        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);
		weaponType = TW_WEAPON_RIFLE;
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
        self.AnimState().Set(anim_weaponFire, 4.0f, 0);
        rifleShotsFired = 0;
    }
    
    /*
    ==============================================================
    OnFire
    ==============================================================
    */
    
    void OnFire(void)
    {
        switch(rifleShotsFired)
        {
        case 0:
            if(self.AnimState().PlayTime() >= 0.0f)
            {
                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;
                ConsumeAmmo(1);
                rifleShotsFired++;
            }
            break;
            
        case 1:
            if(self.AnimState().PlayTime() >= 0.1f)
            {
                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.35f);
                self.FireProjectile("fx/bullet.kfx", 10.24f, 25.6f, -10.24f);
                self.RunFxEvent("GunFire");
                self.Owner().Actor().LoudNoiseAlert();
                self.Owner().Actor().RecoilPitch() = -0.02416609786450863f;
                ConsumeAmmo(1);
                rifleShotsFired++;
            }
            break;
            
        case 2:
            if(self.AnimState().PlayTime() >= 0.2f)
            {
                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;
                ConsumeAmmo(1);
                rifleShotsFired++;
            }
            break;
        }
    }
}

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

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

final class TurokPulseRifle : TurokWeapon
{   
    float pulseRifleFireTime;
    
    TurokPulseRifle(kWeapon @actor)
    {
        pulseRifleFireTime = 0;
        super(actor);
		weaponType = TW_WEAPON_PULSERIFLE;
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
        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;
            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);
		weaponType = TW_WEAPON_MINIGUN;
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
        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);
            
			if (HasUpgradeMinigun()) {
				ConsumeAmmo(2);
			} else {
				ConsumeAmmo(3);
			}
            
            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)
    {
        miniGunCycleSpeed = 0;
        bCycleMiniBarrel = false;
        bMiniGunRampUp = false;
        self.RenderModel().SetRotationOffset(1, 0, 0, 1, 0);
        self.StopLoopingSounds();
        self.PlaySound("sounds/shaders/minigun_stop.ksnd");
    }
}

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

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

final class TurokGrenadeLauncher : TurokWeapon
{   
    TurokGrenadeLauncher(kWeapon @actor)
    {
        super(actor);
		weaponType = TW_WEAPON_GRENADE;
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
        self.AnimState().Set(anim_weaponFire, 4.0f, 0);
        self.PlaySound("sounds/shaders/grenade_launch.ksnd");
        
        self.FireProjectile("fx/grenade_multi.kfx", 18.432f, 25.696f, -5.12f);
        //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;
        ConsumeAmmo(1);
    }
}

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

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

final class TurokAlienRifle : TurokWeapon
{   
    TurokAlienRifle(kWeapon @actor)
    {
        super(actor);
		weaponType = TW_WEAPON_ALIENGUN;
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
        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);
        ConsumeAmmo(5);
    }
}

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

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

final class TurokRocketLauncher : TurokWeapon
{   
    TurokRocketLauncher(kWeapon @actor)
    {
        super(actor);
		weaponType = TW_WEAPON_MISSILE;
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
        self.AnimState().Set(anim_weaponFire, 2.0f, 0); //4.0f, 2.0f
        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.FireProjectile("fx/rocket_fast.kfx", 4.096f, 25.696f, -14.336f);
		        
        self.Owner().Actor().LoudNoiseAlert();
		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);
		weaponType = TW_WEAPON_ACCELERATOR;
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
        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);
            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);
            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);
            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);
            ConsumeAmmo(4);
        }
        else
        {
            self.PlaySound("sounds/shaders/generic_190.ksnd");
            self.FireProjectile("fx/shockwave_pulse_1_weakest.kfx", 4.096f, 25.696f, -14.336f);
            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);
		weaponType = TW_WEAPON_CANNON;
    }
    
    /*
    ==============================================================
    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)
    {
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
        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();
                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);
		weaponType = TW_WEAPON_CHRONO;
    }
    
    /*
    ==============================================================
    OnBeginFire
    ==============================================================
    */
    
    void OnBeginFire(void)
    {
		if (!CanAttack()) { // or Game.GetCurrentMapID() == 0) {
			DoNoAttack();
			return;
		}
        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();
            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;
        }
    }
}
//============================================================================================================================
final class TurokLaserRifle : TurokWeapon {   
	float fxEventTime = 0.0f;
	float lastPlayTime = 0.0f;
	float chargeTime = 1.5f;
	//------------------------------------------------------------------------------------------------------------------------
    TurokLaserRifle(kWeapon @actor) {
		fxEventTime = 0.0f;
        super(actor);
		weaponType = TW_WEAPON_LASERRIFLE;
    }
	//------------------------------------------------------------------------------------------------------------------------
    void OnBeginFire(void) {
		if (!CanAttack()) {
			DoNoAttack();
			return;
		}
		fxEventTime = 0.0f;
		lastPlayTime = 0.0f;
        self.AnimState().Blend(anim_weaponFireLoop, 4.0f, 4.0f, ANF_LOOP);
		self.PlaySound("sounds/shaders/laserRifleCharge.ksnd");
    }
	//------------------------------------------------------------------------------------------------------------------------
	void OnTick(void) {
		fxEventTime = Math::Maxf(fxEventTime - GAME_DELTA_TIME, 0.0f);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void OnFire(void) {
		float playTime = self.AnimState().PlayTime();
		if (lastPlayTime < chargeTime and playTime >= chargeTime) {
			fxEventTime = 0.0f;
			self.AnimState().ChangeSpeed(3.0f);
		}
		lastPlayTime = playTime;
		
    	if (fxEventTime <= 0.0f) {
			if (playTime >= chargeTime) {
				fxEventTime = 1.0f;
				self.RunFxEvent("LaserCharge2");
			} else {
				fxEventTime = 2.0f;
				self.RunFxEvent("LaserCharge");
			}
		}
    }
	//------------------------------------------------------------------------------------------------------------------------
    void OnEndFire(void) {
		float playTime = self.AnimState().PlayTime();
		if (playTime >= chargeTime) {
			self.PlaySound("sounds/shaders/shockwave_weapon_fire.ksnd");
			self.FireProjectile("fx/laserrifle2.kfx", 2.5f, 20.0f, 7.0f);
			self.Owner().Actor().LoudNoiseAlert();
			self.Owner().Actor().RecoilPitch() = -0.01963495463132858f;
			ConsumeAmmo(2);
		} else if (playTime >= 0.25f) {
			self.PlaySound("sounds/shaders/shockwave_weapon_fire.ksnd");
			self.FireProjectile("fx/laserrifle.kfx", 2.5f, 20.0f, 7.0f);
			self.Owner().Actor().LoudNoiseAlert();
			self.Owner().Actor().RecoilPitch() = -0.01963495463132858f;
			ConsumeAmmo(1);
		}
		self.RunFxEvent("LaserChargeEnd");
		self.AnimState().Blend(anim_weaponIdle, 4.0f, 4.0f, ANF_LOOP);
		self.StopLoopingSounds();
    }
	//------------------------------------------------------------------------------------------------------------------------
}
//============================================================================================================================
