// *** MODIFIED BY CHEBMASTER
// I mark most important places modified by me with //***Che -- unless I forget to.





/*
//***Che: this was never used anywhere, commenting it out
Actor Gibs_General
{
...
*/

//===========================================================================
//
// Lost Soul
//
//===========================================================================

// NOTE: unlike all other monsters, lost soul's sfest checks are entirely clientside,
//   the number of lost souls having flames is capped at 100 without any ordering.

ACTOR LostSoulImPatience: Inventory
{
	// without this they often stuck in an infinite failed retreat loop if there is not enough space
	inventory.maxamount 50
}

ACTOR ZandronumLostSoul
{
	//***Che radius, height and maxdropoffheight (n/a for flying ones) MUST be kept consistent with FBD_TrySpawn in FBD_CORE.acs!
	
	//***Che: cross-mod hardening: see ACTOR TehLostSoul: FBD_LostSoul Replaces LostSoul {} in Doom_Replacements.txt
	
	Game Doom
	SpawnID 110
	Health 100
	Radius 16
	Height 56
	Mass 50
	Speed 8
	Damage 3
	PainChance 256
	Monster
	+FLOAT +NOGRAVITY +MISSILEMORE +DONTFALL +NOICEDEATH
	AttackSound "skull/melee"
	PainSound "skull/pain"
	DeathSound "skull/death"
	ActiveSound "skull/active"
	RenderStyle SoulTrans
	Obituary "$OB_SKULL"
	States
	{
	Spawn:
		SKUL AB 10 BRIGHT A_Look
		Loop
	See:
		SKUL AB 6 BRIGHT A_Chase
		Loop
	Missile:
		SKUL C 10 BRIGHT A_FaceTarget
		SKUL D 4 BRIGHT A_SkullAttack
		SKUL CD 4 BRIGHT
		Goto Missile+2
	Pain:
		SKUL E 3 BRIGHT
		SKUL E 3 BRIGHT A_Pain
		Goto See
	Death:
		SKUL F 6 BRIGHT
		SKUL G 6 BRIGHT A_Scream
		SKUL H 6 BRIGHT
		SKUL I 6 BRIGHT A_NoBlocking
		SKUL J 6
		SKUL K 6
		Stop
	}
}

//***Che: cross-mod hardening:
// ACTOR TehLostSoul: FBD_LostSoul Replaces LostSoul {} , see below!
// 1. code won't fall to buggy pieces when GZDoom tries its ham-handed so-called "fix"
//    for identical class names (say, we run FBD on top of Project Brutality or BD22)
// 2. overrides other mod's overrides with FBD monsters. 


