class SHGreenZomb : DoomImp
{
	Default
	{
		Translation "64:73=152:159", "74:79=9:12", "61:63=126:127", "175:191=9:12";
		
		HitObituary "%o was mauled to death.";
		Obituary "%o was killed at range by a melee enemy (?????)";
		
		SeeSound "shlowimp/sight";
		PainSound "shlowimp/pain";
		DeathSound "shlowimp/death";
		ActiveSound "shlowimp/active";
	}
	
	int minDmg;
	int maxDmg;
	property MinDmg : minDmg;
	property MaxDmg : maxDmg;
	
	States
	{
		Missile:
		Goto See;
		
		Melee:
		TROO EF 6 A_FaceTarget;
		TROO G 8 A_ZombAtk;
		Goto See;
	}
	
	action void A_ZombAtk() //idk what im doing but this is going here :):):)
	{
		A_CustomMeleeAttack(random(invoker.minDmg,invoker.maxDmg),"shlowimp/melee","shlowimp/wiff","Melee",1);
	}
}


class DoomAfrit : FireDemon
{
	Default
	{
		Health 50;
	}
	
	States
	{
	Spawn:
		FDMN X 5 Bright Nodelay A_UnSetInvulnerable; //always hated waiting for them to hatch
		FDMN EFG 10 Bright A_Look;
		Goto Spawn+1;
	See: //faster wakeup (~1/2)
		FDMN E 4 Bright;
		FDMN F 3 Bright;
		FDMN G 2 Bright;
		FDMN F 4 Bright;
		FDMN E 3 Bright;
		FDMN G 3 Bright A_FiredRocks;
		FDMN HI 2 Bright;
		FDMN J 2 Bright;
	Missile:
		FDMN K 3 Bright A_FaceTarget;
		FDMN KK 7 Bright A_FiredAttack2; //only fires 2
		Goto Chase;
	}
	
	action void A_FiredAttack2()
	{
		if (target == null)	return;
		Actor mo = SpawnMissile (target, "DoomFDMissile");
		if (mo) A_StartSound ("FireDemonAttack", CHAN_BODY);
	}
}

class DoomFDMissile : FireDemonMissile //make it a bit closer to the imp in power
{
	Default
	{
		Radius 6;
		Height 8; //doomimpball dimensions
		Damage 3; //doomimpball damage
	}
}

/*
class BrokenBottle : Actor
{
	Default
	{
		Height 4;
	}
	
	States
	{
	Spawn:
		BOTK A -1;
		Stop;
	}
}
*/

class CeilingLamp : Actor
{
	Default
	{
		+SPAWNCEILING;
		+CEILINGHUGGER;
		Gravity -1;
		Height 1;
	}
	
	int lightTime;
	bool light;
	int flicker;
	
	States
	{
	Spawn:
		LAMP ABCD 4;
		Loop;
	
	Lit2: //older version w/dynamic light. holdover from an earlier version of the map
		LAMP ABCD 4
		{
			if (!lightTime)
			{
				if (!light)
				{
					lightTime = !flicker? random(1,25) * 2 : 1;
					if (flicker) flicker--;
					A_TheLight();
					light = 1;
					bBright = 1;
				} else
				{
					lightTime = 1;
					A_RemoveLight("fitnessgrampacertest");
					light = 0;
					bBright = 0;
					if (!flicker && random(0,3) == 3) flicker = random(1,3);
				}
			}
			else lightTime--;
		}
		Loop;
	}
	
	action void A_TheLight()
	{
		A_AttachLight("fitnessgrampacertest",DynamicLight.PointLight,"White",128,128,0,(0,0,-8));
	}
}






class MonsterRise : Actor
{
	Default
	{
		MonsterRise.ThingName 'Demon'; //idk man i dont want to make it abstract, im tired
		MonsterRise.Depth 0; //additional depth added on top of sprite height
		MonsterRise.RiseSpeed 3;
		
		Health 1;
		
		+COUNTKILL;
		+SHOOTABLE;
		+ISMONSTER;
		+INVULNERABLE;
		-NOBLOOD;
		
		//$Arg0 Alert radius
		//$Arg0Type 0
		//$Arg1 Alert FOV
		//$Arg1Type 0
		//$Arg2 Face target?
		//$Arg2Type 0
		//$Arg3 Rise speed
		//$Arg3Type 0
		
		//$Sprite ROCCA0
	}
	
	string user_MonsterType;
	
	Class<Actor> theThing;
	
	Name thingName;
	property ThingName : thingName;
	
	int zOff;
	property Depth : zOff;
	
