Monsters Programming - Classifications and Relationships Last edited 1 week ago2020-09-16 11:59:06 UTC

Half-Life Programming

All entities even non-monsters have a int Classify() method that returns its classification, here is the table of them (cbase.h):
ConstantValueWhat does it mean for the entity
CLASS_NONE0This entity does not need a classification.
CLASS_MACHINE1This entity is a machine (sentry, turret).
CLASS_PLAYER2This entity is a player.
CLASS_HUMAN_PASSIVE3This entity is a passive human (scientist).
CLASS_HUMAN_MILITARY4This entity is a human with military knowledge (Barney).
CLASS_ALIEN_MILITARY5This entity is an alien with military knowledge (alien grunt).
CLASS_ALIEN_PASSIVE6This entity is a passive alien (not used by any existing monster).
CLASS_ALIEN_MONSTER7This entity is a not so friendly alien monster (Big Momma, Gargantua).
CLASS_ALIEN_PREY8This entity is an alien prey for predators (headcrab).
CLASS_ALIEN_PREDATOR9This entity is an alien predator on the hunt for preys (bullsquid).
CLASS_INSECT10This entity is an insect (cockroach).
CLASS_PLAYER_ALLY11This entity is an ally for the player (Barney & scientist).
CLASS_PLAYER_BIOWEAPON12This entity is an alien projectile fired by a player (player hornets).
CLASS_ALIEN_BIOWEAPON13This entity is an alien projectile fired by an alien monster (alien grunt hornets).
CLASS_BARNACLE99Special classification for barnacles.
Whenever a relationship needs to be tested, a call to the method IRelationship is made and returns one of the following values (monsters.h):
ConstantValueWhat does it mean for the monster
R_AL-2Ally - This monster is my ally and a friend.
R_FR-1Fear - I am afraid of this monster, I need to get away from him.
R_NO0No relationship - Not my friend but not my enemy either.
R_DL1Dislike - This is an enemy I need to attack him.
R_HT2Hate - I hate this enemy and I will attack him in priority.
R_NM3Nemesis - I really hate this enemy and I want him dead no matter what.
The differences between "dislike", "hate" and "nemesis" explained
All of them means "enemy" but the difference is the severity or priority of the threat when choosing the enemy to attack if many of them are present.
  • "Dislike" can be compared to "low priority" or "I can deal with it later if there is a more important enemy".
  • "Hate" is the "medium priority", in other words, this is the entity thinking "I should probably take care of this kind of target first before dealing with the rest".
  • "Nemesis" is the "highest priority", the entity will prioritize this target no matter what, anything else does not matter.
A matrix is built to determine the relationship between two entities based on their classification, that matrix is (static int iEnemy[14][14] defined in int CBaseMonster::IRelationship( CBaseEntity *pTarget )):
CLASS_NONER_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)
CLASS_MACHINER_NO (ignore)R_NO (ignore)R_DL (dislike)R_DL (dislike)R_NO (ignore)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_NO (ignore)R_DL (dislike)R_DL (dislike)R_DL (dislike)
CLASS_PLAYERR_NO (ignore)R_DL (dislike)R_NO (ignore)R_NO (ignore)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_NO (ignore)R_NO (ignore)R_DL (dislike)R_DL (dislike)
CLASS_HUMAN_PASSIVER_NO (ignore)R_NO (ignore)R_AL (ally)R_AL (ally)R_HT (hate)R_FR (fear)R_NO (ignore)R_HT (hate)R_DL (dislike)R_FR (fear)R_NO (ignore)R_AL (ally)R_NO (ignore)R_NO (ignore)
CLASS_HUMAN_MILITARYR_NO (ignore)R_NO (ignore)R_HT (hate)R_DL (dislike)R_NO (ignore)R_HT (hate)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_NO (ignore)R_HT (hate)R_NO (ignore)R_NO (ignore)
CLASS_ALIEN_MILITARYR_NO (ignore)R_DL (dislike)R_HT (hate)R_DL (dislike)R_HT (hate)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_DL (dislike)R_NO (ignore)R_NO (ignore)
CLASS_ALIEN_PASSIVER_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)
CLASS_ALIEN_MONSTERR_NO (ignore)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_DL (dislike)R_NO (ignore)R_NO (ignore)
CLASS_ALIEN_PREYR_NO (ignore)R_NO (ignore)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_FR (fear)R_NO (ignore)R_DL (dislike)R_NO (ignore)R_NO (ignore)
CLASS_ALIEN_PREDATORR_NO (ignore)R_NO (ignore)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_HT (hate)R_DL (dislike)R_NO (ignore)R_DL (dislike)R_NO (ignore)R_NO (ignore)
CLASS_INSECTR_FR (fear)R_FR (fear)R_FR (fear)R_FR (fear)R_FR (fear)R_NO (ignore)R_FR (fear)R_FR (fear)R_FR (fear)R_FR (fear)R_NO (ignore)R_FR (fear)R_NO (ignore)R_NO (ignore)
CLASS_PLAYER_ALLYR_NO (ignore)R_DL (dislike)R_AL (ally)R_AL (ally)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_NO (ignore)R_NO (ignore)R_NO (ignore)R_NO (ignore)
CLASS_PLAYER_BIOWEAPONR_NO (ignore)R_NO (ignore)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_NO (ignore)R_DL (dislike)R_NO (ignore)R_DL (dislike)
CLASS_ALIEN_BIOWEAPONR_NO (ignore)R_NO (ignore)R_DL (dislike)R_DL (dislike)R_DL (dislike)R_AL (ally)R_NO (ignore)R_DL (dislike)R_DL (dislike)R_NO (ignore)R_NO (ignore)R_DL (dislike)R_DL (dislike)R_NO (ignore)
The way to read this matrix is simple, the correct line is the entity's classification determining the relationship and the column is the target's classification.

Keep in mind that entities can override int IRelationship( CBaseEntity *pTarget ) and thus have a specific relationship with one or more specific entities in specific cases.

Let's take a look at the human grunt (int CHGrunt::IRelationship( CBaseEntity *pTarget )) relationship code for an example:
int CHGrunt::IRelationship( CBaseEntity *pTarget )
    if ( FClassnameIs( pTarget->pev, "monster_alien_grunt" ) || ( FClassnameIs( pTarget->pev,  "monster_gargantua" ) ) )
        return R_NM;

    return CSquadMonster::IRelationship( pTarget );
We can determine that human grunts are really pissed off against alien grunts and gargantuas that they want them dead at all costs because they treat them as "nemesis".

There is no override of int IRelationship( CBaseEntity *pTarget ) in CSquadMonster (the human grunt's base class) so we fall back to the matrix shown above defined in CBaseMonster instead.

From there, we have multiple cases depending on the target:


You must log in to post a comment. You can login or register a new account.