Le "SpellHook" est un système offert par les concepteurs de NWN pour nous permettre de modifier le système de sorts.
Il commence par une action simple : Définir un script principal (pour mon exemple, le script s'appellera "spells_custom")
Pour définir ce script, il y aura deux méthodes possibles. La première consiste à mettre une variable sur le module, dont la valeur (de type string) fera référence à un script :
Name : X2_S_UD_SPELLSCRIPT (respecter les majuscules)
ValueString : spells_custom
VariableType : String
La seconde consiste à rajouter quelques lignes dans le script de l'événement du module "OnModuleLoad" :
// Avant la partie "void main()", j'inclus la
// bibliothèque de fonctions "x2_inc_switches" :
#include "x2_inc_switches"
// Dans la partie "void main()", je définis mon script
// grâce à la fonction "SetModuleOverrideSpellscript(...)" :
SetModuleOverrideSpellscript("spells_custom");
Je pourrai ainsi créer mon script "
spells_custom" dans lequel je pourrai faire toutes les modifications que je souhaite apporter au système de sorts.
Une fonction primordiale est "
SetModuleOverrideSpellScriptFinished()" qui empêchera les scripts des sorts de se lancer. Pratique lorsque l'on veut interdire la magie à certains endroits, définir une composante matérielle, ou modifier le fonctionnement d'un ou plusieurs sorts. Cette fonction se placera en général à la fin de notre script de SpellHook. Pour utiliser cette fonction, il faudra faire appel à la bibliothèque de fonctions "x2_inc_switches".
Les fonctions suivantes fonctionneront comme pour le système de sorts standard :
-
GetSpellCastItem() : Définit l'objet qui a servi à lancer le sort (s'il y a lieu)
-
GetSpellFeatId() : Définit le don utilisé (s'il y a lieu)
-
GetSpellId() : Définit quel sort est en train d'être lancé
-
GetSpellLevel() : Définit le niveau du sort
-
GetSpellResistance(...) : Définit la résistance magique de l'objet placé en paramètre
-
GetSpellSaveDC() : Définit le seuil de difficulté pour un éventuel jet de sauvegarde
-
GetSpellTargetLocation() : Définit la localisation ciblée (dans le cas d'un sort de zone, par exemple)
-
GetSpellTargetObject() : Définit l'objet cible du sort
Sous réserve de tests, la fonction "
GetLastSpellCastClass()" pourrait permettre de déterminer quel classe a été utilisée pour lancer le sort. Cette fonction s'utilise normalement lors d'un événement "OnSpellCastAt", mais il est possible qu'elle ait une utilité pendant l'incantation d'un sort.
Dans un script SpellHook, comme dans n'importe quel script de sort, la commande "
OBJECT_SELF" définit le lanceur du sort.
Enfin, il ne reste plus qu'à déterminer quel sera le contenu de mon script "spells_custom" :
#include "x2_inc_switches"
void main()
{
// imaginons que le joueur doive absolument porter une
// bague (tag : "BAGUE_SORTS") pour lancer ses sorts :
object oBague1 = GetItemInSlot(INVENTORY_SLOT_LEFTRING, OBJECT_SELF);
object oBague2 = GetItemInSlot(INVENTORY_SLOT_RIGHTRING, OBJECT_SELF);
// Si le joueur n'a pas cette bague, on termine
// le script et on signale au module que le script
// du sort ne doit pas s'exécuter :
if(GetTag(oBague1)!="BAGUE_SORTS" && GetTag(oBague2)!="BAGUE_SORTS")
{
SetModuleOverrideSpellScriptFinished()
return;
}
// Imaginons que le joueur se situe dans une zone
// (tag : "ZONE_ANTIMAGIE") où la magie est interdite :
if(GetTag(GetArea(OBJECT_SELF)) == "ZONE_ANTIMAGIE")
{
SetModuleOverrideSpellScriptFinished();
return;
}
// Imaginons que le sort "Boule de feu" doit être modifié :
if(GetSpellId() == SPELL_FIREBALL)
{
// Modification du sort...
// bla bla... etc. etc.
SetModuleOverrideSpellScriptFinished();
// Si le sort subit seulement quelques modifications, et que
// le script original peut quand même s'exécuter, il suffit de
// ne pas utiliser la fonction "SetModuleOverrideSpellScriptFinished()"
return;
}
// Imaginons que le sort "Boule de feu" est lancé...
if(GetSpellId() == SPELL_FIREBALL)
{
// ... et qu'il ne peut pas affeter un PNJ bien précis...
if(GetTag(GetSpellTargetObject()) == "PNJ_BIEN_PRECIS")
{
SetModuleOverrideSpellScriptFinished();
return;
}
// ... ou qu'il nécessiste une composante matérielle (tag : "COMP_FIREBALL")
if(GetItemPossessedBy(OBJECT_SELF, "COMP_FIREBALL") == OBJECT_INVALID)
{
SetModuleOverrideSpellScriptFinished();
return;
}
}
}
Voila voila.