	int spd;
	property RiseSpeed : spd;
	
	int maxhp;
	
	States
	{
	Spawn:
		TNT1 A 0 Nodelay A_InitName;
	Look:
		TNT1 A 1 A_LookEx(LOF_NOSOUNDCHECK,0,args[0],0,args[1] ? args[1] : 360);
		Loop;
	See:
		TNT1 A 0 A_InitStuff;
	Rise:
		#### # 1 A_Rising;
		Loop;
	
	Death:
	DeathX:
	End:
		#### # 1
		{
			A_SpriteOffset(0,0);
		
			let thingy = Spawn(invoker.theThing,invoker.pos,ALLOW_REPLACE);
			if(thingy)
			{
				thingy.angle = invoker.angle;
				thingy.A_DamageSelf(invoker.maxhp-invoker.health);
				A_ChangeCountFlags(0);
				Destroy();
			}
		}
		Loop;
	}
	
	action void A_InitName()
	{
		if (invoker.user_MonsterType)
		{
			invoker.thingName = invoker.user_MonsterType;
			invoker.theThing = invoker.thingName;
			let r = GetDefaultByType(invoker.theThing).radius;
			let h = GetDefaultByType(invoker.theThing).height;
			A_SetSize(r,h);
			
			invoker.translation = GetDefaultByType(invoker.theThing).translation;
		}
	}
	
	action void A_InitStuff()
	{		
		invoker.bInvulnerable = 0;
		invoker.bSolid = 1;
		
		invoker.theThing = invoker.thingName;
		
		invoker.translation = GetDefaultByType(invoker.theThing).translation;

		
		state theState = GetDefaultByType(invoker.theThing).spawnstate;
		TextureID riseSprId = theState.GetSpriteTexture(0);
		Name riseSprite = TexMan.GetName(riseSprId);
		
		invoker.health = GetDefaultByType(invoker.theThing).health;
		invoker.maxhp = GetDefaultByType(invoker.theThing).health;
		
		invoker.sprite = GetSpriteIndex(riseSprite);
		
		invoker.zOff += TexMan.CheckRealHeight(riseSprID) + random(1,5)*15;
		invoker.spd = Round((invoker.args[3] ? invoker.args[3] : invoker.spd) / FRandom(1.,1.5));
		
		A_StartSound("Rocks");
	}
	
	virtual void DoParticles()
	{
		double ang = FRandom(0.,360.);
		Name n = random(0,1) == 0 ? 'ROCCA0' : 'ROCCB0';
		A_SpawnParticleEx("",TexMan.CheckForTexture(n),0,SPF_RELVEL|SPF_RELPOS,35,16,ang,2,0,0,2,0,5,0,0,-1);

	}
	
	action state A_Rising()
	{
		if (invoker.args[2]) A_FaceTarget();
		if (invoker.zOff <= 0) return FindState("End");
		invoker.DoParticles();
		A_SpriteOffset(0,invoker.zOff);
		invoker.zOff -= invoker.spd;
		return null;
	}
}

class MonsterRiseImmediate : MonsterRise
{
	States
	{
	Spawn:
		TNT1 A 0;
		Goto See;
	}
}


class DemonRise : MonsterRiseImmediate
{
	Default
	{
		MonsterRise.ThingName 'Demon';
		MonsterRise.Depth 20;
	}
}

class ImpRise : MonsterRiseImmediate
{
	Default
	{
		MonsterRise.ThingName 'shgreenzomb';
		MonsterRise.Depth 10;
	}
}

class CorpseRevive : Zombieman
{
	Default
	{
		Tag "Fake Corpse";
		SeeSound "";
	}

	bool iSeeYou;

	States
	{
	Spawn:
	POSS L 1 A_LookEx(LOF_NOSOUNDCHECK,0,0,0,10);
	Loop;
	
	See:
	#### # 0 {if (!iSeeYou) {
				iSeeYou = 1;
				return ResolveState("Raise2");
				}
				return findstate(null);
			}
	RealSee:
	POSS AABBCCDD 4 A_Chase;
	Loop;
	
	Raise2:
	POSS L 20;
	TNT1 A 0 A_StartSound("vile/raise");
	Goto Raise;
	}
}

class SpookyAxeWeap : DoomWeapon
{
	Default
	{
		Weapon.SlotNumber 1;
		Weapon.SelectionOrder 3699;
		AttackSound "fireaxe/hit";
		Inventory.PickupMessage("Picked up the fire axe.");
		Inventory.PickupSound "";
		
		Height 32;
		
		+WEAPON.NOALERT;
		
		//add funny pickup sound
	}
	
