Écrit par David Henry, le 26 juillet 2002
Attention : cet article a été écrit pour le SDK 2.2 d'Half-Life 1 ! Il se peut qu'il ne soit pas entièrement compatible avec des versions antérieures ou supérieures du Kit.
Vous avez vu dans le tutorial sur comment créer un nouveau monstre, que
chaque entité possédait une fonction Classify()
permettant de
classer cette entité parmis un des quinze types possibles. Nous allons voir
ici comment est utilisée cette fonction pour définir les relations entres
NPC ou joueur, et comment personnaliser ces relations.
La fonction CBaseMonster::IRelationship()
retourne une
valeur d'un tableau de int, qui est une sorte de table des relations,
avec les attitude de chaque type de CLASS_XXX
envers les
autres CLASS_XXX
. La fonction ressemble à ceci :
int CBaseMonster::IRelationship (CBaseEntity *pTarget) { static int iEnemy[14][14] = { // NONE MACH PLYR HPASS HMIL AMIL APASS ... /*NONE*/ { R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,... }, /*MACHINE*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,... }, /*PLAYER*/ { R_NO ,R_DL ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,... }, /*HUMANPASSIVE*/{ R_NO ,R_NO ,R_AL ,R_AL ,R_HT ,R_FR ,R_NO ,... }, /*HUMANMILITAR*/{ R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_HT ,R_DL ,... }, /*ALIENMILITAR*/{ R_NO ,R_DL ,R_HT ,R_DL ,R_HT ,R_NO ,R_NO ,... }, /*ALIENPASSIVE*/{ R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,... }, /* ... */ { ... ,... ,... ,... ,... ,... ,... ,... }, }; return iEnemy[Classify ()][pTarget->Classify ()]; }
Je n'ai pas recopié toute la fonction pour des raisons de commodité (et puis
à vrai dire on s'en moque un peu). La fonction retourne donc une des macros
suivantes, en fonction de ce que retourne la fonction Classify()
de cette entitée et ce que retourne la fonction Classify()
de
l'autre entité :
Macro | Valeur | Signification | Description |
---|---|---|---|
R_AL | -2 | ALLY | Allié avec le monstre |
R_FR | -1 | FEAR | Aura peur, s'enfuira en présence du monstre |
R_NO | 0 | NONE | Ignorance |
R_DL | 1 | DISLIKE | Attaquera |
R_HT | 2 | HATE | Attaquera en priorité |
R_NM | 3 | NEMESIS | Pire ennemi, attaquera quoi qui se passe, priorité maximale |
Seul le barnacle ne figure pas dans la table car il est un peu spécial.
Maintenant comment cette fonction est elle utilisée ? Et bien à certains
endroits du code, comme les fonctions CBaseMonster::Look()
,
CBaseMonster::BestVisibleEnemy()
ou CBaseMonster::GetEnemy()
qui testent la valeur renvoyée avec le Classify()
d'une autre
entité. Par exemple :
// un NPC quelquonque CBaseMonster *pMonster; if (IRelationship (pMonster) == R_FR) { // faire quelquechose... }
C'est aussi avec cette fonction qu'on active des bits de conditions
(bits_COND_XXX
), avec un switch par exemple (voir
fonction CBaseMonster::Look()
)...
La fonction CBaseMonster::IRelationship()
reste cependant une
fonction de base. L'héritage et la surcharge de classes nous permet de
personnaliser cette table des relations pour chaque monstre.
On va prendre un exemple : le leech, l'espère de vermisseau qui
vie dans la flotte et qui attaque le joueur. Si l'on prend
CLeech::Classify()
(leech.cpp), on obtient
CLASS_INSECT
. Et maintenant, si l'on regarde le tableau
iEnemy
(de IRelationship()
) on voit que les
CLASS_INSECT
en présence de CLASS_PLAYER
, ça renvoie
R_FR
(FEAR). Pour que le leech attaque le joueur, on a donc
surchargé la fonction IRelationship()
à la classe
CLeech
:
int CLeech::IRelationship (CBaseEntity *pTarget) { if (pTarget->IsPlayer ()) return R_DL; return CBaseMonster::IRelationship (pTarget); }
Ici, si pTarget
(qui est l'entité confronté avec le monstre)
est le joueur, IRelationship()
retourne la macro R_DL
(DISLIKE). Sinon, on retombe sur la fonction de CBaseMonster
.
Ainsi, nous avons créé une variante de CLASS_INSECT
uniquement
pour CLeech
.
On peut s'amuser aussi à changer celui du Garg. Ajoutez la déclaration
de fonction dans la classe CGargantua
(gargantua.cpp) :
public: int IRelationship (CBaseEntity *pTarget);
puis juste après la définition de classe par exemple,
int CGargantua::IRelationship (CBaseEntity *pTarget) { if (pTarget->IsPlayer ()) return R_FR; // a peur du joueur ! else if (FClassnameIs (pTarget->pev, "monster_headcrab")) return R_HT; // deteste les headcrabs return CBaseMonster::IRelationship (pTarget); }
Ainsi lorsque le Garg verra le joueur, il en aura une peur bleue et
lorsqu'il rencontrera des headcrabq, il s'énervera dessus. On a utilisé
ici, la fonction FClassenameIs()
pour tester si
pTarget
est un headcrab. Si oui, on modifie la relation
en R_HT
(HATE) avec le headcrab.
Voici un tableau un peu plus propre des relations entres NPC/Joueur :
TARGET / MONSTER | (0) NONE | (1) MACHINE | (2) PLAYER | (3) HUMAN PASSIVE | (4) HUMAN MILITARY | (5) ALIEN MILITARY | (6) ALIEN PASSIVE |
---|---|---|---|---|---|---|---|
NONE | NONE | NONE | NONE | NONE | NONE | NONE | NONE |
MACHINE | NONE | NONE | DISLIKE | DISLIKE | NONE | DISLIKE | DISLIKE |
PLAYER | NONE | DISLIKE | NONE | NONE | DISLIKE | DISLIKE | DISLIKE |
HUMAN PASSIVE | NONE | NONE | ALLY | ALLY | HATE | FEAR | NONE |
HUMAN MILITARY | NONE | NONE | HATE | DISLIKE | NONE | HATE | DISLIKE |
ALIEN MILITARY | NONE | DISLIKE | HATE | DISLIKE | HATE | NONE | NONE |
ALIEN PASSIVE | NONE | NONE | NONE | NONE | NONE | NONE | NONE |
ALIEN MONSTER | NONE | DISLIKE | DISLIKE | DISLIKE | DISLIKE | NONE | NONE |
ALIEN PREY | NONE | NONE | DISLIKE | DISLIKE | DISLIKE | NONE | NONE |
ALIEN PREDATOR | NONE | NONE | DISLIKE | DISLIKE | DISLIKE | NONE | NONE |
INSECT | FEAR | FEAR | FEAR | FEAR | FEAR | NONE | FEAR |
PLAYER ALLY | NONE | DISLIKE | ALLY | ALLY | DISLIKE | DISLIKE | DISLIKE |
PLAYER BIO WEAPON | NONE | NONE | DISLIKE | DISLIKE | DISLIKE | DISLIKE | DISLIKE |
ALIEN BIO WEAPON | NONE | NONE | DISLIKE | DISLIKE | DISLIKE | ALLY | NONE |
TARGET / MONSTER | (7) ALIEN MONSTER | (8) ALIEN PREY | (9) ALIEN PREDATOR | (10) INSECT | (11) PLAYER ALLY | (12) PLAYER BIO WEAPON | (13) ALIEN BIO WEAPON |
---|---|---|---|---|---|---|---|
NONE | NONE | NONE | NONE | NONE | NONE | NONE | NONE |
MACHINE | DISLIKE | DISLIKE | DISLIKE | NONE | DISLIKE | DISLIKE | DISLIKE |
PLAYER | DISLIKE | DISLIKE | DISLIKE | NONE | NONE | DISLIKE | DISLIKE |
HUMAN PASSIVE | HATE | DISLIKE | FEAR | NONE | ALLY | NONE | NONE |
HUMAN MILITARY | DISLIKE | DISLIKE | DISLIKE | NONE | HATE | NONE | NONE |
ALIEN MILITARY | NONE | NONE | NONE | NONE | DISLIKE | NONE | NONE |
ALIEN PASSIVE | NONE | NONE | NONE | NONE | NONE | NONE | NONE |
ALIEN MONSTER | NONE | NONE | NONE | NONE | DISLIKE | NONE | NONE |
ALIEN PREY | NONE | NONE | FEAR | NONE | DISLIKE | NONE | NONE |
ALIEN PREDATOR | NONE | HATE | DISLIKE | NONE | DISLIKE | NONE | NONE |
INSECT | FEAR | FEAR | FEAR | NONE | FEAR | NONE | NONE |
PLAYER ALLY | DISLIKE | DISLIKE | DISLIKE | NONE | NONE | NONE | NONE |
PLAYER BIO WEAPON | DISLIKE | DISLIKE | DISLIKE | NONE | DISLIKE | NONE | DISLIKE |
ALIEN BIO WEAPON | DISLIKE | DISLIKE | NONE | NONE | DISLIKE | DISLIKE | NONE |
Cet article est mis à disposition sous un contrat Creative Commons (licence CC-BY-ND).