Fr/Fixing AI in multiplayer: Difference between revisions

From Valve Developer Community
< Fr
Jump to navigation Jump to search
No edit summary
(Rewrite Template:Lang to Template:LanguageBar. This action was performed by a bot.)
 
(14 intermediate revisions by 9 users not shown)
Line 1: Line 1:
[[Category:Programming]]
{{LanguageBar|Fixing AI in multiplayer|title=Activer et Corriger l'IA en Coop}}
{{ACategory|Networking}}
=Introduction=
=Introduction=
Salut à tous!
Cet article est une mise-à-jour de l'article '''Activer IA en Coop'''.
Cet article est une mise-à-jour de l'article '''Activer IA en Coop'''.
Bien que l'ancienne version expiquait comment activer l'IA dans une partie multijoueurs, il s'avérait que les NPCs de type humanoïdes tels que les ''Combine Soldiers'' ne pouvaient pas se déplacer, ni tirer sur le joueur, et c'est frustrant!
Bien que l'ancienne version expiquait comment activer l'IA dans une partie multijoueurs, il s'avérait que les NPCs de type humanoïdes tels que les ''Combine Soldiers'' ne pouvaient pas se déplacer, ni tirer sur le joueur, et c'est frustrant!
Line 8: Line 7:


Avant que l'on aille plus loin, j'aimerais juste remercier au passage Garry Newman BunkMug, FoxFire, pour leurs tuyaux ainsi que d'autres personnes sur divers forums.
Avant que l'on aille plus loin, j'aimerais juste remercier au passage Garry Newman BunkMug, FoxFire, pour leurs tuyaux ainsi que d'autres personnes sur divers forums.


=Tabes des Relations=
=Tabes des Relations=
Line 14: Line 12:
D'abord, on doit définir cette table en définissant les différentes classes des personnages présents dans le jeu.
D'abord, on doit définir cette table en définissant les différentes classes des personnages présents dans le jeu.
Ouvrez le fichier '''BaseEntity.h''', puis dans la définition de '''enum Class_T''', après le bloc '''#elif defined( CSTRIKE_DLL )''' ajoutez ceci:
Ouvrez le fichier '''BaseEntity.h''', puis dans la définition de '''enum Class_T''', après le bloc '''#elif defined( CSTRIKE_DLL )''' ajoutez ceci:
<pre>
<pre>
//***THOMAS*** INITIALISE LA TABLE DES RELATIONS DES NPC ( =PNJ ) POUR HL2DM
//***THOMAS*** INITIALISE LA TABLE DES RELATIONS DES NPC ( =PNJ ) POUR HL2DM
Line 52: Line 49:


==Utilisation de la Table==
==Utilisation de la Table==
Super! Maintenant il nous faut dire aux ''Game Rules'' d'utiliser cette Table de Relations dans le jeu lorque l'on commence une partie de HL2DM.
Super! Maintenant il nous faut dire aux ''Game Rules'' d'utiliser cette Table de Relations dans le jeu lorque l'on commence une partie de HL2DM.
Ouvrez le fichier '''h2mp_gamerules.h'''. En dessous de l'onglet '''public:''', ajoutez ceci:
Ouvrez le fichier '''h2mp_gamerules.h'''. En dessous de l'onglet '''public:''', ajoutez ceci:
Line 63: Line 59:
//***
//***
</pre>
</pre>
A présent, ouvrez le fichier '''h2mp_gamerules.cpp'''. Ensuite tout en bas du fichier ''.cpp'' ajoutez tout ce bout de code:
A présent, ouvrez le fichier '''h2mp_gamerules.cpp'''. Ensuite tout en bas du fichier ''.cpp'' ajoutez tout ce bout de code:
<pre>
<pre>
Line 82: Line 75:
//***
//***
</pre>
</pre>
Terminons en ajoutant cette petite instruction dans la fonction CHL2MPRules::CHL2MPRules():
Terminons en ajoutant cette petite instruction dans la fonction CHL2MPRules::CHL2MPRules():
<pre>
<pre>
//***THOMAS*** INITIALISE LA TABLE DES RELATIONS DES NPC ( =PNJ ) POUR HL2DM
//***THOMAS*** INITIALISE LA TABLE DES RELATIONS DES NPC ( =PNJ ) POUR HL2DM
Line 94: Line 82:
</pre>
</pre>


 
=Faire fonctionner les NPCs humanoides=
=Making Humanoid NPCs Shoot=
==Animations des Armes==
==Weapons Animations Code==
Pour chaque arme, prendre le code SP de l'arme, et copier la liste des animations contenues dans la structure ''acttable_t''.
First, find each weapon SP code ( located in the \dlls\hl2_dll\ folder ), then move all the animations declarations located in the SP-acttable_t function to the HL2MP-acttable_t structure. See example bellow:
Procédez comme ci-dessous:


<pre>
<pre>
acttable_t CWeaponSMG1::m_acttable[] =  
acttable_t CWeaponSMG1::m_acttable[] =  
{
{
//HL2DM ANIMATIONS LIST START
//DEPART ANIMATIONS HL2DM
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SMG1, false },
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SMG1, false },
( ... )
( ... )
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SMG1, false },
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SMG1, false },
//HL2MP ANIMATIONS LIST END
//FIN ANIMATIONS HL2DM


//HL2SP ANIMATIONS LIST START
//DEPART ANIMATIONS HL2
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SMG1, true },
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SMG1, true },
{ ACT_RELOAD, ACT_RELOAD_SMG1, true },
{ ACT_RELOAD, ACT_RELOAD_SMG1, true },
Line 114: Line 102:
(...)
(...)
{ ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, true },
{ ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, true },
//HL2SP ANIMATIONS LIST END
//FIN ANIMATIONS HL2


}
}
</pre>
</pre>


 
==Autres modifications sur les armes==
 
Il faut à présent insérer le code qui permet à l'IA de controller son arme, en l'occurrence de tirer avec, de la recharger etc. Pour ce faire, il faut déclarer ces deux fonctions, côté serveur seulement:
==Other Weapons Modifications==
Now you have to edit each weapon code by adding a few lines of code in their class definition.  
In each weapon class, add those declarations ( server side only ):
 
<pre>
<pre>
#ifndef CLIENT_DLL
#ifndef CLIENT_DLL
//ALLOW NPCS TO USE THE WEAPON TO SHOOT THEIR ENNEMIES
//PERMET AUX NPC D'UTILISER CETTE ARME
int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
//HANDLES AI'S ACTIVITIES
//GESTION DES ACTIONS DE L'IA
void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
#endif
#endif
</pre>
</pre>


'''NOTICE:''' You will find the ''Operator_HandleAnimEvent()'' function body in the SP-code of the weapon. Thus, do not forget to copy/paste it to avoid compiling errors!
{{note|Vous trouverez le corps de la fonction ''Operator_HandleAnimEvent()'' dans votre copie du SDK. N'oubliez donc pas de l'insérer sinon vous risquez de génererer des erreurs à la compilation!}}
 


==Garry Newman's suggestion==
==Suggestions de Garry Newman==
Garry Newman suggested on forums to modify the ''SetActivity()'' function code.
Garry Newman suggérait sur des forums de modifier la fonction ''SetActivity()''.
Thus, in the '''basecombatweapon_shared.cpp''' file, find the ''SetActivity()'' function, and then, after Adrian's comment:
Ainsi, dans le fichier '''basecombatweapon_shared.cpp''', recherchez la fonction ''SetActivity()'', et juste après e commentaire d'Adrien:
<pre>
<pre>
//Adrian: Oh man...
//Adrian: Oh man...
</pre>
</pre>
 
remplacez
replace
 
<pre>
<pre>
#if !defined( CLIENT_DLL ) && defined( HL2MP )
#if !defined( CLIENT_DLL ) && defined( HL2MP )
Line 151: Line 132:
#endif
#endif
</pre>
</pre>
 
par
to
 
 
<pre>
<pre>
if ( GetOwner()->IsPlayer() )
if ( GetOwner()->IsPlayer() )
SetModel( GetWorldModel() );
SetModel( GetWorldModel() );
</pre>
</pre>
 
Procédez de même après l'autre commentaire, vous remplacerez donc:
 
Proceed similarily after the other comment, so you replace:
 
<pre>
<pre>
//Adrian: Oh man again...
//Adrian: Oh man again...
Line 169: Line 144:
#endif
#endif
</pre>
</pre>
 
par
to
 
<pre>
<pre>
//Adrian: Oh man again...
//Adrian: Oh man again...
Line 177: Line 150:
SetModel( GetViewModel() );
SetModel( GetViewModel() );
</pre>
</pre>
 
Bon, je ne sais pas si ça change queque chose ou pas, mais Garry insistait sur ce code, alors je suggère qu'en en tienne compte. Si quequ'un à le courage de tester pour voir s'il y a une différence ou pas avec ce code, qu'il m'en fasse part, merci.
Well, I don't now if that code fixes anything, I have not tried yet. I hope you will give me feedback about that piece of code.
 


==Ammotypes==
==Ammotypes==
Well, if the NPCS kill you instantly - ''it happened to me'' - here's the tip to fix it. In the '''hl2mp_gamerules.cpp''' file, replace the whole ''CAmmoDef *GetAmmoDef()'' function to this:
Après avoir activé mes NPCs humanoides, ces derniers me tuaient en une seule balle. Si vous avec le même problème, je vous suggère de trouver la fonction ''CAmmoDef *GetAmmoDef()'' dans le fichier '''hl2mp_gamerules.cpp''', et de la remplacer entièrement par ce qui suit.
 
<pre>
<pre>
CAmmoDef *GetAmmoDef()
CAmmoDef *GetAmmoDef()
Line 222: Line 192:
</pre>
</pre>


=Pour terminer=
==Le fichier skill.cfg==
On m'a fait remarquer que les NPC ne causent pas de dommages au joueur, et en plus ils meurent très facilement. Ceci est simplement liée à l'absence du fichier '''skill.cfg''' dans le répertoire ''\cfg'' du mod.
pour corriger l'erreur, il vous faut copier/coller le fichier skill.cfg du jeu Half-Life 2 dans le répertoire
''\cfg'' de votre mod.


==Animations des Models==
Pour en finir avec ces NPCs, il vous faut remplacer les animations des NPCs par celles d'origine.
En clair, il faut remplacer les animations de HL2DM par celles de HL2, ce qui permettra à l'IA de fonctionner
correctement car ee pourra utiliser ses propres animations, et non pas celles de H2DM qui sont différentes!


Il faut évidement utiliser d'autres animations pour les joueurs afin de ne pas corrompre leurs propres animations ( celles utiisées par HL2DM ).


Pour éviter de recompiler les models, il est préférable de les éditer avec un éditeur hexadécimal ( models de joueurs & noms des animations ). Pour vous faire gagner du temps, je vous suggère d'utiliser des models déjà hex-édités, par exemples ceux du Garry's mod.


 
Je vous ai préparé un petit package qui contient ce dont vous avez besoin pour faire fonctionner les ''Combine Soldiers'' et les ''Citoyens''. En fait j'ai emprunté les models de Garry. Vous pouvez avec le ien vers le tléchargement à [http://dolphineye.ifrance.com/aifix.html cette page].
=Let's Finish=
==Import skills data==
Few people noticed that NPCs were not causing any damage to the player and that they could die instantly.
This issue is simply caused by the fact the file '''skill.cfg''' is missing from the ''"\cfg"'' directory in the mod-dir.
To fix it, get the '''skill.cfg''' file located in the Half-Lfe 2 folder.
 
==Models Animations==
You have to replace the HL2DM NPCS animations by the HL2 ones. Indeed HL2DM overrides the NPCs animations - ''used for the player models'' - so it breaks the AI. Thus, you have to use other models files for the players. You can hexedit the HL2DM player models & animations to make it tight. You will also have to put the HL2 original models in your ''\models'' folder.
Finally, do not forget to modify the code related to the player models list in the '''hl2mp_player.cpp''' file.
 
Well, I don't want you to waste time hex-editing the model files, so I borrowed Garry's models, you can downoad the whole package [http://dolphineye.ifrance.com/aifix.html here ].
 
 
 
Hope it helps! Happy modding!
 
 
 
{{otherlang:en}} {{otherlang:en:fr|Activer IA en Coop}}
[[Category:Programming]]
=Introduction=
Howdy!
 
This article is an updated version of the previous tutorial '''Activating AI In Coop Games'''.
Though the previous article allowed you to enable AI in multiplayer games, humanoid NPCs like ''Combine Soldiers'' could not attack the player. It is annoying, isn't it? Well, I think this is time to get over it!
 
Before we go on, I would like to thank Garry Newman, BunkMug & FoxFire - for their contributions to the A.I problem - and some other people on the forums who helped me to figure out that crazy stuff.
I hope the article will help!
 
 
=The Relationship Table=
==Creating the Table==
First of all, we should define the NPCs relationship table. Open the '''BaseEntity.h''' file, then in the '''enum Class_T''' definition, after the '''#elif defined( CSTRIKE_DLL )''' block, add this:
 
<pre>
//***THOMAS*** INITS NPCs' RELATION SHIP TABLE FOR HL2DM
#elif defined ( HL2MP_DLL || HL2MP )
// For CLASSIFY
enum Class_T
{
CLASS_NONE=0,
CLASS_PLAYER,
CLASS_PLAYER_ALLY,
CLASS_PLAYER_ALLY_VITAL,
CLASS_ANTLION,
CLASS_BARNACLE,
CLASS_BULLSEYE,
CLASS_CITIZEN_PASSIVE,
CLASS_CITIZEN_REBEL,
CLASS_COMBINE,
CLASS_COMBINE_GUNSHIP,
CLASS_CONSCRIPT,
CLASS_HEADCRAB,
CLASS_MANHACK,
CLASS_METROPOLICE,
CLASS_MILITARY,
CLASS_SCANNER,
CLASS_STALKER,
CLASS_VORTIGAUNT,
CLASS_ZOMBIE,
CLASS_PROTOSNIPER,
CLASS_MISSILE,
CLASS_FLARE,
CLASS_EARTH_FAUNA,
 
NUM_AI_CLASSES
};
//***
</pre>
 
==Loading the Table==
 
All right! Now we have to tell the Game Rules to use this relationship table when we start a HL2DM game.
Open the '''hl2mp_gamerules.h''' file. Under the '''public:''' tab, add this:
 
<pre>
//***THOMAS*** INITS NPCs' RELATION SHIP TABLE FOR HL2DM
#ifndef CLIENT_DLL
void InitDefaultAIRelationships( void );
#endif
//***
</pre>
 
 
 
Now open the '''hl2mp_gamerules.cpp''' file. Then, at the very bottom of the file, add this piece of code:
<pre>
//------------------------------------------------------------------------------
// Purpose : Initialize all default class relationships
// Input  :
// Output  :
//------------------------------------------------------------------------------
//***THOMAS*** INITS NPCs' RELATION SHIP TABLE FOR HL2DM
#ifndef CLIENT_DLL
void CHL2MPRules::InitDefaultAIRelationships( void )
{
//Copy contents of the hl2_gamerules InitDefaultAIRelationships to here
}
#endif
//***
</pre>
 
 
Let's finish by adding this in the CHL2MPRules::CHL2MPRules() function:
 
<pre>
//***THOMAS*** INITS NPCs' RELATION SHIP TABLE FOR HL2DM
InitDefaultAIRelationships();
//***
</pre>
 
 
=Making Humanoid NPCs Shoot=
==Weapons Animations Code==
First, find each weapon SP code ( located in the \dlls\hl2_dll\ folder ), then move all the animations declarations located in the SP-acttable_t function to the HL2MP-acttable_t structure. See example bellow:
 
<pre>
acttable_t CWeaponSMG1::m_acttable[] =
{
//HL2DM ANIMATIONS LIST START
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SMG1, false },
( ... )
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SMG1, false },
//HL2MP ANIMATIONS LIST END
 
//HL2SP ANIMATIONS LIST START
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SMG1, true },
{ ACT_RELOAD, ACT_RELOAD_SMG1, true },
{ ACT_IDLE, ACT_IDLE_SMG1, true },
(...)
{ ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, true },
//HL2SP ANIMATIONS LIST END
 
}
</pre>
 
 
 
