[SCRIPT] Bonnes pratiques

Répondre
Partager Rechercher
J'espère faire ici un petit regroupement des bonnes pratiques de codage à employer sous NWN. Cela s'adresse principalement à des gens qui savent coder (ou qui apprennent), afin de leur donner une méthodologie de travail pour leur module.

J'étofferais sûrement ce post à l'avenir.



Sommaire
  1. Bien nommer ses scripts
  2. De l'importance des noms de variables
  3. Créez vos constantes
  4. Factoriser : Les bibliothèques de fonctions
  5. Utiliser les variables
1. Bien nommer ses scripts
C'est important, et pourtant peu nombreux sont ceux qui y pensent vraiment. Les noms des scripts sont très importants ; ils doivent indiquer leur rôle, et l'élément sur lequel ils s'appliquent, le cas échéant.


C'est une méthodologie à prendre en compte dès la création d'un module. Cela permet d'éviter les soucis du style :
  • Ne pas retrouver un script parmi la centaine que vous avez déjà fait et appelés "truk_bidule" et "machin"
  • Refaire des scripts en double pour cette même raison précédente
  • Etc...
Adonc, adoptez tout de suite une bonne sémantique des noms de scripts. Pour exemple :
ressource_événement_nom

Le problème, c'est que NWN ne permet qu'un nombre de caractères limités. Utilisez-en un maximum !


Voici des exemples de noms de scripts intelligents :
  • Script de porte à mettre sur l'événement OnOpen des portes : door_onopen
  • Script de PNJ à mettre sur l'événement OnSpawn des gardes : npc_spawn_gardes
  • Script de connexion d'un joueur à mettre sur l'événement OnClientEnter du module : mod_cliententer
  • Script de l'item "objet mj" qui se déclenche à l'utilisation : itm_objetmj
  • Script de plaçable quelconque : plc_onused
Cela peut sembler inutile, mais c'est une très bonne habitude à prendre, ne serait-ce que pour vos propres nerfs par la suite. Quand vous recherchez un script, vous n'avez plus besoin de vous souvenir comment il s'appelle : il porte un nom logique. Pour vos portes, vous cherchez "door_", pour votre module vous cherchez "mod_", etc.


2. De l'importance des noms de variables

Là encore, cela peut vous sembler anodin, mais il n'en est rien. Le soucis de NWN, c'est de ne pas gérer proprement les accents, aussi si vous maîtrisez l'anglais, je vous suggère de faire des noms de variables en anglais.

L'autre "soucis", si c'en est un, est que les scripts par défaut de NWN utilisent des variables créées avec ce qu'on appelle la notation hongroise, c'est à dire l'ajout d'un caractère devant le nom de variable qui définit son type. Bien que logique en soit, c'est un concept plutôt dépassé en programmations. Du reste, les variables de NWN sont signées, c'est à dire que contrairement au PHP par exemple, elles ont un type propre (int, float, string, object, effect...), donc le risque de se tromper est minime, sachant que le compilateur vous signalera que le type de variable n'est pas le bon si vous vous trompez.

Que vous conserviez ou non cette notation, surtout donnez des noms explicites à vos variables ! N'hésitez pas à prendre de la place, la taille des variables n'a pas d'importance.

Songez que vos scripts feront parfois plusieurs dizaines, voire centaines de lignes ! Vous ne vous y retrouverez pas avec des variables nommées "iXP1", "sBienv", "fDistAr". Clairement pas. Alors que l'emploi de noms clairs et explicites, même si longs, vous évitera de chercher à quoi correspond telle ou telle variable : "xpActuelDuJoueur", "messageDeBienvenueNouveauJoueur", "distanceDeTirDesArchers".

C'est forcément plus simple de s'y retrouver, non ?


3. Créez vos constantes

Encore quelque chose qui peut s'avérer utile : la création d'une liste de constantes, au sein d'un script à inclure au besoin. Les constantes sont des sortes de variables, qui restent les mêmes pour tout le monde, et ne peuvent être modifiées une fois créées.

Les constantes s'écrivent toujours en majuscules. Encore une fois, utilisez des noms explicites ! On déclare des constantes comme une variable normale, si ce n'est qu'on ajoute le tag const devant.

Code PHP:

const string NOM_MODULE "Mon super module";
const 
int TEMPS_DE_REPOS 2
C'est simple à faire, ça coûte rien, et ça fait ben d'bien au chien !

L'intérêt ? Imaginez que vous gériez une base de données (c'est courant pour un module persistant). Vous allez devoir faire plusieurs scripts, plusieurs fonctions qui appellent ces bases de données, pour les charger ou écrire dedans. Maintenant que vous avez plus d'une trentaine de scripts qui appellent la BDD, horreur, vous devez changer le nom d'une des tables de la base ! Il va falloir modifier tous ces scripts, ça va faire des bugs à cause d'oublis, et un travail conséquent.

Sauf si vous définissez des constantes ! Exemple :