ACTOR FBD_LostSoul: ZandronumLostSoul 17623
{
	//$category "FBD Monsters"
	Game Doom
	
	//$Sprite SKULC1
	
	Health 100
	Radius 16
	Height 32
	Mass 50
	Speed 12
	DeathHeight 4
	BurnHeight 0
	Damage (random(15,15))
	PainChance 255
	PainChance "Kick", 255
	damagefactor "GibRemoving", 0.0 damagefactor "HangingHook", 0
	
	//***Che
	PainChance "Avoid", 0 //255
	DamageFactor "Avoid", 0.0
	//damagefactor "Fire", 0 
	// 75% resistance instead of outright immunity
	damagefactor "Fire", 0.25
	damagefactor "Flames", 0.25
	PainChance "Fire", 0
	PainChance "Flames", 0
	
	damagefactor "Saw", 4.0 damagefactor "Cut", 4.0
	Monster
    +NOBLOOD
	damagefactor "Blood", 0.0 damagefactor "BlueBlood", 0.0 damagefactor "GreenBlood", 0.0
    damagefactor "Fatality", 5.0 damagefactor "PussyGrab", 50.0
	damagefactor "TeleportRemover", 0.0
	DamageFactor "CauseSplash", 0.0 DamageFactor "CauseObjectsToSplashSlime", 0.0 DamageFactor "CauseObjectsToSplashNukage", 0.0
	DamageFactor "CauseObjectsToSplashBlood", 0.0 DamageFactor "CauseObjectsToSplashLava", 0.0
	RenderStyle Normal
    
	bloodcolor none // gzdoom reports this as invalid hex value "no"
	+NOBLOODDECALS
	
	+FLOAT +NOGRAVITY +DONTFALL +NOICEDEATH
	+FORCEXYBILLBOARD
	
	//***Che: playing attack sound manually when we *intent* to attack 
	// -- which could be as the start of backpedaling, if we are too close
	// Since A_SkullAttck plays the attack sound, we have to set it to none
	// to avoid it playing two times per attack.
	AttackSound None //"skull/melee"
	
	PainSound "skull/pain"
	DeathSound "LSOD"
	ActiveSound "skull/active"
	Obituary "$OB_SKULL"
	//MinMissileChance 50
	BloodType "LostSoulBlood"
	damagefactor "ExplosiveImpact", 3.0
	
	//***Che
	damagefactor "FriendlyExplosion", 3.0	
	damagefactor "Shrapnel", 3.0
	damagefactor "Explosives", 3.0 // revenant
	Tag "$LOST_SOUL"
    Alpha 1
	
	
	var int user_head_tid;
	var int user_head_type; // DEPRECATED 9 Lost soul's flames (unique, non-shootable)
	//P.S. And now it's back with vengeance, using headbox mechanics serverside
	//  to control the number of particle SFX clientside.
	// basically, a ghost headbox that launches a clientside script to start flames 
	// and launches another on despawn to stop clientside flames!
	var int user_head_rel;
	var int user_head_scale;
	var int user_head_xyzf; /* 
		a packed value: 
		bits 0..7 =x+128, clamped to -128..127
		bits 8..15 =y+128, clamped to -128..127
		bits 16..23 =z, clamped to 1..255
		bit 29 is a command to assume an unique TID, used in monster-on-monster headshotting
		A zero value is a command to terminate
	*/	
	var int user_sleeping;
	var int user_item_no;
	var int user_make_flames;
	//var int user_serverside_sfchk;
	
	var int user_dont_scream; // DOESN'T FUCKING WORK, still hisses twice!
	
	DamageFactor "Argent", 0.0
	
	var int user_have_trails;
	var int user_is_charging;
	
	PainChance "Bullet792", 100 // machineguns and snip[er rifles not aimed
	PainChance "SniperBullet", 120 // sniper rifle aimed	
	
	damagefactor "Killme", 1.0 // AOE inflicted by captured marines
	PainChance "Killme", 255

	damagefactor "Ice", 2.0
	PainChance "Ice", 255
	
	States
	{
/*
	//***Che: this gameplay change by Mark-sensei was an abject failure, lost souls being dodgy
		turned them into OP nuisances absolutely *unfun* to fight against, 
		rivaling the old school Cliff Racers
		(those who played Morrowind during the early 2000s should know what I am talking about)
		
	So, I NERFED THE FUG out of this monster.

	Lost soul must be *dumb* because it is already
		A) numerous
		B) tough
		C) flying
		
		Pain.Avoid: // inflicted by the tracer "Alerter" fired by: the vanilla bfg9000; the revenant launcher; the minigun when beginning to spin up; the rocket launcher.  
			TNT1 A 0
			TNT1 A 0 A_Jump(256, "AvoidLeft", "AvoidRight")
			Goto AvoidLeft
		AvoidLeft:
			LSOL B 1 A_FaceTarget
			TNT1 A 0 ThrustThing(angle*256/360+192, 15, 0, 0)
			LSOL B 5 A_FaceTarget
			Goto Missile
		AvoidRight:
			LSOL B 1 A_FaceTarget
			TNT1 A 0 ThrustThing(angle*256/360+64, 15, 0, 0)
			LSOL B 5 A_FaceTarget
			Goto Missile
*/			
/*
	//***Che moved the particle management to the ACS side
*/			
		StartupThenMissile:
			// The lost souls are peculiar, the game engine often forces them into missile state
			// thus bypassing the spawn state.
			// So my Missile state checks if initialized and if not redirects here
			LSOL A 0 ACS_NamedExecuteWithResult("FBD_RunMonster", 9) // lost soul's virtual headbox
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 24)
			Goto MissileAfterParticles
		Spawn:
			LSOL A 0 NODELAY ACS_NamedExecuteWithResult("FBD_RunMonster", 9) // lost soul's virtual headbox
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 24)
			Goto Stand