==Other Weapons Modifications==
Now you have to edit each weapon code by adding a few lines of code in their class definition.
In each weapon class, add those declarations ( server side only ):
 
<pre>
#ifndef CLIENT_DLL
//ALLOW NPCS TO USE THE WEAPON TO SHOOT THEIR ENNEMIES
int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
//HANDLES AI'S ACTIVITIES
void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
#endif
</pre>
 
'''NOTICE:''' You will find the ''Operator_HandleAnimEvent()'' function body in the SP-code of the weapon. Thus, do not forget to copy/paste it to avoid compiling errors!
 
 
==Garry Newman's suggestion==
Garry Newman suggested on forums to modify the ''SetActivity()'' function code.
Thus, in the '''basecombatweapon_shared.cpp''' file, find the ''SetActivity()'' function, and then, after Adrian's comment:
<pre>
//Adrian: Oh man...
</pre>
 
replace
 
<pre>
#if !defined( CLIENT_DLL ) && defined( HL2MP )
SetModel( GetWorldModel() );
#endif
</pre>
 
to
 
 
<pre>
if ( GetOwner()->IsPlayer() )
SetModel( GetWorldModel() );
</pre>
 
 
Proceed similarily after the other comment, so you replace:
 
<pre>
//Adrian: Oh man again...
#if !defined( CLIENT_DLL ) && defined( HL2MP )
SetModel( GetViewModel() );
#endif
</pre>
 
