#include "scripts/common.txt"
#include "scripts/bp_common.txt"
#include "scripts/mapEnemies/MapEnemies.txt"

funcdef void EnemyTickStartCallBack(TurokEnemy @e);
funcdef void EnemyTickCallBack(TurokEnemy @e);
funcdef void EnemyTickDeathCallBack(TurokEnemy @e);
funcdef void EnemyOnDamageCallBack(TurokEnemy @e, kActor @instigator, kDictMem @damageDef, const int damage);
funcdef void EnemyOnGunFireCallBack(TurokEnemy @e, kActor @instigator, const float w, const float x, const float y, const float z);

int mySID = 0;
int lastBPEnemyID = 0;
int spiritGlowIndex = 0;

class TurokEnemy : ScriptObject {
    kActor @self;
    bool m_bMortallyWounded;
    bool m_bDroppedItem;
    kAngle m_lookAngle;
    float m_deathFreezeTime;
	float m_deathExplodeTime;
    bool wasAlive = false;
	int myID;
	int bpEnemyID = -1;
	kVec3 initPos;
	int initSectorIndex;
	bool isMovedEnemy = false;
	bool didTick = false;
	bool didTickDeath = false;
	
	EnemyTickStartCallBack @onTickStart;
	EnemyTickCallBack @onTick;
	EnemyTickDeathCallBack @onTickDeath;
	EnemyOnDamageCallBack @onDamage;
	EnemyOnGunFireCallBack @onGunFire;
	//------------------------------------------------------------------------------------------------------------------------
    TurokEnemy(kActor @actor) {
        @self = actor;
        m_bMortallyWounded = false;
        m_bDroppedItem = false;
        m_lookAngle = 0;
        m_deathFreezeTime = 0;
		m_deathExplodeTime = 0;
		myID = mySID;
		mySID++;
		// actor.Flags() |= AF_INVINCIBLE;
		if (Debug::IsActorsDisabled()) {
			actor.Flags() |= AF_STATIONARY;//AF_NOMOVEMENT;
		}
		
		initPos = self.Origin();
		initSectorIndex = self.SectorIndex();
		//Sys.Print("myID: " + myID + ", X:" + self.Origin().x + ", Y:" + self.Origin().y + ", Z:" + self.Origin().z + ", SectorIndex: " + self.SectorIndex());
		
		TurokBPEnemy @bpEnemy = cast<TurokBPEnemy@>(this);
		if (bpEnemy !is null) {
			bpEnemyID = lastBPEnemyID;
			lastBPEnemyID++;
		}
		
		MapEnemies::Setup(@this);
    }
	//------------------------------------------------------------------------------------------------------------------------
    // ~TurokEnemy() {
		// mySID = 0;
    // }
	//------------------------------------------------------------------------------------------------------------------------
	void OnEndLevel() {
		mySID = 0;
		lastBPEnemyID = 0;
	}
	//------------------------------------------------------------------------------------------------------------------------
	void SetOnTickStartCallBack(EnemyTickStartCallBack @cb) {
		@onTickStart = @cb;
	}
	//------------------------------------------------------------------------------------------------------------------------
	void SetOnTickCallBack(EnemyTickCallBack @cb) {
		@onTick = @cb;
	}
	//------------------------------------------------------------------------------------------------------------------------
	void SetOnTickDeathCallBack(EnemyTickDeathCallBack @cb) {
		@onTickDeath = @cb;
	}
	//------------------------------------------------------------------------------------------------------------------------
	void SetOnDamageCallBack(EnemyOnDamageCallBack @cb) {
		@onDamage = @cb;
	}
	//------------------------------------------------------------------------------------------------------------------------
	void SetOnGunFireCallBack(EnemyOnGunFireCallBack @cb) {
		@onGunFire = @cb;
	}
	//------------------------------------------------------------------------------------------------------------------------
	bool MoveEnemyFromTo(const float sx, const float sy, const float sz, const float dx, const float dy, const float dz) {
		return MoveEnemyFromTo(sx, sy, sz, dx, dy, dz, self.Yaw());
	}
	//------------------------------------------------------------------------------------------------------------------------
	bool MoveEnemyFromTo(const float sx, const float sy, const float sz, const float dx, const float dy, const float dz, const float yaw) {
		kVec3 src = kVec3(sx, sy, sz);
		kVec3 dest = kVec3(dx, dy, dz);
		if (src.Distance(initPos) < 10) {
			int sectorIndex = self.GetSectorIndexAtLocation(dest);
			self.SetSector(sectorIndex);
			self.Origin() = dest;
			self.Yaw() = yaw;
			
			isMovedEnemy = true;
			//self.Origin().z = self.FloorHeight();
			return true;
		}
		return false;
	}
	//------------------------------------------------------------------------------------------------------------------------
	bool IsStartPosHere(const float sx, const float sy, const float sz) {
		kVec3 src = kVec3(sx, sy, sz);
		return src.Distance(initPos) < 10;
	}
	//------------------------------------------------------------------------------------------------------------------------
    void OnTick(void) {
		if (!didTick) {
			didTick = true;
			if (onTickStart !is null) {
				onTickStart(@this);
			}
		}

		if (onTick !is null) {
			onTick(@this);
		}
		
		bool isDead = (self.Flags() & AF_DEAD) != 0;
		
		// if (!Debug::IsActorEditorOn()) {
			// uint16 buttons = Player.Buttons();
			
			// //ClosestEnemy
			// float d = self.Origin().Distance(Player.Actor().Origin());
			// if (d < 100.0f) {
				// Game.PrintLine("Closest Enemy ID is " + myID, 0, 60);
				// if ((buttons & (BC_MAPZOOMOUT)) != 0) {
					// kVec3 pos = Player.Actor().Origin(); //kVec3(-1841.241455f, -3677.148682f, 357.720276f);
					// int sectorIndex = self.GetSectorIndexAtLocation(pos);
					// self.SetSector(sectorIndex);
					// self.Origin() = pos;
					// Sys.Print("Warped enemy at X:" + initPos.x + ", Y:" + initPos.y + ", Z:" + initPos.z + ", SectorIndex: " + initSectorIndex + ", MAPID: " + Game.GetCurrentMapID());
					// //Sys.Print("Warped enemy at X:" + self.Origin().x + ", Y:" + self.Origin().y + ", Z:" + self.Origin().z + ", SectorIndex: " + self.SectorIndex());
					// Sys.Print("To");
					// Sys.Print("X:" + pos.x + ", Y:" + pos.y + ", Z:" + pos.z + ", SectorIndex: " + sectorIndex);
				// }
				
				// if ((buttons & (BC_MAPZOOMIN)) != 0) {
					// kVec3 pos = Player.Actor().Origin(); //kVec3(-1841.241455f, -3677.148682f, 357.720276f);
					// pos.z = Player.Actor().FloorHeight();
					// int sectorIndex = self.GetSectorIndexAtLocation(pos);
					// self.SetSector(sectorIndex);
					// self.Origin() = pos;
					// Sys.Print("GAME_SCALE = " + GAME_SCALE);
					// Sys.Print("Warped enemy at X:" + initPos.x + ", Y:" + initPos.y + ", Z:" + initPos.z + ", SectorIndex: " + initSectorIndex + ", MAPID: " + Game.GetCurrentMapID());
					// //Sys.Print("Warped enemy at X:" + self.Origin().x + ", Y:" + self.Origin().y + ", Z:" + self.Origin().z + ", SectorIndex: " + self.SectorIndex());
					// Sys.Print("To");
					// Sys.Print("X:" + pos.x + ", Y:" + pos.y + ", Z:" + pos.z + ", SectorIndex: " + sectorIndex);
				// }
			// }
		// }
		
        if (isDead) {
			if (wasAlive) {
				wasAlive = false;
				OnTickDeath();
			}
			
            if (m_deathFreezeTime > 0) {
                m_deathFreezeTime -= GAME_DELTA_TIME;
                
                if(m_deathFreezeTime <= 0)
                {
                    Game.SpawnFx("fx/freeze_explosion.kfx", self.Origin(), self.SectorIndex());
                    self.Remove();
                }
            }
			if (m_deathExplodeTime > 0) {
				m_deathExplodeTime -= GAME_DELTA_TIME;
                
                if (m_deathExplodeTime <= 0) {
					self.PlaySound("sounds/shaders/explosion_2.ksnd");
                    Game.SpawnFx("fx/explosion_bits.kfx", self.Origin(), self.SectorIndex()); //bits
                    Game.SpawnFx("fx/generic_244.kfx", self.Origin(), self.SectorIndex()); //blood
					float gibZ = 50.0f;
					if (self.Type() == AT_ALIEN) {
						TossGib1(self, 0, 0, 0, gibZ);
						TossGib2(self, 0, 0, 0, gibZ);
						TossGib3(self, 0, 0, 0, gibZ);
						TossGib4(self, 0, 0, 0, gibZ);
					} else {
						TossGib5(self, 0, 0, 0, gibZ);
						TossGib6(self, 0, 0, 0, gibZ);
						TossGib7(self, 0, 0, 0, gibZ);
						TossGib8(self, 0, 0, 0, gibZ);
					}
                    self.Remove();
                }
			}
        } else {
			wasAlive = true;
		}
    }
	//------------------------------------------------------------------------------------------------------------------------
    void OnSpawn(void) { }
	//------------------------------------------------------------------------------------------------------------------------
    void TurnAngles(const float turnSpeed, const float angles) {
        float temp = angles;
        float ang = angles;
        
        if (ang > turnSpeed) {
            ang = turnSpeed;
        }
        else if (ang < -turnSpeed) {
            ang = -turnSpeed;
        }
        
        ang *= GAME_FRAME_TIME;
        if (Math::Fabs(ang) > Math::Fabs(temp)) {
            ang = temp;
        }
        
        self.Yaw() += ang;
    }
	//------------------------------------------------------------------------------------------------------------------------
    bool InPlayerProjectilePath(const float angleRange)
    {
        if ((Player.Actor().PlayerFlags() & PF_FIREDPROJECTILE) != 0) {
            if(Math::Fabs(self.GetTurnYaw(Player.Actor().Origin())) < angleRange) {
                return true;
            }
        }
        return false;
    }
	//------------------------------------------------------------------------------------------------------------------------
    kActor @TossActor(const kStr &in itemName, const float x, const float y, const float z, const kVec3 &in velocity) {
        kActor @actor = ActorFactory.Spawn(itemName, x, y, z, 0, self.SectorIndex());
        if (actor is null) {
            return null;
        }
        actor.Scale().Set(0.35f, 0.35f, 0.35f);
        actor.ClipFlags() = (CF_DROPOFF|CF_CLIPEDGES|CF_NOCLIPACTORS|CF_COLLIDEFLOORS|CF_COLLIDEHEIGHT);
        actor.Velocity() = velocity;
        actor.Velocity() *= (1.0f / 60.0f);
        
        switch(actor.Type()) {
        case AT_GIB_ALIEN3:
            actor.BounceDamp() = 0.6f;
            actor.Gravity() = 0.5f;
            break;
        
        case AT_GIB_STALKER3:
            actor.BounceDamp() = 0.4f;
            actor.Gravity() = 0.6f;
            break;
            
        case AT_GIB_STALKER5:
        case AT_GIB_STALKER2:
        case AT_GIB_STALKER1:
            actor.BounceDamp() = 0.3f;
            actor.Gravity() = 0.6f;
            break;
            
        default:
            actor.BounceDamp() = 0.5f;
            actor.Gravity() = 0.5f;
            break;
        }
        
        return actor;
    }
	//------------------------------------------------------------------------------------------------------------------------
    void TossItem(const kStr &in itemName, const float x, const float y, const float z) {
        kActor @item = TossActor(itemName, x, y, z, kVec3(0, 0, 1).Randomize(0.25f).Normalize() * 409.6f);
        item.RunFxEvent("Item_Spawn");
    }
	//------------------------------------------------------------------------------------------------------------------------
    void TossArrow() {
		kVec3 pos = self.GetTransformedVector(kVec3(0.0f, 0.0f, 0.0f));
        kActor @item = TossActor("BP_Arrow", pos.x, pos.y, pos.z, kVec3(0, 0, 1).Randomize(0.25f).Normalize() * 409.6f);
		//item.Pitch() = Math::Deg2Rad(180);
		//item.RunFxEvent("ArrowPickup_Glow");
		// Game.SpawnFx("fx/generic_260.kfx", item.Origin(), item.SectorIndex());
    }
	//------------------------------------------------------------------------------------------------------------------------
    void TossGib(const kStr &in gibActor, const float x, const float y, const float z) {
        kVec3 dir = (kVec3(0, 0, 1).Randomize(0.3f).Normalize() * ((Math::Rand() % -2 + 3) * 10.24f)) * 15.0f;
        kVec3 normal, cp;
        kActor @gib;
        TurokGiblet @gibObj;
        
        self.CheckPosition(x, y);
        normal = CModel.ContactNormal();
        
        @gib = TossActor(gibActor, x, y, z, dir);
        
        dir.Normalize();
        
        cp = normal.Cross(dir);
        cp.Normalize();
        
        gib.Yaw() = cp.ToYaw();
        gib.Pitch() = -cp.ToPitch();
        
        @gibObj = cast<TurokGiblet@>(gib.ScriptObject().obj);
        
        if (!(gibObj is null)) {
            gibObj.Spin();
        }
    }
	//------------------------------------------------------------------------------------------------------------------------
    void Knockback(kActor @instigator, const float r, const float x, const float y, const float z) {
        kVec3 org;
        kVec3 pos;
        kActor @targ;
        
        if(self.GetTarget() is null) {
            return;
        }
        
        @targ = self.GetTarget();
        
        org.x = self.Origin().x;
        org.y = self.Origin().y;
        org.z = self.Origin().z + self.Height() * 0.5f;
        
        pos = targ.GetTransformedVector(kVec3(x, y, z));
        
        kVec3 dir = pos - org;
        float dist = dir.Unit();
        
        if (dist > (r * GAME_SCALE + self.Radius())) {
            return;
        }
        
        dir.Normalize();
        dir *= (1.75f*GAME_SCALE);
        dir.z = (0.875f*GAME_SCALE);
        
        targ.Velocity() += dir;
        
        if (targ is Player.Actor().CastToActor()) {
            Player.Actor().Origin().z += GAME_SCALE;
            Player.Actor().PlayerFlags() |= PF_NOAIRFRICTION;
            
            if (!(Player.Actor().ScriptObject() is null)) {
                // WARNING: assumes script object is TurokPlayer
                TurokPlayer @p = cast<TurokPlayer@>(Player.Actor().ScriptObject().obj);
                
                if(p is null) {
                    return;
                }
                
                p.m_shoveTime = 0.5f;
                p.m_vShoveVector = org;
            }
        }
    }
	//------------------------------------------------------------------------------------------------------------------------
    void SightSound(kActor @instigator, const float w, const float x, const float y, const float z) {}
	//------------------------------------------------------------------------------------------------------------------------
    void DeathSound(kActor @instigator, const float w, const float x, const float y, const float z) {}
	//------------------------------------------------------------------------------------------------------------------------
    void InjurySound(kActor @instigator, const float w, const float x, const float y, const float z) {}
	//------------------------------------------------------------------------------------------------------------------------
    void ViolentSound(kActor @instigator, const float w, const float x, const float y, const float z) {}
	//------------------------------------------------------------------------------------------------------------------------
    void Unused23(kActor @instigator, const float w, const float x, const float y, const float z) {}
	//------------------------------------------------------------------------------------------------------------------------
    void Unused24(kActor @instigator, const float w, const float x, const float y, const float z) {}
	//------------------------------------------------------------------------------------------------------------------------
    void Unused60(kActor @instigator, const float w, const float x, const float y, const float z) {}
	//------------------------------------------------------------------------------------------------------------------------
    void Unused94(kActor @instigator, const float w, const float x, const float y, const float z) {}
	//------------------------------------------------------------------------------------------------------------------------
    void Unused398(kActor @instigator, const float w, const float x, const float y, const float z) {}
	//------------------------------------------------------------------------------------------------------------------------
    void CauseThump(kActor @instigator, const float r, const float x, const float y, const float z) {
        kActor @actor = ActorFactory.Spawn("QuakeSource", 0, 0, 0, 0, self.SectorIndex());
        TurokQuakeSource @quake;
        if (actor is null) {
            return;
        }
        @quake = cast<TurokQuakeSource@>(actor.ScriptObject().obj);
        if (quake is null) {
            return;
        }
        quake.SetupThump(self.GetTransformedVector(kVec3(x, y, z)), r);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void TriggerEvent(kActor @instigator, const float w, const float x, const float y, const float z) {
        World.TriggerActorsByTID(instigator, int(w));
    }
	//------------------------------------------------------------------------------------------------------------------------
    void FootStepPuff(kActor @instigator, const float a, const float x, const float y, const float z) {
        if(a == 0.0f) {
            self.SpawnFx("fx/dustcloud_footfall.kfx", kVec3(x, y, z+4.096f));
        }
        else {
            self.SpawnFx("fx/dustcloud_bodyfall.kfx", kVec3(x, y, z+4.096f));
        }
    }
	//------------------------------------------------------------------------------------------------------------------------
    void SwishSound(kActor @instigator, const float w, const float x, const float y, const float z) {
        self.PlaySound("sounds/shaders/knife_swish_1.ksnd");
    }
	//------------------------------------------------------------------------------------------------------------------------
    void GunFire(kActor @instigator, const float w, const float x, const float y, const float z) {}
	//------------------------------------------------------------------------------------------------------------------------
    void MeleeVeryWimpy(kActor @instigator, const float w, const float x, const float y, const float z) {
        self.MeleeObject("Damage_Generic_1", kVec3(x, y, z), w);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void MeleeBluntWeak(kActor @instigator, const float w, const float x, const float y, const float z) {
        self.MeleeObject("Damage_Blunt_3", kVec3(x, y, z), w);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void MeleeBluntMedium(kActor @instigator, const float w, const float x, const float y, const float z) {
        self.MeleeObject("Damage_Blunt_5", kVec3(x, y, z), w);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void MeleeAttack1(kActor @instigator, const float w, const float x, const float y, const float z) {
        self.MeleeObject("Damage_Flesh_3", kVec3(x, y, z), w);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void MeleeAttack2(kActor @instigator, const float w, const float x, const float y, const float z) {
        self.MeleeObject("Damage_Flesh_5", kVec3(x, y, z), w);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void MeleeAttack3(kActor @instigator, const float w, const float x, const float y, const float z) {
        self.MeleeObject("Damage_Blunt_5", kVec3(x, y, z), w);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void MeleeBluntWimpy(kActor @instigator, const float w, const float x, const float y, const float z) {
        self.MeleeObject("Damage_Blunt_2", kVec3(x, y, z), w);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void MeleeBluntStrong(kActor @instigator, const float w, const float x, const float y, const float z) {
        self.MeleeObject("Damage_Blunt_10", kVec3(x, y, z), w);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void MeleeBluntVeryStrong(kActor @instigator, const float w, const float x, const float y, const float z) {
        self.MeleeObject("Damage_Blunt_15", kVec3(x, y, z), w);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void MeleeBluntHeavy(kActor @instigator, const float w, const float x, const float y, const float z) {
        self.MeleeObject("Damage_Blunt_20", kVec3(x, y, z), w);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void MeleeBluntVeryHeavy(kActor @instigator, const float w, const float x, const float y, const float z) {
        self.MeleeObject("Damage_Blunt_30", kVec3(x, y, z), w);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void BloodGush(kActor @instigator, const float w, const float x, const float y, const float z) {
        const int count = 3;
        
        if ((self.Flags() & AF_NOBLOOD) != 0) {
            return;
        }
        
        kVec3 vel   = self.Velocity();
        kVec3 pos   = self.GetTransformedVector(kVec3(x, y, z));
        kVec3 pos_v = pos - vel;
        kQuat rot   = vel.ToQuat();
        
        float f = 0.0f;
        kVec3 newPos;
        
        for(int i = 0; i < count; ++i) {
            newPos = pos;
            newPos.Lerp(pos_v, f / 3.0f);
            
            Game.SpawnFx("fx/spurt_blood.kfx", self, vel, newPos, rot);
            f += 1.0f;
        }
    }
	//------------------------------------------------------------------------------------------------------------------------
    void TossGib1(kActor @instigator, const float w, const float x, const float y, const float z) {
        kVec3 org = self.GetTransformedVector(kVec3(x, y, z));
        TossGib("Gib_Alien_Head", org.x, org.y, org.z);
        Game.SpawnFx("fx/generic_108.kfx", org, self.SectorIndex());
    }
	//------------------------------------------------------------------------------------------------------------------------
    void TossGib2(kActor @instigator, const float w, const float x, const float y, const float z) {
        kVec3 org = self.GetTransformedVector(kVec3(x, y, z));
        TossGib("Gib_Alien_Torso", org.x, org.y, org.z);
        Game.SpawnFx("fx/generic_108.kfx", org, self.SectorIndex());
    }
	//------------------------------------------------------------------------------------------------------------------------
    void TossGib3(kActor @instigator, const float w, const float x, const float y, const float z) {
        kVec3 org = self.GetTransformedVector(kVec3(x, y, z));
        TossGib("Gib_Alien_Feet", org.x, org.y, org.z);
        Game.SpawnFx("fx/generic_108.kfx", org, self.SectorIndex());
    }
	//------------------------------------------------------------------------------------------------------------------------
    void TossGib4(kActor @instigator, const float w, const float x, const float y, const float z) {
        kVec3 org = self.GetTransformedVector(kVec3(x, y, z));
        TossGib("Gib_Alien_Body", org.x, org.y, org.z);
        Game.SpawnFx("fx/generic_108.kfx", org, self.SectorIndex());
    }
	//------------------------------------------------------------------------------------------------------------------------
    void TossGib5(kActor @instigator, const float w, const float x, const float y, const float z) {
        kVec3 org = self.GetTransformedVector(kVec3(x, y, z));
        TossGib("Gib_Stalker_Head", org.x, org.y, org.z);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void TossGib6(kActor @instigator, const float w, const float x, const float y, const float z) {
        kVec3 org = self.GetTransformedVector(kVec3(x, y, z));
        TossGib("Gib_Stalker_Torso", org.x, org.y, org.z);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void TossGib7(kActor @instigator, const float w, const float x, const float y, const float z) {
        kVec3 org = self.GetTransformedVector(kVec3(x, y, z));
        TossGib("Gib_Stalker_Feet", org.x, org.y, org.z);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void TossGib8(kActor @instigator, const float w, const float x, const float y, const float z) {
        kVec3 org = self.GetTransformedVector(kVec3(x, y, z));
        TossGib("Gib_Stalker_Body", org.x, org.y, org.z);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void ExplosionSfx2(kActor @instigator, const float w, const float x, const float y, const float z) {
        self.PlaySound("sounds/shaders/explosion_2.ksnd");
    }
	//------------------------------------------------------------------------------------------------------------------------
    void DropItem(kActor @instigator, const float w, const float x, const float y, const float z) {
        if(Game.GetDifficulty() >= DIFFICULTY_HARD or Game.GetCurrentMapID() == 53) {
            return;
        }
        
        kVec3 org;
        const uint spawnFlags = self.SpawnFlags2();
        
        if (m_bDroppedItem) {
            return;
        }
        
        org = self.GetTransformedVector(kVec3(x, y, z));
        m_bDroppedItem = true;
        
        if ((spawnFlags & 0x1) != 0) {
            TossItem("Ammo_ExpShells_Pickup", org.x, org.y, org.z);
        }
        if ((spawnFlags & 0x2) != 0) {
            TossItem("Ammo_Grenade_Pickup", org.x, org.y, org.z);
        }
        if ((spawnFlags & 0x4) != 0) {
            TossItem("Health_Medium", org.x, org.y, org.z);
        }
        if ((spawnFlags & 0x8) != 0) {
            TossItem("Health_Full", org.x, org.y, org.z);
        }
        if ((spawnFlags & 0x10) != 0) {
            TossItem("Health_Ultra", org.x, org.y, org.z);
        }
        if ((spawnFlags & 0x20) != 0) {
            TossItem("Health_Small", org.x, org.y, org.z);
        }
        if ((spawnFlags & 0x40) != 0) {
            TossItem("Health_Large", org.x, org.y, org.z);
        }
        if ((spawnFlags & 0x80) != 0) {
            TossItem("Ammo_MiniGunAmmo_Pickup", org.x, org.y, org.z);
        }
        if ((spawnFlags & 0x100) != 0) {
            if(m_bMortallyWounded && Math::RandMax(100) > 85) {
                TossItem("Health_MortalWound", org.x, org.y, org.z);
            }
        }
        if ((spawnFlags & 0x200) != 0) {
            TossItem("Ammo_Rockets_Pickup", org.x, org.y, org.z);
        }
        if ((spawnFlags & 0x400) != 0) {
            TossItem("Ammo_Shells_Pickup", org.x, org.y, org.z);
        }
        if ((spawnFlags & 0x800) != 0) {
            TossItem("Ammo_Cell_Pickup", org.x, org.y, org.z);
        }
        if ((spawnFlags & 0x1000) != 0) {
            TossItem("Ammo_LargeCell_Pickup", org.x, org.y, org.z);
        }
        if ((spawnFlags & 0x2000) != 0) {
            TossItem("Ammo_Clip_Pickup", org.x, org.y, org.z);
        }
    }
	//------------------------------------------------------------------------------------------------------------------------
	void TossSpiritItem(int amount) {
		for (int i = 0; i < amount; i++) {
			kVec3 vel = kVec3(0, 0, 1).Randomize(0.25f).Normalize() * 1209.6f;
			vel.z = Math::RandRange(500.0f, 750.0f);
			kActor @item = TossActor("SpiritForce_1", self.Origin().x, self.Origin().y, self.Origin().z, vel);
			item.Yaw() = Math::Deg2Rad(Math::RandRange(0.0f, 360.0f));
			item.RunFxEvent("Item_Spawn");
			item.RunFxEvent("Spirit_Glow" + spiritGlowIndex);
			spiritGlowIndex++;
			if (spiritGlowIndex > 4) {
				spiritGlowIndex = 0;
			}
		}
	}
	//------------------------------------------------------------------------------------------------------------------------
	// Check if dead on Tick (Gets called on all enemies except the turret unlike OnDeath)
	//------------------------------------------------------------------------------------------------------------------------
	void OnTickDeath() {
		didTickDeath = true;
		if (onTickDeath !is null) {
			onTickDeath(@this);
		}
		
		//no spirits on arena and challenge maps
		if (Game.GetCurrentMapID() >= 53) {
            return;
        }
		
		//spawn exp based on map and enemy killed
		int baseAmount = 0;
		switch(Game.GetCurrentMapID()) {
			case 4:
			case 5:
				baseAmount = 5;
				break;
			case 6:
			case 7:
			case 8:
			case 9:
				baseAmount = 10;
				break;
			case 10:
			case 11:
			case 12:
			case 13:
				baseAmount = 15;
				break;
			default:
				baseAmount = 20;
				break;
		}
		
		int enemyAmount = 0;
		switch(self.Type())
        {
			case AT_RAPTOR:
				enemyAmount = 1;
				break;
			case AT_ALIEN:
			case AT_KILLERPLANT:
				enemyAmount = 2;
				break;
			case AT_DINOSAUR1:
			case AT_PURLIN:
				enemyAmount = 3;
				break;
			case AT_MECH:
			case AT_SEWERCRAB:
				enemyAmount = 4;
				break;
			case AT_RIDER:
			case AT_SANDWORM:
				enemyAmount = 5;
				break;
			case AT_ANIMAL:
			case AT_GRUNT:
			case AT_STALKER:
			case AT_FISH:
			case AT_INSECT:
			case AT_BOAR:
			case AT_DRAGONFLY:
			case AT_UNKNOWN1:
			case AT_TURRET:
			default:
				enemyAmount = 0;
				break;
		}
		
		TossSpiritItem(baseAmount + enemyAmount);
	}
	//------------------------------------------------------------------------------------------------------------------------
    void OnDamage(kActor @instigator, kDictMem @damageDef, const int damage) {
		
		//self.SpawnFx("fx/generic_244.kfx", kVec3(0, 0, 100));
		//BloodGush(instigator, 0, 0, 0, 100);
		
		if (onDamage !is null) {
			onDamage(@this, @instigator, @damageDef, damage);
		}
		
        if (damageDef is null) {
            return;
        }
		        
		bool bValue;
        
		if (damageDef.GetBool("bPlayerOnly", bValue) && bValue == true) {
			self.Health() += damage;
		}
		
        if (damageDef.GetBool("bArrow", bValue) && bValue == true) {
			TossArrow();
        }
		
		
		
		//TossGib1(self, 0, 0, 0, 0);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void OnDeath(kActor @killer, kDictMem @damageDef)
    {
        bool bValue;
        
        if(damageDef is null)
        {
            return;
        }
		        
        m_bDroppedItem = false;
        
        if (damageDef.GetBool("bAccelerator", bValue) && bValue == true) {
            self.AnimState().flags |= (ANF_PAUSED|ANF_NOINTERRUPT);
            m_deathFreezeTime = 3.0f;
            self.RunFxEvent("Enemy_Freeze");
            Game.SpawnFx("fx/freeze_start.kfx", self.Origin(), self.SectorIndex());
        } else if (damageDef.GetBool("bDeathExplode", bValue) && bValue == true) {
            self.AnimState().flags |= (ANF_PAUSED|ANF_NOINTERRUPT);
            m_deathExplodeTime = 0.01f;
            // self.RunFxEvent("Enemy_Freeze");
            //Game.SpawnFx("fx/freeze_start.kfx", self.Origin(), self.SectorIndex());
        }
		// if (damageDef.GetBool("bArrow", bValue) && bValue == true) {
			// TossArrow();
        // }
		
    }
	//------------------------------------------------------------------------------------------------------------------------
};