/*

	DO NOT FORGET
	ACTOR InstaAggroMinionLostSoul: FBD_LostSoul 
	declared in DECORATE.fbd_chebskies
	
	-- it has its own Spawn state that creates the flame particles

*/			
		
		Stand:
			"----" A 0
			//TNT1 A 0 A_JumpIfInventory("IAmSfestMonster", 1, "StandSfest") // this only happens on the client, mind you
			//TNT1 A 0 ACS_NamedExecuteWithResult("FrankenHeadAdjustPosition", 0, 0, 24)
/*
	How could this stupid Cheb be so STUPID to forget the most basic fact of headboxes being SERVERSIDE ONLY?
	I blame COVID that had damaged my aging brain.
	( wasn't as bad as some people got but still would not have survived without hospital stay and oxygen apparatus
	 -- I would have been long dead and gone by now and there would have been no Chebskies and no FBD)
*/			
			
			
			"----" A 0 A_CheckFlag("SKULLFLY", "GotoCharging")
			LSOL A 10 BRIGHT A_Look
			Loop
		
		GotoCharging:
			"----" A 0
			Goto Charging
			
		Idle: // without this state, the game engine puts it into its Spawn state when it loses target 
				//-- and that wrecks havok with the init scripts!
			"----" A 0
			"----" A 0 A_JumpIf(user_is_charging, "SlamCustom")
			Goto Stand		
		
		See:
			"----" A 0
			"----" A 0 A_TakeInventory("MaxLostSoulRange", 30)
			"----" A 0 A_ChangeFlag("NOPAIN", 0)			

		SeeContinue:	
		
			"----" A 0 A_CheckFlag("SKULLFLY", "GotoCharging")
			
			"----" A 0 A_StopSound(CHAN_VOICE) // shared code with Hater, stop screeching
			
			"----" A 0 A_JumpIf(user_is_charging, "SlamCustom")
			
			LSOL A 2 BRIGHT A_Chase("", "")
			//***Che: no dodging in melee!
			LSOL A 2 BRIGHT A_Chase
			
			// copy-pasted to lessen the headbox script calls frequency:
			LSOL A 2 BRIGHT A_Chase("", "")
			LSOL A 2 BRIGHT A_Chase
			LSOL A 2 BRIGHT A_Chase("", "")
			LSOL A 2 BRIGHT A_Chase
			LSOL A 2 BRIGHT A_Chase("", "")
			LSOL A 2 BRIGHT A_Chase
			
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 24)
			Loop
		
		Missile:
			TNT1 A 0
			// lost souls are peculiar, the game engine often forces them into missile state
			// thus bypassing the spawn state
			TNT1 A 0 A_JumpIf(!user_item_no, "StartupThenMissile") // does nothing on the client
			//TNT1 A 0 A_JumpIf(!user_have_trails && user_make_flames, "MakeParticlesThenMissile")
		MissileAfterParticles:
			
			// prevents hissing several times as it moves back and forth
			// trying to gain a proper distance for an attack
			
			TNT1 A 0 A_JumpIfInTargetInventory("GoFatality", 1, "WaitTargetsFatalityOut")
			
			TNT1 A 0 A_JumpIf(user_dont_scream, 2)
			TNT1 A 0 A_PlaySound("skull/melee", CHAN_VOICE)
			TNT1 A 0 A_SetUserVar("user_dont_scream", 1)
		MissileContinue:	
			TNT1 A 0 A_JumpIfCloser(160, "RetreatThenMissile")
			TNT1 A 0 A_takeInventory("LostSoulImPatience", 10)
			TNT1 A 0 A_ChangeFlag("NOPAIN", 1)
			TNT1 A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 24)
			LSOL B 3 BRIGHT A_FaceTarget
			LSOL D 0 BRIGHT A_SkullAttack // the cause of the double hiss: this *does* incorporate making the attack sound!
			TNT1 A 0 A_SetUserVar("user_dont_scream", 0)
			goto Charging
			
		ChargeImpatiently:
			TNT1 A 0 A_ChangeFlag("NOPAIN", 1)
			LSOL B 3 BRIGHT A_FaceTarget
			LSOL D 0 BRIGHT A_SkullAttack
			TNT1 A 0 A_SetUserVar("user_dont_scream", 0)
			goto Charging

		Charging:
			TNT1 A 0 A_SetUserVar("user_is_charging", 1)
			TNT1 A 0 A_takeInventory("LostSoulImPatience", 100)
			LSOL BBBB 2 BRIGHT
			TNT1 A 0 A_JumpIfInventory("MaxLostSoulRange", 10, "See")
			TNT1 A 0 A_giveInventory("MaxLostSoulRange", 1)
			Loop
		
		WaitTargetsFatalityOut:
//Zandronum doesn't support this state
//		Slam: // collided with another actor
		SlamCustom:
			LSOL A 0 A_SetUserVar("user_is_charging", 0)
			LSOL A 0 A_Recoil(5)
			LSOL AAAAAAAA 2
			TNT1 A 0 A_SetAngle(angle + random(-45, 45))
			
		WanderAfterSlam:	
			LSOL AAAAAAAA 2 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			LSOL A 0 A_Wander
			LSOL A 2 A_Look
			Goto See

		RetreatThenMissile:
			TNT1 A 0
			TNT1 A 0 A_giveInventory("LostSoulImPatience", 2)
			TNT1 A 0 A_JumpIfInventory("LostSoulImPatience", 15, "WiggleAround")
			TNT1 A 0 A_Recoil(3)
			LSOL B 1 A_FaceTarget
			LSOL B 1 A_Recoil(3)
			Goto MissileContinue
		WiggleAround:	
			LSOL B 1 A_Chase ("","", CHF_FASTCHASE) // hexen boss dodging
			TNT1 A 0 A_Recoil(5)			
			LSOL B 1 A_Chase ("","", CHF_FASTCHASE) // hexen boss dodging
			TNT1 A 0 A_Recoil(5)
			TNT1 A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 24)
			TNT1 A 0 A_JumpIfInventory("LostSoulImPatience", 35, "ChargeImpatiently")
			Goto MissileContinue
		
		Pain.Ice:
			"----" A 20 A_Pain
		Pain:
			TNT1 A 0
			TNT1 A 0 A_SetUserVar("user_is_charging", 0) // to prevent idle wandering when charge is interrupted with pain
			TNT1 A 0 A_SetUserVar("user_dont_scream", 0)
			LSOL C 3 BRIGHT
			TNT1 A 0 A_Jump (128, 1)
			Goto Avoid
			LSOL C 1 BRIGHT A_Pain
			Goto See
			
		Pain.Bullet792:
		Pain.SniperBullet:			
		Pain.Minigun:
			TNT1 A 0
			// does *not* prevent wandering when charge is interrupted with pain -- thus making the 7.92 weapons effectively stun it!
			TNT1 A 0 A_SetUserVar("user_dont_scream", 0)
			TNT1 AA 0 A_CustomMissile ("SmallLSPart1", 0, 0, random (0, 360), CMF_AIMDIRECTION, random (0, 360))
			TNT1 AA 0 A_CustomMissile ("SmallLSPart3", 0, 0, random (0, 360), CMF_AIMDIRECTION, random (0, 360))
			LSOL C 3 BRIGHT
			TNT1 A 0 A_Jump (128, 1)
			Goto Avoid
			LSOL C 1 BRIGHT A_Pain
			Goto See		
			
		Avoid:
			NULL A 0 A_FaceTarget
			LSOL B 6 A_FastChase
			NULL A 0 A_FaceTarget
			LSOL B 6 BRIGHT A_FastChase
			NULL A 0 A_FaceTarget
			LSOL B 6 BRIGHT A_FastChase
			NULL A 0 A_FaceTarget
			LSOL B 6 BRIGHT A_FastChase

			Goto Missile

		//Death.Fatality:
		Death.PussyGrab:
			TNT1 A 0
			
			TNT1 A 0 A_Pain
			
			TNT1 A 0 A_JumpIfIntargetInventory("FistsSelected", 1, 1)
			Goto Death

			TNT1 A 0 A_GiveToTarget("LostSoulFatality", 1)
			TNT1 A 30 A_ChangeFlag("CORPSE", 0) // without at least 8 tics delay, the bonus drop script runs ownerless
			TNT1 A 0
			Stop
		Death:
			TNT1 A 0
			LSOL F 4 BRIGHT A_NoBlocking

			EXPL AAAAA 0 A_CustomMissile ("FireBallExplosionFlamesMedium", 32, 0, random (0, 360), 2, random (0, 360))

			// this apawns *most* of the particle spam, or nothing at all if the load balancer says no
			TNT1 A 0 A_SpawnItemEx ("LostSoulExplode", 0,0,0, 0,0,0, 0,SXF_NOCHECKPOSITION,0)
			
			LSOL G 0 BRIGHT A_Scream
			
			TNT1 A 0
			LSOL HI 0
			TNT1 A 30 A_ChangeFlag("CORPSE", 0)
			Stop

		Pain.KillMe: 
		Pain.Taunt: // not enrageable
			TNT1 A 0
			TNT1 A 0 HealThing(1)
			Goto Missile
		Death.KillMe:
		Death.Taunt:
			Goto Death
	}
}



