Warcraft III

Sort poison avec GC (Jass)

Introduction

Cet article va vous expliquer comment réaliser un simple sort de poison en utilisant le "rustinage" au Gamecache. Dans cet article vous apprendrez à manipuler le gamecache au travers d'un compteur temps, ce qui se fait très souvent.
Le sort sera un sort actif contre une unique cible ennemie, l'unité subira X points de dégâts par seconde pendant Y secondes. Les dégâts varieront selon le niveau du sort.

I- Pré-requis:

Lisez tout d'abord l'excellent tutorial de Bantas qui explique l'utilisation du GC.
Rustinage au Game cache par Bantas
Et cette liste de fonction à copier dans le script personnalisé de votre map si ce n'est pas déjà fait.
Liste des fonctions du rustinage au GC (pas encore en ligne, version rtf à télécharger)

II- Le sort:

Utilisez un sort de base avec cible requise: prenez canaliser si vous savez utiliser ce sort sinon prenez le sort Bouclier de foudre. Retirez tout les effets de votre sort, par exemple si vous avez pris Bouclier de foudre retirez les dégâts infligés aux unités proches et modifiez l'effet d'éclair par un effet de poison.
Il ne faut garder qu'un sort basique n'ayant aucun effet, appelez ce sort "Poison".

III- Le déclencheur GUI de base:

IV- Le déclencheur Jass:

A-Fonction Trig_Sort_Poison_Actions:

1) Les variables

Cette fonction est le point de départ de notre sort. C'est ici que nous allons créer un compteur temps (timer) et y attaché les données nécessaires pour le sort (cible, dégâts, durée etc..)

Tout d'abord nous récupérons les informations essentielles relatives au sort qui vient d'être lancé:

local unit caster = GetSpellAbilityUnit()		// L'unité qui lance le sort
local unit target = GetSpellTargetUnit()		// L'unité ennemie ciblée par le sort
local integer lvl = GetUnitAbilityLevel( GetSpellAbilityUnit(), GetSpellAbilityId())	// Niveau du sort

Puis les informations complémentaires au sort que nous choisissons:

local real dmg = lvl * 15	// Points de dégâts infligés par le sort chaque seconde
local real duree = 10.0		// Durée du sort en secondes

Enfin les informations nécessaires pour le déroulement du sort et le stockage des données:

local timer t = CreateTimer()		// Le compteur temps pour le déroulement du sort
local string m = I2S(H2I( t ))	// L'adresse de la variable du compteur temps pour le stockage des données

Premier aperçu de ce vous devriez avoir pour cette fonction:

function Trig_Sort_Poison_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()		// L'unité qui lance le sort
local unit target = GetSpellTargetUnit()		// L'unité ennemie ciblée par le sort
local integer lvl = GetUnitAbilityLevel( GetSpellAbilityUnit(), GetSpellAbilityId())	// Niveau du sort
local real dmg = lvl * 15	// Points de dégâts infligés par le sort chaque seconde
local real duree = 10.0		// Durée du sort en secondes
local timer t = CreateTimer()		// Le compteur temps pour le déroulement du sort
local string m = I2S(H2I( t ))	// L'adresse de la variable du compteur temps pour le stockage des données
endfunction

2) Le stockage des données dans le GC

Nous avons précédemment récupérer l'adresse du compteur temps dans la variable "m", cela va nous permettre de stocker les données dans le GC sous ce nom de dossier.

call StoreInteger( udg_GC, m, "caster", H2I(caster) )	// Le lanceur de sort, conversion d'unité à entier
call StoreInteger( udg_GC, m, "caster", H2I(target) )	// La cible du sort, conversion d'unité à entier
call StoreReal( udg_CG, m, "damage", dmg )		// Les dommages du sorts, stockage d'un réel
call StoreReal( udg_GC, m, "duree", duree )		// Durée du sort, cette durée sera décrémenté à chaque itération (chaque seconde)

A partir de là il ne reste plus qu'à lancer le compteur temps qui exécutera une fonction chaque seconde, c'est dans cette fonction que seront infligé les dégâts.

3) Lancement du compteur temps

La fonction pour lancer un compteur s'appelle TimerStart, elle se compose ainsi:

natives TimerStart takes timer whichTimer, real timeout, boolean periodic, code handlerFunc returns nothing
Paramètres d'entrées: Dans notre cas:
call TimerStart( t, 1.0, true, function Poison )

Lance le compteur "t" qui expire au bout d'1 seconde et qui exécute la fonction Poison. Le compteur se relance après expiration.

Au final, pour la fonction Trig_Sort_Poison_Action, vous obtenez ceci:

function Trig_Sort_Poison_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()		// L'unité qui lance le sort
local unit target = GetSpellTargetUnit()		// L'unité ennemie ciblée par le sort
local integer lvl = GetUnitAbilityLevel( GetSpellAbilityUnit(), GetSpellAbilityId())	// Niveau du sort
local real dmg = lvl * 15	// Points de dégâts infligés par le sort chaque seconde
local real duree = 10.0		// Durée du sort en secondes
local timer t = CreateTimer()		// Le compteur temps pour le déroulement du sort
local string m = I2S(H2I( t ))	// L'adresse de la variable du compteur temps pour le stockage des données

call StoreInteger( udg_GC, m, "caster", H2I(caster) )	// Le lanceur de sort, conversion d'unité à entier
call StoreInteger( udg_GC, m, "caster", H2I(target) )	// La cible du sort, conversion d'unité à entier
call StoreReal( udg_CG, m, "damage", dmg )		// Les dommages du sorts, stockage d'un réel
call StoreReal( udg_GC, m, "duree", duree )		// Durée du sort, cette durée sera décrémenté à chaque itération (chaque seconde)

call TimerStart( t, 1.0, true, function Poison )
endfunction

B- Fonction Poison:

1) Création de la fonction

Cette fonction n'est pas initialement présente dans le déclencheur, c'est à l'intérieur de cette fonction que nous allons infliger les points de dégâts à l'unité ciblée chaque seconde.
Insérez la fonction Poison juste avant la fonction Trig_Sort_Poison_Actions, voilà l'en-tête:

function Poison takes nothing returns nothing

endfunction

2) Variables

Dans un premier temps nous allons récupérer toutes les valeurs qui sont stockées dans le gamecache sous l'identifiant du compteur temps.

local timer t = GetExpiredTimer()	//On récupère le compteur qui a lancé la fonction
local string m = I2S(H2I(t))		// Identifiant unique du compteur
local unit caster = H2U( GetStoredInteger( udg_GC, m, "caster") )	// Récupération du lanceur de sort
local unit target = H2U( GetStoredInteger( udg_GC, m, "target") )	// Récupération de la cible du sort
local real dmg = GetStoredReal( udg_GC, m, "dmg") )			// Récupération des dommages à infliger
local real duree = GetStoredReal( udg_GC, m, "duree") )		// Récupération de la durée restante
Désormais nous avons toutes les variables nécessaires à notre sort.

3) Dommages et réduction de la durée restante

Cette partie reste très simple, points de dégâts à infliger:

call UnitDamageTarget( caster, target, dmg, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)

Réduction de la durée:

set duree = duree - 1.0
call StoreReal( udg_GC, m, "duree", duree)

4) Fin du sort et destruction des données

Lorsque les Y secondes se sont écoulées -> variable "duree" inférieur ou égal à 0.0 OU que la cible est morte, il est nécessaire de stopper le sort, détruire le compteur et libérer la mémoire utilisée dans le GC.

if( duree <= 0.0 or IsUnitDeadBJ(target)) then
call FlushStoredMission(udg_GC, m)	// Libère la mémoire utilisée par le gamecache
call DestroyTimer(t)			// Détruit le compteur
endif

5) Nettoyage pour éviter les petites fuites de mémoires

Avant le "endfunction" ajoutez ces quelques lignes:

set t = null
set caster = null
set target = null

Au final votre fonction "Poison" devrait ressembler à ceci:

function Poison takes nothing returns nothing
local timer t = GetExpiredTimer()	//On récupère le compteur qui a lancé la fonction
local string m = I2S(H2I(t))		// Identifiant unique du compteur
local unit caster = H2U( GetStoredInteger( udg_GC, m, "caster") )	// Récupération du lanceur de sort
local unit target = H2U( GetStoredInteger( udg_GC, m, "target") )	// Récupération de la cible du sort
local real dmg = GetStoredReal( udg_GC, m, "dmg") )			// Récupération des dommages à infliger
local real duree = GetStoredReal( udg_GC, m, "duree") )		// Récupération de la durée restante

call UnitDamageTarget( caster, target, dmg, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
set duree = duree - 1.0
call StoreReal( udg_GC, m, "duree", duree)

if( duree <= 0.0 or IsUnitDeadBJ(target)) then
call FlushStoredMission(udg_GC, m)	// Libère la mémoire utilisée par le gamecache
call DestroyTimer(t)			// Détruit le compteur
endif

set t = null
set caster = null
set target = null
endfunction

V-Conclusion:

Le sort est terminé, il est extrèmement basique, ce qui importe c'est la technique utilisée. Vous pouvez désormais exploiter cette technique pour réaliser énormément de sorts bien plus intéressant. Bien que basique ce sort est multi-instanciable, facile à réaliser en JASS mais quasiment impossible en GUI.