Skip to content

AssessThreatLevel()

inkoalawetrust edited this page Sep 25, 2024 · 7 revisions

AssessThreatLevel (Actor Other[, Bool CheckPlayers = True, Bool ForceAssess = False])

Parameters:

  • Other: The actor whose threat level must be assessed.
  • CheckPlayers: Should players be returned as THREAT_UNSTOPPABLE if they have buddha or god mode. Or be automatically returned as THREAT_DANGEROUS otherwise ? Default is true.
  • ForceAssess: Makes the function ignore any threat level property or token value the actor has, and only heuristically assess their threat level.

AssessThreatLevel() is the special virtual function in the KAI library that handles the threat assessment system. It returns an enumerated threat level based on what conditions the Other actor meets. The function can be overwritten to add entirely custom threat assessment logic, or to extend the existing logic.

Threat levels

These are the threat levels included in the library, and roughly what vanilla monster they map out to:

Threat Level Value Description
THREAT_ASSESS 0 The default threat level. The virtual will heuristically determine what Other's threat level is.
THREAT_NONE 1 The actor is harmless. e.g a prop or a defenseless enemy.
THREAT_VERYLOW 2 The actor poses minimal threat. e.g a mosquito enemy or something
THREAT_LOW 3 The actor poses little threat. e.g a Zombieman or Shotgunner
THREAT_MILD 4 The actor is somewhat dangerous. e.g a Chaingunner* or Imp
THREAT_NORMAL 5 The actor is an average threat. e.g a Pinky
THREAT_ABOVENORMAL 6 The actor is an above average threat. e.g a Hell Knight, Cacodemon, or Revenant
THREAT_DANGEROUS 7 The actor is dangerous. e.g a Baron of Hell, Arachnotron or Mancubus
THREAT_VERYDANGEROUS 8 The actor is a major threat. e.g bosses like Cyberdemons and Spider Masterminds
THREAT_SUPERDANGER 9 The actor is a GIGANTIC THREAT. Like, literally as strong as 5-6 Cyberdemons or more.
THREAT_UNSTOPPABLE 666 The actor is straight up unstoppable, like an NPC with NODAMAGE, or player with ultimate god mode.

*Keep in mind that these heuristic threat levels are far from perfect, for example, Chaingunners are not merely THREAT_MILD, but GZDoom has no universal way to check how powerful a monsters' attack is.

How it works

If the Other actor is a KAI NPC that does not have a ThreatLevel specified (TODO: Add a link to the KAI_Actor subheading for that property), or it's a non-KAI NPC without a KAI_Token with a threat level specified, then the function will try to heuristically determine how threatening the actor is. This is largely done by checking how much health the actor has, and to a lesser extend based on if it can fly and/or move fast. As GZDoom has no way of universally figuring out how powerful an actors' attacks are. For a more detailed breakdown, check the definition of the AssessThreatLevel() virtual in /ZScript/Bases/Base.zsc.

That being said, if the actor has a preset threat level specified, through the property or the KAI_Token variable. Then the function will simply spit out that threat level. Allowing you to define specific threat levels for NPCs.

Checking players

In addition to assessing the threat level of NPCs. The function is also assesses the threat level of players. If Other is a player with any of the god or buddha mode cheats enabled, they will be returned as THREAT_UNSTOPPABLE like invulnerable NPCs are. But if not cheating, players will still be automatically returned as THREAT_DANGEROUS, since they are not mere NPCs, the only exception is if the players' username is inkoalawetrust, yes, I'm serious, you can check the source code. None of these player checks will run if the CheckPlayers parameter is set to false.

Dynamic threat levels

Since the ThreatLevel property on KAI actors is simply an integer, you can change it dynamically to alter how dangerous other KAI NPCs perceive your actor as being. For example, you can make an Archvile with a normal threat level of THREAT_DANGEROUS, but also give it a secondary AOE resurrect attack, and while it is in its' AOE state, it will have its' threat level changed to THREAT_VERYDANGEROUS until the end of that state sequence.

Example

Cowardly baron

This big Baron of Hell is scared of foes as strong or stronger than him, but is also unreasonably scared of small Pinkies and treats them as large threats as well. This NPC does not replace AssessThreatLevel(), but simply expands it to make the Baron also consider small Pinkies as dangerous.