	States
	{
	Spawn:
		FAXX B -1;
		Stop;
	
	Select:
		FFAX A 1 A_Raise;
		Loop;
	Deselect:
		FFAX A 1 A_Lower;
		Loop;
	
	Ready:
		FFAX A 1 A_WeaponReady;
		Loop;
	
	Fire:
		FFAX B 2 A_WeaponOffset(0,32);
		FFAX C 2;
		FFAX C 2 A_WeaponOffset(0,36);
		FFAX C 3 A_WeaponOffset(0,50);
		TNT1 A 0 A_Refire;
		Goto Hit;
	Hold:
		FFAX C 1;
		/* this was a bad idea
		{
			let p = playerpawn(invoker.owner);
			p.forwardmove1=0.25;
			p.forwardmove2=0.125;
			p.sidemove1=0.25;
			p.sidemove2=0.125;
			p.viewbob = 0.25;
		}
		*/
		TNT1 A 0 A_Refire;
	Hit:
		TNT1 A 0 A_StartSound("fireaxe/mis",CHAN_WEAPON);
		FFAX IH 1 A_WeaponOffset(20,0);
		FFAX G 1 A_CustomPunch(17,1,CPF_NOTURN,"BulletPuff",96);
		FFAX FE 1;
		TNT1 A 3
		{
			let p = playerpawn(invoker.owner);
			p.forwardmove1=1;
			p.forwardmove2=1;
			p.sidemove1=1;
			p.sidemove2=1;
			p.viewbob = 1;
		}
		TNT1 A 0 A_WeaponOffset(0,58);
		FFAX A 3 A_Refire("Fire");
		TNT1 A 0 A_WeaponOffset(0,50);
		FFAX A 2 A_Refire("Fire");
		TNT1 A 0 A_WeaponOffset(0,42);
		FFAX A 2 A_Refire("Fire");
		TNT1 A 0 A_WeaponOffset(0,30);
		FFAX A 2 A_Refire("Fire");
		Goto Ready;
	}
}


