[English]

NEWS
INTRODUCTION
TERMINOLOGIE
LE CODE SOURCE
LES BUGS
TUTORIAUX
DOWNLOADS
L'AUTEUR

  LES MODS: AJOUTER UN MOUVEMENT POUR LE PREDATOR AFIN DE CHANGER SON CYCLE DE VISION EN ARRIERE
Idée de mod par Titan

Un aspect des plus cool du Predator est son système multi-vision: une pression et les humains ne peuvent plus se cacher! Une autre et c'est la fête des Aliens ! Juste au cas où vous voulez voir vos amis, vous avez également cette pression... Un aspect des moins cool du Predator est qu'il perd son temps à faire basculer son système de vision pour trouver celle qui lui convient: une pression supplémentaire & vous êtes prêt pour refaire un cycle ! En résumé: le Chasseur devient le Chassé !
Ainsi, le but de ce tutorial est d'ajouter une nouvelle touche pour le Predator afin de lui faire basculer son système de vision en arrière. Dedans, nous changerons plus en détails le système de configuration des touches du joueur (étant donné que nous l'avons déjà manipulé dans le tutorial "Ajouter un mouvement pour le Marine afin de recharger ses armes") et cela constituera une introduction au système de vision du Predator. Comme dans le tutorial précédemment cité, vous aurez besoin de l'utilitaire Huffcomp provenant de l'archive avptools pour manipuler les chaînes de caractères, le Source Code d'AvP et plus important: aucune connaissance du Code Source !

1) Deux étapes principales pour faire ce mod

Aucune surprise à ce sujet: nous avons déjà rencontré un tutorial similaire pour Marine. Rapide sommaire pour les nouveaux-venus:
  • Premièrement, nous parlerons du menu de Configuration des Touches Predator et du code pour gérer les requêtes joueur sur la touche.
  • Deuxièmement, nous serons près à créer le nouveau mode de cycle de vision, c-à-d ledit "cycle de vision inverse".
2) Mise à jour du menu de Configuration des Touches Predator

Voici le fait: chaque fan d'AvP sait que vous pouvez redéfinir la configuration de vos touches pour chaque espèce et les remettre à un état par défaut. Ce qui est important de remarquer est que nous disposons de types de configuration par espèce: la "primaire" et la "secondaire". Le but de ce système est de vous laisser customiser votre clavier/souris avec 2 configurations. Ce que nous allons maintenant faire est d'ajouter une touche sous l'item de menu "Parcourir Modes Vision".

a) gestion des touches

La touche par défaut que nous choisirons pour ce mod est 'P' pour la config primaire et rien pour la secondaire. peut importe s'il s'agit du bon choix, vous pouvez la changer vraiment facilement: lisez juste attentivement ce qui suit...

Les touches dans AvP sont représentées par des constantes - également appelées "enums" dans les langages C/C++ - et c'est ce que nous aurons besoin d'utiliser dans le code: d'après ce que nous pouvons voir dans le fichier platform.h, l'enum KEY_ID est le bon endroit pour prendre ce que nous désirons. Dans ce cas, nous prenons l'enum KEY_P pour la touche 'P' et KEY_VOID pour la touche vide.

Maintenant, nous allons placer ces enums quelque part dans le code pour faire "comprendre" au jeu que nous allons enrichir les Configurations de Touches du Predator: l'astuce est d'ajouter les 2 enums dans le fichier usr_io.c: premièrement, trouvez la définition d'objet DefaultPredatorInputPrimaryConfig dans la section "English". Grâce aux commentaires (ils sont vraiment importants les dudes !), nous pouvons voir que l'enum KEY_SLASH, est la touche qui gère le Mode de Cycle de Vision commun. Donc juste après cela, ajoutez ce qui suit: KEY_P, // CycleVisionModeBack;. L'astuce est la même qu'avec l'objet DefaultPredatorInputSecondaryConfig, mais avec l'enum KEY_VOID.

b) affichage des touches

Ce qui suit parle du texte que nous allons ajouter dans le menu de Configuration des Touches Predator pour afficher nos précédents changements.