ACTOR InstaAggroMinionLostSoul: FBD_LostSoul {
	States {
		Spawn:
			LSOL A 0
			LSOL A 0 NODELAY ACS_NamedExecuteWithResult("FBD_RunMonster", 9) // lost soul's virtual headbox
			"----" A 0 ACS_NamedExecuteWithResult("AdjustHeadboxMkII", 0, 0, 24)
			Goto ChargeImpatiently
	}
}

////// LOSTSOUL BODY PARTS //////


ACTOR LSPart1
{
    Radius 2
    Height 2
    Speed 7
	Mass 3
	BounceFactor 0.4
	+DOOMBOUNCE
    +NOBLOCKMAP
	+MISSILE
    +NOTELEPORT
    +DONTSPLASH
    +MOVEWITHSECTOR
    +CLIENTSIDEONLY
	+THRUACTORS
    Scale 0.7
    States
    {
		Spawn:
			TNT1 A 0
			
			//***Che: what the fug?
			//TNT1 A 0 Thing_ChangeTID(0,394)
			
			TNT1 A 0 A_Jump(128,9)
			LGI1 ABCDEFGH 2
			wait
			LGI1 HGFEDCBA 2
			wait
		Death:
			TNT1 A 0
			TNT1 A 0 A_JumpIfInTargetInventory("IAmSfestMonster", 1, "Vanish")
			TNT1 A 0 A_QueueCorpse
			TNT1 A 0 A_Jump(128,2)
			LGI1 A 200
			stop
			LGI1 E 200
			Stop
		Vanish:
			TNT1 A 0
			Stop
    }
}




actor LSpart2 : LSpart1
{
	states
	{
		spawn:
			TNT1 A 0
			TNT1 A 0 Thing_ChangeTID(0,394)
			TNT1 A 0 A_Jump(128,9)
			LGI2 ABCDEFGH 2
			wait
			LGI2 HGFEDCBA 2
			wait
		Death:
			TNT1 A 0
			TNT1 A 0 A_JumpIfInTargetInventory("IAmSfestMonster", 1, "Vanish")
			TNT1 A 0 A_QueueCorpse
			TNT1 A 0 A_Jump(128,2)
			LGI2 A 200
			stop
			LGI2 E 200
			Stop
	}
}

