Monsters Programming - Classifications and Relationships Last edited 1 month ago2024-11-05 16:47:41 UTC

Half-Life Programming

In this page, we will see how monsters know the difference between an ally, neutral and enemy.

Classification

All entities even non-monsters have a int CBaseEntity::Classify() method that returns its classification that determines which kind/faction/team it is part of.

Here's a table of all existing classifications (cbase.h):
Constant Value What does it mean for the entity
CLASS_NONE 0 This entity does not need a classification.
CLASS_MACHINE 1 This entity is a machine (sentry, turret).
CLASS_PLAYER 2 This entity is a player.
CLASS_HUMAN_PASSIVE 3 This entity is a passive human (scientist).
CLASS_HUMAN_MILITARY 4 This entity is a human with military knowledge (Barney).
CLASS_ALIEN_MILITARY 5 This entity is an alien with military knowledge (alien grunt).
CLASS_ALIEN_PASSIVE 6 This entity is a passive alien (not used by any existing monster).
CLASS_ALIEN_MONSTER 7 This entity is a not so friendly alien monster (Big Momma, Gargantua).
CLASS_ALIEN_PREY 8 This entity is an alien prey for predators (headcrab).
CLASS_ALIEN_PREDATOR 9 This entity is an alien predator on the hunt for preys (bullsquid).
CLASS_INSECT 10 This entity is an insect (cockroach).
CLASS_PLAYER_ALLY 11 This entity is an ally for the player (Barney & scientist).
CLASS_PLAYER_BIOWEAPON 12 This entity is an alien projectile fired by a player (player hornets).
CLASS_ALIEN_BIOWEAPON 13 This entity is an alien projectile fired by an alien monster (alien grunt hornets).
CLASS_BARNACLE 99 Special classification for barnacles.

Relationships

Like in real life, a relationship dictates how an entity (mostly monsters) should behave towards another.

Whenever a relationship needs to be tested, a call to the method int CBaseMonster::IRelationship(CBaseEntity* pTarget) is made and returns one of the following values (monsters.h):
Constant Value What does it mean for the monster
R_AL -2 Ally - This monster is my ally and a friend.
R_FR -1 Fear - I am afraid of this monster, I need to get away from him.
R_NO 0 No relationship - Not my friend but not my enemy either.
R_DL 1 Dislike - This is an enemy I need to attack him.
R_HT 2 Hate - I hate this enemy and I will attack him in priority.
R_NM 3 Nemesis - 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 hard-coded matrix is used 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)):

In the following image, prefixes (CLASS_ and R_) are omitted for the sake of clarity.
User posted image
The way to read this matrix is simple, the correct line is the entity's classification determining the relationship (this) and the column is the target's (pTarget) classification.

Keep in mind that entities can override int CBaseMonster::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 CBaseMonster::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:

Comments

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