Dans AvP, les textes de base affichés - c-à-d les "textstrings" (ou "chaînes de caractères en anglais) - sont localisés dans un fichier externe: "language.txt". Ce qui est important de comprendre est que ce fichier est compressé et respecte une structure spéciale: celle-ci est dictée par l'enum TEXTSTRING_ID dans le fichier langenum.h, c'est à dire que chaque textstring est à la même place que chaque enum dans ce fichier. Donc dans notre cas, nous voulons que la nouvelle touche apparaisse dans le menu juste sous la "touche qui gère le cycle de vision" pour le Predator, c-à-d l'enum TEXTSTRING_PREDATOR_KEY_CYCLE_VISION, - pas si dure à comprendre hein ?! Afin de refléter nos changements, ajoutez juste après cette ligne: TEXTSTRING_PREDATOR_KEY_CYCLE_VISION_BACK, (notre nouvelle textstring pour la nouvele commande). Okay, maintenant que cela est fait, le fichier "language.txt" doit être également adapté. Voici donc ma petite manipulation (ici vous aurez besoin de l'utilitaire huffcomp):

Note importante: faites une copie de votre fichier "language.txt" original avant de faire ces manipulations, ou vous risquez probablement de le perdre...
  • allez en mode console sous Windows et tappez: huffcomp language.txt mylanguage.txt
    Cela décompressera le premier fichier vers le second.

  • ouvrez le fichier "mylanguage.txt", localisez la textstring "Parcourir Modes Vision" et juste après, placez la vôtre: "Retour Modes Vision". Sauvegardez et fermez le fichier.

  • maintenant, compressez votre nouveau fichier ressource avec: huffcomp mylanguage.txt language.txt.

  • finalement, vous pouvez supprimer le fichier "mylanguage.txt".
c) gestion des requêtes du joueur

A ce point, le jeu sait que le menu possède une nouvelle touche et qu'elle sera associée à une entrée joueur. Maintenant, ouvrez le fichier usr_io.h et regardez la structure PLAYER_INPUT_CONFIGURATION.

Cette structure représente toutes les entrées joueur, c-à-d toutes les entrées d'espèces. Ainsi, quelques unes sont communes (ex.: sauter, s'accroupir, etc...) et d'autres adaptées à chaque type de joueur (ex.: le camouflage du Predator, le vision infrarouge du Marine, etc...).

En revenant à notre structure, nous pouvons comprendre que sa première partie (les variables "unsigned char" séparées) est la partie commune d'entrées et la seconde (avec les mots clés "union") est la partie spécifique.

Donc, dans notre mod, nous voulons changer la partie du Predator en ajoutant une nouvelle entrée. Afin de garder l'intégrité de la structure, nous devons insérer notre entrée juste après celle nomée CycleVisionMode et parce que chaque union doit contenir seulement 1 entrée d'espèce, alors nous devons changer les unions comme suit:

typedef struct
{
unsigned char Forward;
unsigned char Backward;
unsigned char Left;
unsigned char Right;

unsigned char Strafe;
unsigned char StrafeLeft;
unsigned char StrafeRight;
unsigned char LookUp;

unsigned char LookDown;
unsigned char CentreView;
unsigned char Walk;
unsigned char Crouch;

unsigned char Jump;
unsigned char Operate;
unsigned char FirePrimaryWeapon;
unsigned char FireSecondaryWeapon;

union
{
unsigned char NextWeapon; // Predator & Marine
unsigned char AlternateVision; // Alien
};

union
{
unsigned char PreviousWeapon; // Predator & Marine
unsigned char Taunt; // Alien
};

union
{
unsigned char FlashbackWeapon; // Predator & Marine
unsigned char Alien_MessageHistory; // Alien
};

union
{
unsigned char Cloak; // Predator
unsigned char ImageIntensifier; // Marine
unsigned char Alien_Say; // Alien
};

union
{
unsigned char CycleVisionMode; // Predator
unsigned char ThrowFlare; // Marine
unsigned char Alien_SpeciesSay; // Alien
};

union
{
unsigned char CycleVisionModeBack; // Predator // ==> Notre nouvelle entrée Predator
unsigned char Jetpack; // Marine
unsigned char Alien_ShowScores; // Alien
};

union
{
unsigned char ZoomIn; // Predator
unsigned char MarineTaunt; // Marine
};

union
{
unsigned char ZoomOut; // Predator
unsigned char Marine_MessageHistory; // Marine
};

union
{
unsigned char GrapplingHook; // Predator
unsigned char Marine_Say; // Marine
};

union
{
unsigned char RecallDisc; // Predator
unsigned char Marine_SpeciesSay; // Marine
};

union
{
unsigned char PredatorTaunt; // Predator
unsigned char Marine_ShowScores; // Marine
};

unsigned char Predator_MessageHistory; // Predator
unsigned char Predator_Say;
unsigned char Predator_SpeciesSay;
unsigned char Predator_ShowScores;
unsigned char ExpansionSpace7;
unsigned char ExpansionSpace8;
} PLAYER_INPUT_CONFIGURATION;
Comme vous pouvez le voir, chaque entrée Predator à été déplacée vers le bas, donc nous avons augmenté la taille de la structure. Nous allons donc maintenant ajuster le jeu de manière à prendre en compte la nouvelle entrée.

