Créer une nouvelle touche

Écrit le 03/07/2003 par Kurim
Dernière mise à jour : 06/02/2006

Introduction

Dans ce tutorial on va apprendre à créer une nouvelle touche et à la rendre définissable dans le menu du jeu. J'ai pris comme thème pour cette touche la création d'un tir secondaire, mais je présenterai seulement la création de la touche, pas du tir... Bon bref, au travail :)

Création du bouton

Tout se passe ici dans cl_input.c. Cherchez la fonction CL_InitInput(), et ajoutez-y :

Cmd_AddCommand ("+attack2", IN_Attack2Down);
Cmd_AddCommand ("-attack2", IN_Attack2Up);

On a ici créé la commande qui considère le tir, et on l'a lié a deux fonction, Attack2Down et Attack2Up. L'étape suivante va consister à créer une variable qui gère l'état de la touche, puis à créer ces deux fonctions. Remontez au début du fichier et ajoutez :

kbutton_t    in_attack2;

kbutton_t est une structure qui contrôle l'état du bouton. Voici sa définition qui pourra vous servir quand vous coderez l'effet de votre touche :)

typedef struct
{
    int       down[2];   // key nums holding it down
    unsigned  downtime; // msec timestamp
    unsigned  msec;       // msec down this frame
    int       state;
} kbutton_t;

L'entier state sert bien sur à définir l'état de la touche, à savoir enfoncé ou relâché, et ce sous forme de flag. Les deux fonction Attack2Down et Attack2Up vont servir a ajuster ce flag en fonction du joueur par le billet de deux fonction préparées a cet usage, KeyUp et KeyDown. Vers la ligne :

void IN_Attack2Down(void) {KeyDown(&in_attack2);}
void IN_Attack2Up(void) {KeyUp(&in_attack2);}

Maintenant, étant donnée que notre bouton est un tir, et qu'on aura besoin d'une certaine souplesse pour tester s'il est enfoncé ou pas, et notamment s'il vient d'être enfoncé, on va ajouter ce code qui affecte une variable utilisée dans le fonctionnement du tir et de la touche action (use). Ce code ne s'applique qu'en cas d'une touche de tir, ou en cas de besoin pour votre action ! Ouvrez simplement q_shared.h, avancez vers la ligne 500 pour rajouter :

#define    BUTTON_ATTACK     1
#define    BUTTON_USE        2
#define    BUTTON_ATTACK2    4 /*Nouveau code*/
#define    BUTTON_ANY        128

Revenez à cl_input.c, cherchez la fonction void CL_FinishMove (usercmd_t *cmd) et modifiez la comme ceci :

if ( in_attack.state & 3 )
    cmd->buttons |= BUTTON_ATTACK;
in_attack.state &= ~2;

/*Nouveau code:*/
if ( in_attack2.state & 3 )
    cmd->buttons |= BUTTON_ATTACK2;
in_attack2.state &= ~2;

if (in_use.state & 3)
    cmd->buttons |= BUTTON_USE;
in_use.state &= ~2;

Ajout du bouton dans le menu de configuration

Tout d'abord j'aimerai vous faire remarquer que dans cette partie du code, l'ordre dans lequel les variables sont déclarées est important pour le bon fonctionnement du menu, et ce du à l'utilisation de pointeurs et de variables static. Prenez donc bien soin de placer vos lignes de code aux bons endroits. Ca se passe dans menu.c :

vers ligne 590, on donne le nom du bouton tel qu'il apparaît dans le menu de config :

char *bindnames[][2] =
{"+attack",            "attack"},
{"+attack2",           "attack secondaire"}, /*Nouveau code*/
{"weapnext",           "next weapon"},

vers la ligne 620, on déclare l'entrée du menu

static menuaction_s          s_keys_attack_action;
static menuaction_s          s_keys_attack2_action; /*Nouveau code*/
static menuaction_s          s_keys_change_weapon_action; 

Puis dans Keys_MenuInit, vers la ligne 750, on ajoute cette entrée lors de l'initialisation du menu :

s_keys_attack_action.generic.type = MTYPE_ACTION;
s_keys_attack_action.generic.flags = QMF_GRAYED;
s_keys_attack_action.generic.x = 0;
s_keys_attack_action.generic.y = y;
s_keys_attack_action.generic.ownerdraw = DrawKeyBindingFunc;
s_keys_attack_action.generic.localdata[0] = i;
s_keys_attack_action.generic.name = bindnames[s_keys_attack_action.generic.localdata[0]][1];

/* Nouveau code : */
s_keys_attack2_action.generic.type = MTYPE_ACTION;
s_keys_attack2_action.generic.flags = QMF_GRAYED;
s_keys_attack2_action.generic.x = 0;
s_keys_attack2_action.generic.y = y;
s_keys_attack2_action.generic.ownerdraw = DrawKeyBindingFunc;
s_keys_attack2_action.generic.localdata[0] = i;
s_keys_attack2_action.generic.name = bindnames[s_keys_attack2_action.generic.localdata[0]][1];

s_keys_change_weapon_action.generic.type = MTYPE_ACTION;
s_keys_change_weapon_action.generic.flags = QMF_GRAYED;
s_keys_change_weapon_action.generic.x = 0;
s_keys_change_weapon_action.generic.y = y += 9;
s_keys_change_weapon_action.generic.ownerdraw = DrawKeyBindingFunc;
s_keys_change_weapon_action.generic.localdata[0] = ++i;
s_keys_change_weapon_action.generic.name = bindnames[s_keys_change_weapon_action.generic.localdata[0]][1];

et enfin, à la fin de cette fonction, on ajoute l'entrée dans le menu :

Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_attack_action );
Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_attack2_action ); /*Nouveau code*/
Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_change_weapon_action );

Dernière remarque, n'oubliez pas d'éditer le default.cfg qui se trouve dans votre pak pour ajouter un bind par défaut a votre touche, sinon le joueur qui lancera le jeu sans configurer ses touches ne pourra l'utiliser.