actor LSpart3 : LSpart1
{
	states
	{
		spawn:
			TNT1 A 0
			TNT1 A 0 A_QueueCorpse
			TNT1 A 0 Thing_ChangeTID(0,394)
			TNT1 A 0 A_Jump(128,9)
			LGI3 ABCDEFGH 2
			wait
			LGI3 HGFEDCBA 2
			wait
		Death:
			TNT1 A 0
			TNT1 A 0 A_JumpIfInTargetInventory("IAmSfestMonster", 1, "Vanish")
			TNT1 A 0 A_QueueCorpse
			TNT1 A 0 A_Jump(128,2)
			LGI3 A 200
			stop
			LGI3 E 200
			Stop
	}
}

/*
ACTOR SoulTrails
{
	Game Doom
	Radius 1
	Height 1
	Speed 2
	Damage 0 
    +NOBLOCKMAP
    +NOTELEPORT
    +DONTSPLASH
	+MISSILE
	+FORCEXYBILLBOARD
    +CLIENTSIDEONLY
	RenderStyle Add
    DamageType Flames
    Scale 0.5
	Alpha 0.6
	Gravity 0
	States
	{
		Spawn:
			TNT1 A 2 
			FRFX KLMNOP 3 BRIGHT
			Stop
	}
}
*/

ACTOR FireBlood
{
	Radius 6
	Height 8
	States
	{
		Spawn:
			EXPL AAA 0 A_CustomMissile ("FlameTrails", 6, 0, random (0, 360), CMF_AIMDIRECTION, random (0, 360))
			Stop
	}
}

ACTOR FireBloodSaw: FireBlood
{
	States
	{
		Spawn:
			
			EXPL AAA 0 A_CustomMissile ("FlameTrails", 6, 0, random (0, 360), CMF_AIMDIRECTION, random (0, 360))
			TNT1 A 0 A_RadiusGive("ChainsawHitRed", 200, RGF_PLAYERS, 1)
			Stop
	}
}




actor LostSoulBlood : Blood
{
	Decal None
	game Doom
	+FORCEXYBILLBOARD
	+GHOST
	+NOBLOCKMAP
	+NOGRAVITY
	+NOCLIP
	-DONTSPLASH
	-ALLOWPARTICLES 
	+PUFFGETSOWNER
	Speed 0
	states
	{
		Spawn:
			TNT1 A 0
			TNT1 AAAAAA 0 A_CustomMissile ("SparkXNoModel", 2, 0, random (0, 360), 2, random (0, 360))
			TNT1 AA 0 A_CustomMissile ("SmallLSPart1", 0, 0, random (0, 360), 2, random (0, 360))
			TNT1 AA 0 A_CustomMissile ("SmallLSPart3", 0, 0, random (0, 360), 2, random (0, 360))
			stop
	}
}


actor SmallLSPart1: LSPart1
{
	Scale 0.3
	Speed 10
}


actor SmallLSPart3: LSPart1
{
	Scale 0.3
	Speed 12
}



actor BigLSPart1: LSPart1
{
	Scale 1.0
	Speed 10
}


actor BigLSPart3: LSPart1
{
	Scale 1.0
	Speed 12
}

actor BigLSPart2: LSPart1
{
	Scale 1.0
	Speed 12
}




/*

//***Che

 What is the most expensive thing that makes slaughtermap optimizations mandatory? 
	Detailed asplosions (a single zombie explosive death turns him into seventy (70!)
	chunks and body parts of various types). 
	Creation and deletion of that many objects RAPES the garbage collector
	bringing framerate to its knees.

	Particle effects, in particular - as with lost soul's flames - are a murder. 
	I built an extremely convoluted system around that (commented out below), buuut...

	Who said particle actors have to *die* ?

	I can easily make a flame particle that re-uses itself by teleporting back 
		to the lost soul and plays its animation anew. This way... Every lost soul 
		would be accompanied by a small flock of perpetual flame particles 
		that stay with it all its lifetime. Clienstide-only, of course.

	Aaaand, that just removes the need to slaughtermap-optimize lost souls at all. 
		No matter how many, their flame particles (with total no-collision, 
		happily going through map geometry) would be dirt cheap. 
*/