Dans cet exemple, vous avez besoin de changer les lignes
#if PREDATOR_DEMO||DEATHMATCH_DEMO
#define NUMBER_OF_PREDATOR_INPUTS 30
#else
#define NUMBER_OF_PREDATOR_INPUTS 30
#endif
en:
#if PREDATOR_DEMO||DEATHMATCH_DEMO
#define NUMBER_OF_PREDATOR_INPUTS 30
#else
#define NUMBER_OF_PREDATOR_INPUTS 31
#endif
(localisées juste au-dessus de la structure).

Okay, nous avons donc notre nouvelle entrée CycleVisionModeBack: dans AvP, cette variable sera accessible à partir du tableau KeyboardInput (KeyboardInput[primaryInput->CycleVisionModeBack] pour la config primaire et KeyboardInput[secondaryInput->CycleVisionModeBack] pour la secondaire).

L'entrée du joueur devrait maintenant correspondre à une requête joueur: dans le fichier bh_types.h, localisez la structure PLAYER_INPUT_REQUESTS et dans la section Predator, juste après la requête Rqst_CycleVisionMode, placez la ligne unsigned int Rqst_CycleVisionModeBack :1;. Maintenant, ouvrez le fichier usr_io.c et dans la procédure void InitPlayerGameInput(STRATEGYBLOCK* sbPtr), sous la ligne playerStatusPtr->Mvt_InputRequests.Mask2 = 0;, ajoutez celle-ci: playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Jetpack = 0;.

Voyez la note spéciale à la fin de ce tutorial si vous voulez plus de détails sur cette ligne...

La dernière chose à faire est d'associer l'entrée joueur avec la requête joueur dans la procédure void ReadPlayerGameInput(STRATEGYBLOCK* sbPtr): dans la section "ckeck for character specific abilities", partie Predator, ajoutez les lignes suivantes:
( . . . )
if(DebouncedKeyboardInput[primaryInput->CycleVisionMode]
||DebouncedKeyboardInput[secondaryInput->CycleVisionMode])
playerStatusPtr->Mvt_InputRequests.Flags.Rqst_CycleVisionMode = 1;
// Ici nous testons l'état d'entrée pour activer notre nouvele requête
if(DebouncedKeyboardInput[primaryInput->CycleVisionModeBack]
||DebouncedKeyboardInput[secondaryInput->CycleVisionModeBack])
playerStatusPtr->Mvt_InputRequests.Flags.Rqst_CycleVisionModeBack = 1;
#if !(PREDATOR_DEMO||DEATHMATCH_DEMO)
if(DebouncedKeyboardInput[primaryInput->GrapplingHook]
||DebouncedKeyboardInput[secondaryInput->GrapplingHook])
playerStatusPtr->Mvt_InputRequests.Flags.Rqst_GrapplingHook = 1;
#endif

