Class GHAGEventHandler : EventHandler
{
	GHAGGardevoir Gardie;
	
	int shinyodds;
	
	bool mapHasMinimalSecrets;
	
	bool bonus_one;
	bool bonus_two;
	bool bonus_three;
	bool bonus_gun;
	
	bool dropShotgun;
	bool dropChaingun;
	bool dropThunderbolt;
	bool dropPsychic;
	bool dropIcyWind;
	bool dropWillOWisp;
	bool dropMoonblast;
	
	override void PlayerEntered(PlayerEvent event)
	{
		gardie = GHAGGardevoir(players[consoleplayer].mo);
		
		if (level.levelNum == 999)
		{
			gardie.rageConstant = 940;
			
			bonus_one = true;
			bonus_two = true;
			bonus_three = true;
			bonus_gun = true;
	
			dropThunderbolt = true;
			dropPsychic = true;
			dropIcyWind = true;
			dropWillOWisp = true;
			dropMoonblast = true;
		}
		else
		{
			bonus_one = false;
			bonus_two = false;
			bonus_three = false;
			bonus_gun = false;
	
			dropThunderbolt = players[consoleplayer].mo.countInv('GHAGthunderbolt') == 0 ? false : true;
			dropPsychic = players[consoleplayer].mo.countInv('GHAGpsychic') == 0 ? false : true;
			dropIcyWind = players[consoleplayer].mo.countInv('GHAGicywind') == 0 ? false : true;
			dropWillOWisp = players[consoleplayer].mo.countInv('GHAGWillOWisp') == 0 ? false : true;
			dropMoonblast = players[consoleplayer].mo.countInv('GHAGMoonBlastGun') == 0 ? false : true;
		}
	}
	
	override void WorldThingSpawned(WorldEvent event)
	{
		if (GHAGGardevoir(event.thing)) {
			gardie = GHAGGardevoir(event.thing);
			return;
		}
		
		if (event.thing is "Inventory")
		{
			let item = event.thing;
		
			switch(event.thing.getClassName())
			{
				default:
					item.height = 32;
			}
		}
		
										//Nazis don't get to be shiny
		if (Actor(event.thing).bIsMonster && !WolfensteinSS(event.thing) && !event.thing.bFriendly)
		{
			if (shinyodds == 0) shinyodds = 4096;
			int rng = random(1, shinyodds);
			if (rng == shinyodds / 2 || shinyodds == 1) 
			{
				GHAGEventHandler.SetShinyDemon(event.thing);
			}
			return;
		}
		
		if (Health(event.thing)) {
				
			let healItem = Health(event.thing);
			if (healItem.maxAmount < 350) {
				healItem.MaxAmount = 350;
			} else {
				healItem.MaxAmount = Int(healItem.MaxAmount * 1.75);
			}
			if(healItem.Amount >= 100) {
				healItem.Amount = Int(healItem.Amount * 1.75);
			}
			return;
		}
		
		if (event.thing is "Weapon")
		{
			let gun = Weapon(event.thing);
			if (!gun) return;
			
			//Ignore any spawning GHAG weapons
			if (GHAGWeapon(gun))
			{
				return;
			}
			
			//Agnostic weapon type check
			if (gun is "Pistol")
			{
				if (gardie.countinv("GHAGPistol") == 0) {
					gun.spawn("GHAGPistolPickup", gun.pos);
				} else {
					gun.spawn("Clipbox", gun.pos);
				}
				gun.destroy();
			}
			if (gun is "Shotgun")
			{
				if (gardie.countinv("GHAGShotgun") == 0 && !dropShotgun) {
					gun.spawn("GHAGShotgunPickup", gun.pos);
					dropShotgun = true;
				} else {
					gun.spawn("Shellbox", gun.pos);
				}
				gun.destroy();
			}
			if (gun is "SuperShotgun")
			{
				if (gardie.countinv("GHAGSuperRailgun") == 0) {
					gun.spawn("GHAGSuperRailgunPickup", gun.pos);
				} else {
					gun.spawn("Shellbox", gun.pos);
				}
				gun.destroy();
			}
			if (gun is "Chaingun")
			{
				if (gardie.countinv("GHAGNailgun") == 0 && !dropChaingun) {
					gun.spawn("GHAGNailgunPickup", gun.pos);
					dropChaingun = true;
				} else {
					gun.spawn("Clipbox", gun.pos);
				}
				gun.destroy();
			}
			if (gun is "RocketLauncher")
			{
				gun.spawn("GHAGRocketBox", gun.pos);
				gun.destroy();
				return;
			}
			if (gun is "PlasmaRifle" || gun is "BFG9000")
			{
				if (gardie.countinv("GHAGPlasmaRifle") == 0) {
					gun.spawn("GHAGPlasmaPickup", gun.pos);
				} else {
					gun.spawn("CellPack", gun.pos);
				}
				gun.destroy();
			}
		}
	}
	
	string getWeaponClass(String _type)
	{
		if (_type == "Clip") return "GHAGBulletBox";
		if (_type == "Shell") return "GHAGShellBox";
		if (_type == "RocketAmmo") return "GHAGRocketBox";
		if (_type == "Cell") return "GHAGCellPack";
	
		return "NullAmmoType";
	}
	
	static void SetShinyDemon(Actor thing)
	{
		let shinything = Actor(thing);
		if (!shinything) return;
		
		//ActorTracker.TrackThing(thing, SHINY);
		
		if (Zombieman(shinything)) 
		{
			shinything.A_SetTranslation("ShinyZombie");
			return;
		}
		
		if (ShotgunGuy(shinything))
		{
			shinything.A_SetTranslation("ShinyShotgun");
			return;
		}
		
		if (ChaingunGuy(shinything))
		{
			shinything.A_SetTranslation("ShinyChaingun");
			return;
		}
		
		if (DoomImp(shinything))
		{
			shinything.A_SetTranslation("ShinyImp");
			return;
		}
		
		if (Demon(shinything)) 
		{
			shinything.A_SetTranslation("ShinyDemon");
			return;
		}
				
		if (HellKnight(shinything))
		{
			shinything.A_SetTranslation("ShinyKnight");
			return;
		}
		
		if (BaronOfHell(shinything))
		{
			shinything.A_SetTranslation("ShinyBaron");
			return;
		}
		
		if (Arachnotron(shinything))
		{
			shinything.A_SetTranslation("ShinySpidey");
			return;
		}
		
		if (Revenant(shinything))
		{
			shinything.A_SetTranslation("ShinyBoner");
			return;
		}
		
		if (Cacodemon(shinything))
		{
			shinything.A_SetTranslation("ShinyCaco");
			return;
		}
		
		if (LostSoul(shinything))
		{
			shinything.A_SetTranslation("ShinySoul");
			return;
		}
		
		if (PainElemental(shinything))
		{
			shinything.A_SetTranslation("ShinyPain");
			return;
		}
		
		if (Fatso(shinything))
		{
			shinything.A_SetTranslation("ShinyFatty");
			return;
		}
		
		if (Archvile(shinything))
		{
			shinything.A_SetTranslation("ShinyVile");
			return;
		}
		
		if (Cyberdemon(shinything))
		{
			shinything.A_SetTranslation("ShinyCybie");
			return;
		}
		
		if (SpiderMasterMind(shinything))
		{
			shinything.A_SetTranslation("ShinyMomma");
			return;
		}
		
		
	}

	//Killing an enemy will reset the anger delay timer.
	override void WorldThingDied(WorldEvent event) 
	{
		gardie = GHAGGardevoir(players[consoleplayer].mo);
		
		if (ExplosiveBarrel(event.thing)) return;
		if (event.thing.target is 'PlayerPawn' ||
			event.thing.target is 'ExplosiveBarrel' ||
			event.thing.target is 'Pod' ||
			event.thing.target is 'GHAGChainRailMarker'
			) {
			
			if (gardie.RageConstant >= 300 && !dropThunderBolt && gardie.countInv("GHAGThunderbolt") == 0)
			{
				spawnPokemonMove('GHAGThunderbolt', event);
				dropThunderbolt = true;
			}
			
			if (gardie.RageConstant >= 400 && !dropPsychic && gardie.countInv("GHAGPsychic") == 0)
			{
				spawnPokemonMove('GHAGPsychic', event);
				dropPsychic = true;
			}
			
			if (gardie.RageConstant >= 500 && !dropIcyWind && gardie.countInv("GHAGIcyWind") == 0)
			{
				spawnPokemonMove('GHAGIcyWind', event);
				dropIcyWind = true;
			}
			
			if (gardie.RageConstant >= 600 && !dropWillOWisp && gardie.countInv("GHAGWillOWisp") == 0)
			{
				spawnPokemonMove('GHAGWillOWisp', event);
				dropWillOWisp = true;
			}
			
			if (gardie.RageConstant >= 700 && !dropMoonblast && gardie.countInv("GHAGMoonBlastGun") == 0)
			{
				spawnPokemonMove('GHAGMoonBlastGun', event);
				dropMoonblast = true;
			}
			
			int killed = level.killed_monsters + 1;
			double ratio = double(killed) / double(level.total_monsters);
			
			if (killed >= level.total_monsters && !bonus_gun)
			{
				SpawnBonusItem(event.thing.pos, true);
				bonus_gun = true;
			}
			
			if (ratio >= 0.25 && !bonus_one)
			{
				SpawnBonusItem(event.thing.pos);
				bonus_one = true;
			}
			
			if (ratio >= 0.5 && !bonus_two)
			{
				SpawnBonusItem(event.thing.pos);
				bonus_two = true;
			}
			
			if (ratio >= 0.75 && !bonus_three)
			{
				SpawnBonusItem(event.thing.pos);
				bonus_three = true;
			}
			
			CatharsisBonus(event.thing);
		}
		
		if (event.thing.bIsMonster)
		{
			//Original code by Marisa Kirisame, used with permission
			int gibhealth = event.Thing.GetGibHealth();
			bool gotgibbed = (	!event.Thing.bDONTGIB && 
								(	(event.Inflictor && event.Inflictor.bEXTREMEDEATH) || 
									(event.DamageSource && event.DamageSource.bEXTREMEDEATH) || 
									(event.DamageType == 'Extreme') 
									|| (event.Thing.Health < gibhealth)
									|| (event.Thing.health == (gibhealth * -1) && event.Thing.Health < int(gibhealth / 4))
								) 
								&& (!event.Inflictor || !event.Inflictor.bNOEXTREMEDEATH) 
								&& (!event.DamageSource || !event.DamageSource.bNOEXTREMEDEATH));
		
			if (gotGibbed)
			{
				switch (event.thing.getClassName())
				{
					case 'Arachnotron':
						XDeathHandler.assignGibState(event.thing, 'XDeathArachnotron');
						break;
					case 'Archvile':
						XDeathHandler.assignGibState(event.thing, 'XDeathArchvile');
						break;
					case 'BaronOfHell':
						XDeathHandler.assignGibState(event.thing, 'XDeathBaronOfHell');
						break;
					case 'Cacodemon':
						XDeathHandler.assignGibState(event.thing, 'XDeathCacodemon');
						break;
					case 'Demon':
					case 'Spectre':
						XDeathHandler.assignGibState(event.thing, 'XDeathDemon');
						break;
					case 'HellKnight':
						XDeathHandler.assignGibState(event.thing, 'XDeathHellKnight');
						break;
					case 'Fatso':
						XDeathHandler.assignGibState(event.thing, 'XDeathMancubus');
						break;
					case 'Revenant':
						XDeathHandler.assignGibState(event.thing, 'XDeathRevenant');
						break;
					default:
						break;
				}
			}
		}
	}
	
	void spawnPokemonMove(Name _move, WorldEvent event)
	{
		let wep = event.thing.spawn(_move, event.thing.pos);
		wep.A_ChangeVelocity(random(-4, 4), random(-4, 4), random(-4, 4), CVF_REPLACE);
		wep.A_SetPitch(random(80, 120));
	}
	
	void CatharsisBonus(Actor thing) 
	{
		if (!thing) return;
		
		gardie = GHAGGardevoir(players[consoleplayer].mo);
		
		gardie.killInterupt = 35 + Int(35 * gardie.getRageModifier());
		
		int angerBonus = Max(int(thing.spawnHealth() / 5), 1);
		int willBonus = int(AngerBonus / 10);
		
		if (WolfensteinSS(thing)) angerbonus = 3000;
		
		if (gardie.player.ReadyWeapon is "GHAGPokemonMove")
		{
			return;
		}
		
		else 
		
		{
		
			while (true) 
			{
				let rageitem = GHAGRageEssence(thing.A_DropItem("GHAGRageEssence", 1));
				rageitem.A_SetPitch(random(60, 80));
				rageitem.A_SetAngle(random(1, 360));
			
				if (WolfensteinSS(thing)) 
				{
					rageitem.amount = 100;
					rageitem.A_SetScale(1, 1);
					angerbonus -= 100;
					rageitem.A_ChangeVelocity(random(-4, 4), random(-4, 4), random(-4, 4), CVF_REPLACE);
					rageitem.A_SetPitch(random(80, 120));
					if (angerbonus <= 0) break;
					else continue;
				}
			
				rageitem.A_ChangeVelocity(random(-2, 2), random(-2, 2), random(-2, 2), CVF_REPLACE);
				
				if (angerbonus >= 1000) 
				{
					rageitem.amount = 500;
					rageitem.A_SetScale(3, 3);
					angerbonus -= 500;
				} 
				else if (angerbonus >= 500)
				{
					rageitem.amount = 250;
					rageitem.A_SetScale(2, 2);
					angerbonus -= 250;
				}
				else if (angerbonus >= 250)
				{
					rageitem.amount = 100;
					rageitem.A_SetScale(1.5, 1.5);
					angerbonus -= 100;
				} 
				else if (angerbonus >= 50)
				{
					rageitem.amount = 50;
					rageitem.A_SetScale(1, 1);
					angerbonus -= 50;
				}
				else if (angerbonus >= 5)
				{
					rageitem.amount = 5;
					rageitem.A_SetScale(0.5, 0.5);
					angerbonus -= 5;
				}
				else if (angerbonus <= 5)
				{
					rageitem.amount = angerbonus;
					rageitem.A_SetScale(0.5, 0.5);
					break;
				}
			}
		}
		
		if (willBonus > 0) {
			let healitem = GHAGHealEssence(thing.A_DropItem("GHAGHealEssence", 1));
			healitem.amount = willBonus;
			if (WolfensteinSS(thing)) healitem.amount = 350;
			healitem.A_ChangeVelocity(random(-2, 2), random(-2, 2), random(-2, 2), CVF_REPLACE);
			healitem.A_SetPitch(random(60, 80));
			healitem.A_SetAngle(random(1, 360));
		}
	}
	
	override void worldtick()
	{
		if (gardie)
		{
			//change rage value
			//set to any value aside from -1
			Cvar rage = Cvar.findCvar("ghagrage");
			if (rage) {
				if (rage.getInt() != -1) 
				{
					Gardie.RageValue = rage.getInt();
					rage.resetToDefault();
				}
			}
			
			//change the odds of a demon spawning as shiny
			cvar c_shinyodds = Cvar.findCvar("shinyodds");
			if (c_shinyodds) {
				if (c_shinyodds.getInt() != -1) {
					shinyodds = c_shinyodds.getInt();
					c_shinyodds.setInt(-1);
				}
			}
			
			/*cvar charon = Cvar.findCvar("ghagcharon");
			if (charon) {
				bool mode = charon.getBool();
				Gardie.charonmode = mode;
			}*/
		}
	}
	
	override void PlayerSpawned(PlayerEvent player) 
	{
		Gardie = GHAGGardevoir(players[player.PlayerNumber].mo);
	}
	
	int numSecrets;
	int weaponspawned;
	
	override void WorldLoaded(WorldEvent event)
	{
		gardie = GHAGGardevoir(players[consoleplayer].mo);
	
		if (gardie) {
			gardie.initFloatWeapons();
			gardie.updateWeapons = true;
		}
	}
	
	void SpawnBonusItem(Vector3 _pos, bool _gun = false)
	{
		gardie = GHAGGardevoir(players[consoleplayer].mo);
	
		int limit = GameInfo.GameType == 1 ? 4 : 2;
		if (!_gun) Actor.spawn('GHAGRageCandyBar', _pos);
		else
		{
			Array<name> gunlist;
			gunlist.clear();
			
			name winner = 'GHAGRageCandyBar';
			
			if (gardie.countInv('GHAGPistol'))
			{
				if (gardie.countInv('GHAGPistolOverlay') < 4) {
					gunlist.push('GHAGSecretPistol');
				}
			}
			
			if (gardie.countInv('GHAGShotgun'))
			{
				if (gardie.countInv('GHAGShotgunOverlay') < 4) 
				{
					gunlist.push('GHAGSecretShotgun');
				}
			}
			
			if (gardie.countInv('GHAGNailgun'))
			{
				if (gardie.countInv('GHAGNailgunOverlay') < 4)
				{
					gunlist.push('GHAGSecretNailgun');
				}
			}
			
			if (gardie.countInv('GHAGPlasmaRifle'))
			{
				if (gardie.countInv('GHAGPlasmaOverlay') < 4) 
				{
					gunlist.push('GHAGSecretPlasma');
				}
			}
			
			if (gardie.countInv('GHAGSuperRailgun'))
			{
				if (gardie.countInv('GHAGSuperRailgunOverlay') < 4) 
				{
					gunlist.push('GHAGSecretRailgun');
				}
			}
			
			if (gunlist.size() != 0) winner = gunlist[random(0, gunlist.size() - 1)];
			let item = Actor.spawn(winner, _pos);
			item.A_ChangeVelocity(random(-4, 4), random(-4, 4), random(-4, 4), CVF_REPLACE);
		}
	}
}

Class DummyActor : Actor
{}