//The mouse-sized Pinky the Baron is scared of.
Class SmallPinky : Demon
{
	Default
	{
		Scale 0.3333;
		Health 60;
		Speed 5;
		Radius 10;
		Height 18.6;
	}
}

Class BigBaron : KAI_Actor
{
	Default
	{
		Health 1500;
		Scale 1.25;
		Radius 30;
		Height 80;
		Mass 1250;
		Speed 8;
		PainChance 37;
		Monster;
		KAI_Actor.ThreatLevelThreshold THREAT_DANGEROUS;
		+FLOORCLIP
		+BOSSDEATH
		SeeSound "baron/sight";
		PainSound "baron/pain";
		DeathSound "baron/death";
		ActiveSound "baron/active";
		Obituary "$OB_BARON";
		HitObituary "$OB_BARONHIT";
		Tag "$FN_BARON";
	}
	
	Override Int AssessThreatLevel (Actor Other, Bool CheckPlayers)
	{
		Int Lvl = KAI_Actor.AssessThreatLevel (Other, CheckPlayers);
		
		//The big Baron is unreasonably scared of small Pinkies.
		If (Other Is "Demon" && Other.Radius <= 24 && Other.Height <= 48)
			Return THREAT_DANGEROUS;
		
		Return Lvl;
	}
	
	Int AttackCount;
	States
	{
		Spawn:
			BOSS AB 10 A_Look();
			Loop;
		See:
			BOSS AABBCCDD 3
			{
				//If your targets' threat level is over the threshold, then walk away from it.
				If (Target && AssessThreatLevel (Target) >= ThreatLevelThreshold)
					bFrightened = True;
				Else
					bFrightened = False;
				
				A_Chase();
			}
			Loop;
		Melee:
		Missile:
			BOSS EF 8 A_FaceTarget();
			BOSS G 8 A_BruisAttack();
			BOSS G 0 {AttackCount++;}
			BOSS G 0 A_JumpIf (AttackCount < 4,"Missile");
			BOSS G 0 {AttackCount = 0;}
			Goto See;
		Pain:
			BOSS H  2;
			BOSS H  2 A_Pain();
			Goto See;
		Death:
			BOSS I  8;
			BOSS J  8 A_Scream();
			BOSS K  8;
			BOSS L  8 A_NoBlocking();
			BOSS MN 8;
			BOSS O -1 A_BossDeath();
			Stop;
		Raise:
			BOSS O 8;
			BOSS NMLKJI 8;
			Goto See;
	}
}

Threat assessing actor

This actor will return the threat level of whatever actor it catches in its' sight first using the stock threat assessment code.

Class ThreatAssess : KAI_Actor
{
	Default {+NoTarget;}
	States
	{
		Spawn:
			TNT1 A 1 A_LookEx(fov:360);
			loop;
		See:
			TNT1 A 1
			{
				String Text;
				Switch (AssessThreatLevel (Target))
				{
					Case THREAT_SUPERDANGER:
						Text = "THREAT_SUPERDANGER";
						Break;
					Case THREAT_VERYDANGEROUS:
						Text = "THREAT_VERYDANGEROUS";
						Break;
					Case THREAT_DANGEROUS:
						Text = "THREAT_DANGEROUS";
						Break;
					Case THREAT_ABOVENORMAL:
						Text = "THREAT_ABOVENORMAL";
						Break;
					Case THREAT_NORMAL:
						Text = "THREAT_NORMAL";
						Break;
					Case THREAT_MILD:
						Text = "THREAT_MILD";
						Break;
					Case THREAT_LOW:
						Text = "THREAT_LOW";
						Break;
					Case THREAT_VERYLOW:
						Text = "THREAT_VERYLOW";
						Break;
					Case THREAT_UNSTOPPABLE:
						Text = "THREAT_UNSTOPPABLE";
						Break;
					Case THREAT_NONE:
						Text = "THREAT_NONE";
						Break;
					Default:
						Text = "Oops";
						Break;
				}
				Console.Printf ("%s threat level:%s",Target.GetClassName(),Text);
			}
			Stop;
	}
}

See also

Clone this wiki locally