/*
class SpookWeapon : DoomWeapon
{
	Default
	{
		Weapon.AmmoUse1 0;
		Weapon.AmmoUse2 0;
		Weapon.AmmoGive1 0;
		Weapon.AmmoGive2 0;
		Weapon.SlotNumber 2;
		+WEAPON.NOALERT;
		+WEAPON.ALT_AMMO_OPTIONAL;
		
		SpookWeapon.AllowRefire 1;
	}
	int aimReFire;
	bool AllowRefire;
	property AllowRefire : AllowRefire;
	
	float speedCache;
	
	States
	{
	Deselect:
	Ready:
	Fire:
	Spawn:
        TNT1 A 0 A_Print("??? Weapon reached unimplemented state ???");
        Stop;
    Select:
		TNT1 A 0 A_WeaponOffset(0.0, 32.0);
        TNT1 A 0 A_Raise;
        Wait;
	
	AltFire:
	StartAim:
	AimReady:
	AimFire:
	EndAim:
	Goto Ready;
	
	}
	
	protected action state A_AimReady()
	{
		if (player == null) return ResolveState(null);
		
		let inp = GetPlayerInput(MODINPUT_BUTTONS);
		
		if(inp&BT_ATTACK && (!invoker.aimReFire || invoker.AllowRefire))
		{
			if (invoker.owner.CountInv(invoker.ammotype1) >= invoker.ammouse1)
			{
				invoker.owner.TakeInventory(invoker.ammotype1,invoker.ammouse1);
				invoker.aimReFire = true;
				return invoker.FindState("AimFire");
			}
		}
		if (!(inp&BT_ATTACK)) invoker.aimReFire = false;
		
		if(!(inp&BT_ALTATTACK))
		{
			return invoker.FindState("EndAim");
		}
		
		return ResolveState(null);
	}
	
	protected action state A_StartAim(int spd = 24, bool inst = false)
	{
		if (player == null) return ResolveState(null);
		
		//SetPlayerProperty(0, 1, PROP_FROZEN);
		let p = playerpawn(invoker.owner);
		p.forwardmove1=0.25;
		p.forwardmove2=0.125;
		p.sidemove1=0.25;
		p.sidemove2=0.125;
		p.viewbob = 0.25;
		
		let psp = player.GetPSprite(PSP_WEAPON);
		
		psp.y -= spd;
		if (psp.y < WEAPONTOP || inst) psp.y = WEAPONTOP;
		
		if (psp.y > WEAPONTOP) return ResolveState(null);
		
		return invoker.FindState("AimReady");
	}
	
	protected action state A_EndAim(int spd = 24, bool inst = false)
	{
		if (player == null) return ResolveState(null);
		
		let psp = player.GetPSprite(PSP_WEAPON);
		
		psp.y += spd;
		
		if (psp.y < WEAPONBOTTOM && !inst) return ResolveState(null);
		
		//SetPlayerProperty(0, 0, PROP_FROZEN);
		let p = playerpawn(invoker.owner);
		p.forwardmove1=1;
		p.forwardmove2=1;
		p.sidemove1=1;
		p.sidemove2=1;
		p.viewbob = 1;
		
		return invoker.FindState("Ready");
	}
}

class SpookyPistol : SpookWeapon
{
	Default
	{
		Weapon.AmmoType1 "Clip";
		Weapon.AmmoUse1 1;
		Weapon.AmmoGive 5;
		Weapon.SlotNumber 2;
		
		Tag "Spooky Pistol";
		
		SpookWeapon.AllowRefire 0;
	}
	
	States
	{
		Spawn:
		PIST
		A -1;
		Stop;
		
		Select:
		TNT1 A 0 {invoker.weaponscalex = 1;}
		PUNG B 1 A_Raise;
		Loop;
		Deselect:
		PUNG B 1 A_Lower;
		Loop;
		
		Fire:
		Goto Ready;
		
		Ready:
		TNT1 A 0 {invoker.weaponscalex = 1;}
		PUNG B 1 A_WeaponReady;
		Loop;
		
		AltFire:
		TNT1 A 0 {invoker.weaponscalex = -1;}
		TNT1 A 0 A_ZoomFactor(1.2);
		PISG A 0 Offset(0,WEAPONBOTTOM);
		StartAim:
		PISG A 1 A_StartAim;
		Loop;
		
		AimReady:
		PISG A 1 A_AimReady;
		Loop;
		
		AimFire:
		PISG B 6
		{
			A_FireBullets (0, 0, 1, 12, "BulletPuff",FBF_NORANDOM);
		    A_StartSound("weapons/pistol", CHAN_WEAPON);
		    A_GunFlash();
		}
		PISG C 3;
		PISG B 2;
		Goto AimReady;
		
		EndAim:
		TNT1 A 0 A_ZoomFactor(1);
		PISG A 1 A_EndAim;
		Loop;
		
		Flash:
		PISF A 3 Bright A_Light1;
		Goto LightDone;
		PISF A 3 Bright A_Light1;
		Goto LightDone;
	}
}

class SpookyShotgun : SpookWeapon
{
	Default
	{
		Weapon.AmmoType1 "Shell";
		Weapon.AmmoUse1 1;
		Weapon.SlotNumber 3;
		Weapon.AmmoGive 1;
		
		Tag "Spoooky Shotgun";
	}
	
	States
	{
		Spawn:
		SHOT A -1;
		Stop;
	
		Select:
		SHTS A 1 A_Raise;
		Loop;
		Deselect:
		SHTS A 1 A_Lower;
		Loop;
		
		Spawn:
		SHOT A -1;
		Stop;
		
		Fire:
		Goto Ready;
		
		Ready:
		SHTS A 1 A_WeaponReady;
		Loop;
		
		AltFire:
		TNT1 A 0 A_ZoomFactor(1.2);
		StartAim:
		SHTS AAAA 1 A_WeaponOffset(-11,-2,WOF_ADD);
		TNT1 A 0 A_WeaponOffset(0,32);
		SHTG A 1 A_StartAim(0,1);
		Loop;
		
		AimReady:
		SHTG A 1 A_AimReady;
		Loop;
		
		AimFire:
		SHTG A 6
		{
			A_FireBullets (5.6, 0, 7, 15,"BulletPuff",FBF_NORANDOM);
			A_StartSound("weapons/shotgf", CHAN_WEAPON);
			A_GunFlash();
		}
		SHTG B 3;
		SHTG BC 5;
		SHTG D 4;
		SHTG CB 5;
		SHTG A 3;
		Goto AimReady;
		
		EndAim:
		TNT1 A 0 A_ZoomFactor(1);
		TNT1 A 0 A_WeaponOffset(-44,24);
		SHTS AAAA 1 A_WeaponOffset(11,2,WOF_ADD);
		SHTG A 1 A_EndAim(0,1);
		Loop;
		
		Flash:
		SHTF A 2 Bright A_Light1;
		SHTF B 2 Bright A_Light2;
		Goto LightDone;
	}
}
*/