to
 
<pre>
//Adrian: Oh man again...
if ( GetOwner()->IsPlayer() )
SetModel( GetViewModel() );
</pre>
 
Well, I don't now if that code fixes anything, I have not tried yet. I hope you will give me feedback about that piece of code.
 
 
==Ammotypes==
Well, if the NPCS kill you instantly - ''it happened to me'' - here's the tip to fix it. In the '''hl2mp_gamerules.cpp''' file, replace the whole ''CAmmoDef *GetAmmoDef()'' function to this:
 
<pre>
CAmmoDef *GetAmmoDef()
{
static CAmmoDef def;
static bool bInitted = false;
if ( !bInitted )
Au fait, n'oubliez pas de prendre en compte ce changement dans le code, au niveau de la liste des models de joueurs dans le fichier '''hl2mp_player.cpp'''.
{
bInitted = true;
 
//THOMAS: HL2SP DEFINITIONS
def.AddAmmoType("AR2", DMG_BULLET, TRACER_LINE_AND_WHIZ, "sk_plr_dmg_ar2", "sk_npc_dmg_ar2", "sk_max_ar2", BULLET_IMPULSE(200, 1225), 0 );
def.AddAmmoType("AlyxGun", DMG_BULLET, TRACER_LINE, "sk_plr_dmg_alyxgun", "sk_npc_dmg_alyxgun", "sk_max_alyxgun", BULLET_IMPULSE(200, 1225), 0 );
def.AddAmmoType("Pistol", DMG_BULLET, TRACER_LINE_AND_WHIZ, "sk_plr_dmg_pistol", "sk_npc_dmg_pistol", "sk_max_pistol", BULLET_IMPULSE(200, 1225), 0 );
def.AddAmmoType("SMG1", DMG_BULLET, TRACER_LINE_AND_WHIZ, "sk_plr_dmg_smg1", "sk_npc_dmg_smg1", "sk_max_smg1", BULLET_IMPULSE(200, 1225), 0 );
def.AddAmmoType("357", DMG_BULLET, TRACER_LINE_AND_WHIZ, " sk_plr_dmg_357", "sk_npc_dmg_357", "sk_max_357", BULLET_IMPULSE(800, 5000), 0 );
def.AddAmmoType("XBowBolt", DMG_BULLET, TRACER_LINE, "sk_plr_dmg_crossbow", "sk_npc_dmg_crossbow", "sk_max_crossbow", BULLET_IMPULSE(800, 8000), 0 );
 
def.AddAmmoType("Buckshot", DMG_BULLET | DMG_BUCKSHOT, TRACER_LINE, "sk_plr_dmg_buckshot", "sk_npc_dmg_buckshot", "sk_max_buckshot", BULLET_IMPULSE(400, 1200), 0 );
def.AddAmmoType("RPG_Round", DMG_BURN, TRACER_NONE, "sk_plr_dmg_rpg_round", "sk_npc_dmg_rpg_round", "sk_max_rpg_round", 0, 0 );
def.AddAmmoType("SMG1_Grenade", DMG_BURN, TRACER_NONE, "sk_plr_dmg_smg1_grenade", "sk_npc_dmg_smg1_grenade", "sk_max_smg1_grenade", 0, 0 );
def.AddAmmoType("Grenade", DMG_BURN, TRACER_NONE, "sk_plr_dmg_grenade", "sk_npc_dmg_grenade", "sk_max_grenade", 0, 0);
def.AddAmmoType("Thumper", DMG_SONIC, TRACER_NONE, 10, 10, 2, 0, 0 );
def.AddAmmoType("Gravity", DMG_CLUB, TRACER_NONE, 0, 0, 8, 0, 0 );
def.AddAmmoType("Battery", DMG_CLUB, TRACER_NONE, NULL, NULL, NULL, 0, 0 );
def.AddAmmoType("GaussEnergy", DMG_SHOCK, TRACER_NONE, "sk_jeep_gauss_damage", "sk_jeep_gauss_damage", "sk_max_gauss_round", BULLET_IMPULSE(650, 8000), 0 ); // hit like a 10kg weight at 400 in/s
def.AddAmmoType("CombineCannon", DMG_BULLET, TRACER_LINE, "sk_npc_dmg_gunship_to_plr", "sk_npc_dmg_gunship", NULL, 1.5 * 750 * 12, 0 ); // hit like a 1.5kg weight at 750 ft/s
def.AddAmmoType("AirboatGun", DMG_AIRBOAT, TRACER_LINE, "sk_plr_dmg_airboat", "sk_npc_dmg_airboat", NULL, BULLET_IMPULSE(10, 600), 0 );
def.AddAmmoType("StriderMinigun", DMG_BULLET, TRACER_LINE, 5, 5, 15, 1.0 * 750 * 12, AMMO_FORCE_DROP_IF_CARRIED ); // hit like a 1.0kg weight at 750 ft/s
def.AddAmmoType("HelicopterGun", DMG_BULLET, TRACER_LINE_AND_WHIZ, "sk_npc_dmg_helicopter_to_plr", "sk_npc_dmg_helicopter", "sk_max_smg1", BULLET_IMPULSE(400, 1225), AMMO_FORCE_DROP_IF_CARRIED | AMMO_INTERPRET_PLRDAMAGE_AS_DAMAGE_TO_PLAYER );
def.AddAmmoType("AR2AltFire", DMG_DISSOLVE, TRACER_NONE, 0, 0, "sk_max_ar2_altfire", 0, 0 );
//***
}
 
return &def;
}
</pre>
 
 
 
 
 
 
=Let's Finish=
==Import skills data==
Few people noticed that NPCs were not causing any damage to the player and that they could die instantly.
This issue is simply caused by the fact the file '''skill.cfg''' is missing from the ''"\cfg"'' directory in the mod-dir.
To fix it, get the '''skill.cfg''' file located in the Half-Lfe 2 folder.
 
==Models Animations==
You have to replace the HL2DM NPCS animations by the HL2 ones. Indeed HL2DM overrides the NPCs animations - ''used for the player models'' - so it breaks the AI. Thus, you have to use other models files for the players. You can hexedit the HL2DM player models & animations to make it tight. You will also have to put the HL2 original models in your ''\models'' folder.
Finally, do not forget to modify the code related to the player models list in the '''hl2mp_player.cpp''' file.
 
Well, I don't want you to waste time hex-editing the model files, so I borrowed Garry's models, you can downoad the whole package [http://dolphineye.ifrance.com/aifix.html here ].
 
 
 
Hope it helps! Happy modding!
 
 
 
{{otherlang:en}} {{otherlang:fr:en|Activating AI In Coop Games}}

Latest revision as of 17:53, 18 July 2025

English (en)Français (fr)Translate (Translate)

Introduction

Cet article est une mise-à-jour de l'article Activer IA en Coop. Bien que l'ancienne version expiquait comment activer l'IA dans une partie multijoueurs, il s'avérait que les NPCs de type humanoïdes tels que les Combine Soldiers ne pouvaient pas se déplacer, ni tirer sur le joueur, et c'est frustrant! Eh bien voilà, c'est une histoire an cienne à présent, je vous propose que l'on étudie tout celà ensembe...

Avant que l'on aille plus loin, j'aimerais juste remercier au passage Garry Newman BunkMug, FoxFire, pour leurs tuyaux ainsi que d'autres personnes sur divers forums.

Tabes des Relations

Création de la Table

D'abord, on doit définir cette table en définissant les différentes classes des personnages présents dans le jeu. Ouvrez le fichier BaseEntity.h, puis dans la définition de enum Class_T, après le bloc #elif defined( CSTRIKE_DLL ) ajoutez ceci:

//***THOMAS*** INITIALISE LA TABLE DES RELATIONS DES NPC ( =PNJ ) POUR HL2DM
#elif defined ( HL2MP_DLL || HL2MP )
// For CLASSIFY
enum Class_T
{
	CLASS_NONE=0,				
	CLASS_PLAYER,			
	CLASS_PLAYER_ALLY,
	CLASS_PLAYER_ALLY_VITAL,
	CLASS_ANTLION,
	CLASS_BARNACLE,
	CLASS_BULLSEYE,
	CLASS_CITIZEN_PASSIVE,	
	CLASS_CITIZEN_REBEL,
	CLASS_COMBINE,
	CLASS_COMBINE_GUNSHIP,
	CLASS_CONSCRIPT,
	CLASS_HEADCRAB,
	CLASS_MANHACK,
	CLASS_METROPOLICE,		
	CLASS_MILITARY,		
	CLASS_SCANNER,		
	CLASS_STALKER,		
	CLASS_VORTIGAUNT,
	CLASS_ZOMBIE,
	CLASS_PROTOSNIPER,
	CLASS_MISSILE,
	CLASS_FLARE,
	CLASS_EARTH_FAUNA,

	NUM_AI_CLASSES
};
//***

Utilisation de la Table

Super! Maintenant il nous faut dire aux Game Rules d'utiliser cette Table de Relations dans le jeu lorque l'on commence une partie de HL2DM. Ouvrez le fichier h2mp_gamerules.h. En dessous de l'onglet public:, ajoutez ceci:

//***THOMAS*** INITIALISE LA TABLE DES RELATIONS DES NPC ( =PNJ ) POUR HL2DM
#ifndef CLIENT_DLL 
void InitDefaultAIRelationships( void );
#endif
//***

A présent, ouvrez le fichier h2mp_gamerules.cpp. Ensuite tout en bas du fichier .cpp ajoutez tout ce bout de code:

//------------------------------------------------------------------------------
// Purpose : Initialize all default class relationships
// Input   :
// Output  :
//------------------------------------------------------------------------------
//***THOMAS*** INITIALISE LA TABLE DES RELATIONS DES NPC ( =PNJ ) POUR HL2DM
#ifndef CLIENT_DLL 
void CHL2MPRules::InitDefaultAIRelationships( void )
{
	//Copiez le contenu of de hl2_gamerules InitDefaultAIRelationships ici
}
#endif
//***

Terminons en ajoutant cette petite instruction dans la fonction CHL2MPRules::CHL2MPRules():

//***THOMAS*** INITIALISE LA TABLE DES RELATIONS DES NPC ( =PNJ ) POUR HL2DM
InitDefaultAIRelationships();
//***

Faire fonctionner les NPCs humanoides

Animations des Armes

Pour chaque arme, prendre le code SP de l'arme, et copier la liste des animations contenues dans la structure acttable_t. Procédez comme ci-dessous:

acttable_t	CWeaponSMG1::m_acttable[] = 
		{
			//DEPART ANIMATIONS HL2DM
			{ ACT_HL2MP_IDLE,		ACT_HL2MP_IDLE_SMG1,		false },
			( ... )
			{ ACT_RANGE_ATTACK1,		ACT_RANGE_ATTACK_SMG1,		false },
			//FIN ANIMATIONS HL2DM

			//DEPART ANIMATIONS HL2
			{ ACT_RANGE_ATTACK1,		ACT_RANGE_ATTACK_SMG1,		true },
			{ ACT_RELOAD,			ACT_RELOAD_SMG1,		true },
			{ ACT_IDLE,			ACT_IDLE_SMG1,			true },
			(...)
			{ ACT_GESTURE_RELOAD,		ACT_GESTURE_RELOAD_SMG1,	true },
			//FIN ANIMATIONS HL2

		}

Autres modifications sur les armes

Il faut à présent insérer le code qui permet à l'IA de controller son arme, en l'occurrence de tirer avec, de la recharger etc. Pour ce faire, il faut déclarer ces deux fonctions, côté serveur seulement:

#ifndef CLIENT_DLL
		//PERMET AUX NPC D'UTILISER CETTE ARME
		int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
		//GESTION DES ACTIONS DE L'IA
		void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
#endif
Note.pngNote:Vous trouverez le corps de la fonction Operator_HandleAnimEvent() dans votre copie du SDK. N'oubliez donc pas de l'insérer sinon vous risquez de génererer des erreurs à la compilation!

Suggestions de Garry Newman

Garry Newman suggérait sur des forums de modifier la fonction SetActivity(). Ainsi, dans le fichier basecombatweapon_shared.cpp, recherchez la fonction SetActivity(), et juste après e commentaire d'Adrien:

//Adrian: Oh man...

remplacez

#if !defined( CLIENT_DLL ) && defined( HL2MP )
	SetModel( GetWorldModel() );
#endif

par

	if ( GetOwner()->IsPlayer() )
		SetModel( GetWorldModel() );

Procédez de même après l'autre commentaire, vous remplacerez donc:

	//Adrian: Oh man again...
#if !defined( CLIENT_DLL ) && defined( HL2MP )
	SetModel( GetViewModel() );
#endif

par

	//Adrian: Oh man again...
	if ( GetOwner()->IsPlayer() )
		SetModel( GetViewModel() );

Bon, je ne sais pas si ça change queque chose ou pas, mais Garry insistait sur ce code, alors je suggère qu'en en tienne compte. Si quequ'un à le courage de tester pour voir s'il y a une différence ou pas avec ce code, qu'il m'en fasse part, merci.

Ammotypes

Après avoir activé mes NPCs humanoides, ces derniers me tuaient en une seule balle. Si vous avec le même problème, je vous suggère de trouver la fonction CAmmoDef *GetAmmoDef() dans le fichier hl2mp_gamerules.cpp, et de la remplacer entièrement par ce qui suit.

CAmmoDef *GetAmmoDef()
	{
		static CAmmoDef def;
		static bool bInitted = false;
	
		if ( !bInitted )
		{
			bInitted = true;

			//THOMAS: HL2SP DEFINITIONS
			def.AddAmmoType("AR2",				DMG_BULLET,					TRACER_LINE_AND_WHIZ,		"sk_plr_dmg_ar2",		"sk_npc_dmg_ar2",			"sk_max_ar2",			BULLET_IMPULSE(200, 1225), 0 );
			def.AddAmmoType("AlyxGun",			DMG_BULLET,					TRACER_LINE,			"sk_plr_dmg_alyxgun",		"sk_npc_dmg_alyxgun",		"sk_max_alyxgun",			BULLET_IMPULSE(200, 1225), 0 );
			def.AddAmmoType("Pistol",			DMG_BULLET,					TRACER_LINE_AND_WHIZ,		"sk_plr_dmg_pistol",		"sk_npc_dmg_pistol",		"sk_max_pistol",			BULLET_IMPULSE(200, 1225), 0 );
			def.AddAmmoType("SMG1",				DMG_BULLET,					TRACER_LINE_AND_WHIZ,		"sk_plr_dmg_smg1",		"sk_npc_dmg_smg1",			"sk_max_smg1",			BULLET_IMPULSE(200, 1225), 0 );
			def.AddAmmoType("357",				DMG_BULLET,					TRACER_LINE_AND_WHIZ,	"	sk_plr_dmg_357",		"sk_npc_dmg_357",			"sk_max_357",			BULLET_IMPULSE(800, 5000), 0 );
			def.AddAmmoType("XBowBolt",			DMG_BULLET,					TRACER_LINE,			"sk_plr_dmg_crossbow",		"sk_npc_dmg_crossbow",		"sk_max_crossbow",			BULLET_IMPULSE(800, 8000), 0 );

			def.AddAmmoType("Buckshot",			DMG_BULLET | DMG_BUCKSHOT,			TRACER_LINE,			"sk_plr_dmg_buckshot",		"sk_npc_dmg_buckshot",		"sk_max_buckshot",			BULLET_IMPULSE(400, 1200), 0 );
			def.AddAmmoType("RPG_Round",			DMG_BURN,					TRACER_NONE,			"sk_plr_dmg_rpg_round",		"sk_npc_dmg_rpg_round",		"sk_max_rpg_round",		0, 0 );
			def.AddAmmoType("SMG1_Grenade",			DMG_BURN,					TRACER_NONE,			"sk_plr_dmg_smg1_grenade",	"sk_npc_dmg_smg1_grenade",	"sk_max_smg1_grenade",	0, 0 );
			def.AddAmmoType("Grenade",			DMG_BURN,					TRACER_NONE,			"sk_plr_dmg_grenade",		"sk_npc_dmg_grenade",		"sk_max_grenade",		0, 0);
			def.AddAmmoType("Thumper",			DMG_SONIC,					TRACER_NONE,			10, 10, 2, 0, 0 );
			def.AddAmmoType("Gravity",			DMG_CLUB,					TRACER_NONE,			0,	0, 8, 0, 0 );
			def.AddAmmoType("Battery",			DMG_CLUB,					TRACER_NONE,			NULL, NULL, NULL, 0, 0 );
			def.AddAmmoType("GaussEnergy",			DMG_SHOCK,					TRACER_NONE,			"sk_jeep_gauss_damage",		"sk_jeep_gauss_damage", "sk_max_gauss_round", BULLET_IMPULSE(650, 8000), 0 ); // hit like a 10kg weight at 400 in/s
			def.AddAmmoType("CombineCannon",		DMG_BULLET,					TRACER_LINE,			"sk_npc_dmg_gunship_to_plr", 	"sk_npc_dmg_gunship", NULL, 1.5 * 750 * 12, 0 ); // hit like a 1.5kg weight at 750 ft/s
			def.AddAmmoType("AirboatGun",			DMG_AIRBOAT,					TRACER_LINE,			"sk_plr_dmg_airboat",		"sk_npc_dmg_airboat",		NULL,					BULLET_IMPULSE(10, 600), 0 );
			def.AddAmmoType("StriderMinigun",		DMG_BULLET,					TRACER_LINE,			5, 5, 15, 1.0 * 750 * 12, AMMO_FORCE_DROP_IF_CARRIED ); // hit like a 1.0kg weight at 750 ft/s
			def.AddAmmoType("HelicopterGun",		DMG_BULLET,					TRACER_LINE_AND_WHIZ,		"sk_npc_dmg_helicopter_to_plr", "sk_npc_dmg_helicopter",	"sk_max_smg1",	BULLET_IMPULSE(400, 1225), AMMO_FORCE_DROP_IF_CARRIED | AMMO_INTERPRET_PLRDAMAGE_AS_DAMAGE_TO_PLAYER );
			def.AddAmmoType("AR2AltFire",			DMG_DISSOLVE,					TRACER_NONE,			0, 0, "sk_max_ar2_altfire", 0, 0 );
			//***
		}

		return &def;
	}

Pour terminer

Le fichier skill.cfg

On m'a fait remarquer que les NPC ne causent pas de dommages au joueur, et en plus ils meurent très facilement. Ceci est simplement liée à l'absence du fichier skill.cfg dans le répertoire \cfg du mod. pour corriger l'erreur, il vous faut copier/coller le fichier skill.cfg du jeu Half-Life 2 dans le répertoire \cfg de votre mod.

Animations des Models

Pour en finir avec ces NPCs, il vous faut remplacer les animations des NPCs par celles d'origine. En clair, il faut remplacer les animations de HL2DM par celles de HL2, ce qui permettra à l'IA de fonctionner correctement car ee pourra utiliser ses propres animations, et non pas celles de H2DM qui sont différentes!

Il faut évidement utiliser d'autres animations pour les joueurs afin de ne pas corrompre leurs propres animations ( celles utiisées par HL2DM ).

Pour éviter de recompiler les models, il est préférable de les éditer avec un éditeur hexadécimal ( models de joueurs & noms des animations ). Pour vous faire gagner du temps, je vous suggère d'utiliser des models déjà hex-édités, par exemples ceux du Garry's mod.

Je vous ai préparé un petit package qui contient ce dont vous avez besoin pour faire fonctionner les Combine Soldiers et les Citoyens. En fait j'ai emprunté les models de Garry. Vous pouvez avec le ien vers le tléchargement à cette page.

Au fait, n'oubliez pas de prendre en compte ce changement dans le code, au niveau de la liste des models de joueurs dans le fichier hl2mp_player.cpp.