On définit une constante pour l'utilisation de la table "GestionBanque", qui recevra les sommes détenues par chaque personnage.
Code PHP:

const string BDD_BANQUE "GestionBanque"
Pour chaque fonction et script, plutôt que de définir le nom de la table "GestionBanque", vous allez faire un appel à la constante "BDD_BANQUE". Ainsi, il suffira de modifier cette constante une seule fois pour que la modification soit prise en compte par tous les scripts qui font référence à cette constante.


4. Factoriser : Les bibliothèques de fonctions

Créez vos propres fonctions ! Plutôt que d'utiliser le même bout de code plusieurs fois, il suffit simplement de créer une fonction, et de l'appeler ! C'est simple et efficace. Pour modifier la fonction sur l'ensemble du module, il n'y a qu'un seul endroit où le gérer ! C'est ça, factoriser.

Exemple : Un script simple qui donne une certaine quantité d'xp en fonction de la race du personnage :

Code PHP:

void main()
{
 
object oPC /*à définir*/;
 
int xpFinalRecu;
 
 switch(
GetRacialType(oPC))
 {
   case 
RACIAL_TYPE_DWARF iXPfinal 500; break;
   case 
RACIAL_TYPE_ELF iXPfinal 250; break;
   case 
RACIAL_TYPE_GNOME iXPfinal 350; break;
   case 
RACIAL_TYPE_HALFELF iXPfinal 350; break;
   case 
RACIAL_TYPE_HALFLING iXPfinal 400; break;
   case 
RACIAL_TYPE_HALFORC iXPfinal 100; break;
   case 
RACIAL_TYPE_HUMAN iXPfinal 600; break;
   default: 
iXPfinal 400; break;
  }
  
GiveXPToCreature(oPCxpFinalRecu);

Vous allez donc écrire ce script autant de fois que nécessaire, entièrement. Ça peut vouloir dire 40 scripts identiques, juste pour ça. La solution ? Faire une fonction !

Code PHP:

int XPRecompenseParRace(object oPCint iXP)
{
 
int iXPfinal;
 switch(
GetRacialType(oPC))
 {
  case 
RACIAL_TYPE_DWARF iXPfinal iXP*50/100; break;
  case 
RACIAL_TYPE_ELF iXPfinal iXP*50/100; break;
  case 
RACIAL_TYPE_GNOME iXPfinal iXP*75/100; break;
  case 
RACIAL_TYPE_HALFELF iXPfinal iXP; break;
  case 
RACIAL_TYPE_HALFLING iXPfinal iXP*75/100; break;
  case 
RACIAL_TYPE_HALFORC iXPfinal iXP; break;
  case 
RACIAL_TYPE_HUMAN iXPfinal iXP; break;
  default: 
iXPfinal iXP; break;
 }
 return 
iXPfinal;

Ainsi vous avez une seule fonction qui renvoie une valeur de type int, l'xp calculé que vous voulez donner à vos joueurs. Dans vos scripts, il suffira alors d'appeler la fonction, de cette manière :
Code PHP:

GiveXpToCreature(oPCXPRecompenseParRace(oPC1000)); 

Bien entendu, vous écrivez vos fonctions dans un script que vous incluez par la suite lorsque vous en avez besoin.


5. Utiliser les variables

NWN permet d'ajouter des variables automatiques aux plaçables et aux pnj, ainsi que sur le module et les zones. Ces variables se trouvent dans les propriétés des objets, généralement dans l'onglet "avancés".

variables-31c2f53.jpg

vous avez à disposition 3 types de variables : int, float, string.

var-31c2f66.jpg

À partir de là, vous pouvez donc ajouter des variables sur chaque objet de votre choix, par exemple une porte, pour définir si elle doit se fermer la nuit par exemple, ou au bout de combien de temps elle doit se refermer.

Vous pouvez donc allègrement créer des scripts génériques, qui lancent des fonctions si une variable et présente, ou exécutent telle ou telle action en fonction de ces mêmes variables.

Un exemple simple d'utilisation : Certaines zones autorisent ou non le port d'arme dans une main il suffit d'ajouter dans les variables de la zone un int "armeInterdite", et de mettre la valeur à 1. Sur l'événement OnEnter des zones, un seul script pour toutes les zones, vous vérifiez par une condition si la zone possède la variable "armeInterdite", et si c'est le cas, vous exécutez un bout de code pour déséquiper automatiquement une arme.

Ainsi vous pouvez avoir un seul script pour toutes vos portes, toutes vos zones, etc. !


Conclusion

Il y a sûrement des choses à ajouter. Je mettrais peut-être d'avantages d'exemples plus concrêts. Le but ici est surtout de sensibiliser à l'utilisation intelligente des ressources offertes par Aurora pour avoir un module le plus optimisé possible, car c'est ce qui permet à ce dernier d'être stable et évolutif.

En espérant que ce post vous ait été utile.

Dernière modification par warpShadow ; 20/02/2012 à 16h19.
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés