Relations NPC à NPC

Écrit le 03/07/2003 par DukeNukem
Dernière mise à jour : 30/01/2006

Introduction

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é parmi 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 IRelationship()

La fonction CBaseMonster::IRelationship() retourne une valeur d'un tableau de int, qui est une sorte de table des relations, avec les attitudes de chaque type de CLASS_*** envers les autres CLASS_***. 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 problème de mise en page. La fonction retourne donc une des macros suivantes, en fonction de ce que retourne la fonction Classify() de cette entité et du Classify() de l'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 quelconque
CBaseMonster *pMonster;

if( IRelationship( pMonster ) == R_FR )
{
    // faire quelque chose...
}

C'est aussi avec cette fonction qu'on active des bits de conditions (bits_COND_***), avec un switch par exemple (voir fonction CBaseMonster::Look())...

Personnaliser les relations d'un monstre

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 donne 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 :D
    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 (;p) et lorsqu'il rencontrera des headcrab, 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.

Table des relations

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