( . . . )
A ce point, le jeu peut être compilé, mais FAITES ATTENTION DE NE PAS L'EXECUTER AVANT D'AVOIR LU LE TROISIEME CHAPITRE, ou vous bousillerez vos fichiers de configuration...

3) Créer l'effet de mouvement

Maintenant que notre touche est associée à une entrée et cette dernière, à une requête, nous avons besoin de créer l'effet de mouvement désiré (c-à-d le cycle de vision dans le sens inverse) et d'adapter le gestionnaire de mouvements.
a) l'effet de mouvement

Okay, donc tout ce que nous avons besoin de faire est de créer un autre cycle de vision pour le Predator: cela est géré dans le fichier Vision.c. Juste après la procédure extern void ChangePredatorVisionMode(void), ajoutez le code suivant:
extern void ChangePredatorVisionModeBack(void) // Notre nouveau cycle de vision Predator
{
switch (CurrentVisionMode)
{
case VISION_MODE_NORMAL:
{
CurrentVisionMode=VISION_MODE_PRED_SEEPREDTECH;
break;
}
case VISION_MODE_PRED_THERMAL:
{
CurrentVisionMode=VISION_MODE_NORMAL;
break;
}
case VISION_MODE_PRED_SEEALIENS:
{
CurrentVisionMode=VISION_MODE_PRED_THERMAL;
break;
}
case VISION_MODE_PRED_SEEPREDTECH:
{
CurrentVisionMode=VISION_MODE_PRED_SEEALIENS;
break;
}
}
Sound_Play(SID_VISION_ON,"h");
PredatorVisionChangeCounter=ONE_FIXED;
}
b) adaptation du gestionnaire de mouvements

Finissons ces modifications de code source avec la mise à jour du gestionnaire de mouvements: ouvrez juste le fichier Pmove.c, puis localisez la procédure void ExecuteFreeMovement(STRATEGYBLOCK* sbPtr) et juste après

if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_CycleVisionMode)
{
ChangePredatorVisionMode();
}
ajoutez le code suivant :
if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_CycleVisionModeBack) {
ChangePredatorVisionModeBack();
}
4) Utiliser le mod

Comme vous l'avez probablement vu dans le tutorial "Ajouter un mouvement pour le Marine afin de recharger ses armes", ce genre de mod ne peut pas être utilisé directement dans votre répertoire AvP pour une simple raison: nous avons changé le système de configuration, donc cela ne sera pas compatible avec l'AvP original. C'est pourquoi la manière la plus simple de l'utiliser est de copier votre dossier AvP, placer votre exécutable dans cette copie et supprimer votre/vos profil(s).

Après cela, vous pouvez démarrer le jeu, sélectionner n'importe quel mode de jeu, tester votre nouveau mouvement, changer votre configuration...

5) Conclusion

Nous avons vu que pour ajouter un tel mouvement joueur, nous avons dû changer le Menu des Touches Predator, en ajoutant un nouvel item dans la liste des mouvements que nous avons appelé "Retour Modes Vision" et en mettant plus profondément à jour les entrées joueur et le système de requêtes. Finalement, nous avons ajouté le nouveau mouvement, qui consistait à préparer une nouvelle procédure pour le Système de Vision du Predator, le chemin le plus simple pour arriver à notre but selon moi.

J'espère qu'en contraste avec le tutorial pré-cité, vous avez compris quelles contraintes nous pouvons rencontrer en créant de tels mods.

Note spéciale:
La raison pour l'ajout d'une telle ligne est la même que celle exposée dans le tutorial "Ajouter un mouvement pour le Marine afin de recharger ses armes", mais cette fois, notre nouvelle requête n'était pas la dernière dans la structure PLAYER_INPUT_REQUESTS, donc le résultat était que la requête Rqst_Jetpack est devenus le 33ème bit de la structure, c-à-d un bit au-dessus de la taille size de la variable PLAYER_STATUS.Mvt_InputRequests.Mask et donc, quand cette dernière est remise à 0 (dans la procédure void InitPlayerGameInput(STRATEGYBLOCK* sbPtr) du fichier usr_io.c), le reste de cette structure se retrouve inchangée: l'effet produit serait une boucle infinie pour l'activation du Jetpack du Marine !!!