ACTOR PerpeualLSFlameParticle: RealFlameTrailsSmall 
// FIR1 are from torches as per BD18a. Still defined in BD21 but almost never used.
// let's UPGRADE them!
{
	Speed 0
	//+NOINTERACTION // not participating in collision at all
	
	-NOINTERACTION // lo and behold, waterlevel doesn't work without this! 
		// Nointeraction means NO interaction, including not belonging in any sector.
	+FORCEXYBILLBOARD
	-FORCEYBILLBOARD
	+DontSplash
	
	var int user_x;
	var int user_y;
	var int user_z;
	var int user_blife;
	
	States
	{
		Spawn:
			TNT1 A Random(1,8)
		Warpback:
			TNT1 A 0 A_SetUserVar("user_x", Random(-12, 0))
			TNT1 A 0 A_SetUserVar("user_y", Random(-8,8))
			TNT1 A 0 A_SetUserVar("user_z", Random(10,17) + user_x)
			
			//// extra offsets x -8 z -16 due to changed flame sprite
			//TNT1 A 1 A_Warp(AAPTR_TARGET,user_x -8,Random(-8,8),Random(22,30) + user_x - 16,0,WARPF_NOCHECKPOSITION|WARPF_COPYINTERPOLATION)
			//TNT1 A 1 A_Warp(AAPTR_TARGET,user_x,Random(-8,8),Random(22,30) + user_x,0,WARPF_NOCHECKPOSITION)
			//16384: WARPF_COPYVELOCITY = 0x4000, GZDoom only. Zandronum does not know this constant, would stop with an error
			//TNT1 A 0 ACS_NamedExecuteAlways("FBD_LSFlameCopyLSVelocity") // no worse than regular monsters spamming headbox adjust scripts
			
			TNT1 A 0 A_Stop
			Goto DoBurn
		DoBurn:
			TNT1 A 0 A_JumpIf(waterlevel >= 1, "Bubble")
				
			//***Che: trinary operator to the resue! Down with the jumps!
			TNT1 A 0 A_SetScale(0.01 * (Random(0, 1) ? Random(25,40) : Random(-40,-25)), 0.01 * random(40,60)) //A_SetScale(0.25, 0.5)
			Goto Burn
		
		Burn:
			INFE D 1 BRIGHT A_Warp(AAPTR_TARGET,user_x,user_y,user_z,0,WARPF_NOCHECKPOSITION|WARPF_INTERPOLATE)
			
			// without these, flames continue buring underwater for half a second
			// when the lost soul dives in at full ramming speed
			TNT1 A 0 A_JumpIf(waterlevel >= 1, "ProceedBubbling")
			
			INFE I 1 BRIGHT A_Warp(AAPTR_TARGET,user_x,user_y,user_z+1,0,WARPF_NOCHECKPOSITION|WARPF_INTERPOLATE)
			TNT1 A 0 A_JumpIf(waterlevel >= 1, "ProceedBubbling")
			INFE J 1 BRIGHT A_Warp(AAPTR_TARGET,user_x,user_y,user_z+2,0,WARPF_NOCHECKPOSITION|WARPF_INTERPOLATE)
			TNT1 A 0 A_JumpIf(waterlevel >= 1, "ProceedBubbling")
			INFE K 1 BRIGHT A_Warp(AAPTR_TARGET,user_x,user_y,user_z+3,0,WARPF_NOCHECKPOSITION|WARPF_INTERPOLATE)
			TNT1 A 0 A_JumpIf(waterlevel >= 1, "ProceedBubbling")
			INFE L 1 BRIGHT A_Warp(AAPTR_TARGET,user_x-1,user_y,user_z+4,0,WARPF_NOCHECKPOSITION|WARPF_INTERPOLATE)
			TNT1 A 0 A_JumpIf(waterlevel >= 1, "ProceedBubbling")
			INFE M 1 BRIGHT A_Warp(AAPTR_TARGET,user_x-2,user_y,user_z+5,0,WARPF_NOCHECKPOSITION|WARPF_INTERPOLATE)
			TNT1 A 0 A_JumpIf(waterlevel >= 1, "ProceedBubbling")
			INFE N 1 BRIGHT A_Warp(AAPTR_TARGET,user_x-3,user_y,user_z+6,0,WARPF_NOCHECKPOSITION|WARPF_INTERPOLATE)
			TNT1 A 0 A_JumpIf(waterlevel >= 1, "ProceedBubbling")
			INFE O 1 BRIGHT A_Warp(AAPTR_TARGET,user_x-4,user_y,user_z+7,0,WARPF_NOCHECKPOSITION|WARPF_INTERPOLATE)
			TNT1 A 0 A_JumpIf(waterlevel >= 1, "ProceedBubbling")
			TNT1 A 0 ThrustThingZ(0,Random(3,7),0,1)
			INFE PQRST 1 BRIGHT A_JumpIf(waterlevel >= 1, "ProceedBubbling")
			Goto Recycle
		Bubble:
			TNT1 A 0 A_Warp(AAPTR_TARGET,user_x,user_y,user_z,0,WARPF_NOCHECKPOSITION|WARPF_INTERPOLATE)
		ProceedBubbling:	
			TNT1 A 0 A_PlaySound("BUGURG_S", CHAN_BODY)
			TNT1 A 0 A_SetScale(0.5, 0.5)
			TNT1 A 0 A_SetUserVar("user_blife", Random(30,50))
			TNT1 A 0 A_Jump(255, "Bubble1", "Bubble2")
		Bubble1:
			BUBL A 1 A_JumpIf(waterlevel < 1, "Pop")
			"----" A 0 A_SetUserVar("user_blife", user_blife - 1)
			"----" A 0 A_JumpIf(user_blife <= 0, "Recycle")
			"----" A 0 A_ChangeVelocity(momx * 0.95, momy * 0.95, momz * 0.85 + 0.3, CVF_REPLACE)
			Loop
		Bubble2:
			BUBL B 1 A_JumpIf(waterlevel < 1, "Pop")
			"----" A 0 A_SetUserVar("user_blife", user_blife - 1)
			"----" A 0 A_JumpIf(user_blife <= 0, "Recycle")
			"----" A 0 A_ChangeVelocity(momx * 0.95, momy * 0.95, momz * 0.85 + 0.3, CVF_REPLACE)
			Loop
		Pop:		
			"----" A 0 A_Stop
			"----" A 1 A_PlaySound("BUBULZ_S", CHAN_BODY)
			"----" A 1 A_SetScale(0.7, 0.7)
			LIQU ABDCD 1
			TNT1 A 10
			Goto Recycle
		
		Recycle:
			TNT1 A 0 A_Stop // otherwise they keep accelerating with each recycle
			TNT1 A Random(0,3)
			TNT1 A 0 A_JumpIf(CallAcs("DoesHostLostSoulHaveFlames"), "Warpback")
			TNT1 A 1
			Stop
	}
}

Actor PerpeualLSFlameParticleKickstart: PerpeualLSFlameParticle
{
	States
	{
		Spawn:
			TNT1 A Random(0,2) // instead of regular particle's 1..8
			Goto Warpback
	}
}

ACTOR PerpetualHellHoundParticle: PerpeualLSFlameParticle
{
	States
	{
		Warpback:
			TNT1 A 0 A_SetUserVar("user_x", Random(-12, 0))
			TNT1 A 0 A_SetUserVar("user_y", Random(-5,5))
			TNT1 A 0 A_SetUserVar("user_z", Random(0,16))
			TNT1 A 0 A_Stop
			Goto DoBurn	
	}
}


#include Hater.txt