Auteur : John Howe
 

Petit tutorial de scriptage

Démarré par Heralios, 2012-04-04, 00:32:38

« précédent - suivant »

Heralios



LES ITEMS SIMPLES


Les objets simples sont les objets courants que nous pouvons voir en grande quantité sur les serveurs (mur, rabot, , pièce d'or, bourse...). Ces objets, même s'ils sont simples doivent être définis selon plusieurs attributs, les voici : (Si j'en oublie, merci de m'en faire part!)

[ITEMDEF x]
DEFNAME=x
ID=x
NAME=x
WEIGHT=x
TYPE=x
RESOURCES=x
SKILLMAKE=x
VALUE=x
TDATA1=x
TDATA2=x
TDATA3=x
TDATA4=x
DUPELIST=x
DUPEITEM=x
CATEGORY=x
SUBSECTION=x
DESCRIPTION=x


[ITEMDEF x]
Ceci dit à Sphere "Je veux créer un nouvel objet avec comme définition x". En gros, Sphere utilisera les prochaines lignes pour définir chaque attribut de l'objet, c'est ce qui suivra. Vous pourrez faire apparaitre cet objet grâce à la commande ".add x". Il est recommandé de commencer votre nom avec "i" comme dans l'exemple "i_roche" pour montrer que c'est un objet ordinaire. Les objets de type "memory" commenceront avec "m"... etc.

DEFNAME=x
Cette ligne est purement inutile, sauf si vous voulez utiliser un deuxième nom pour votre objet. Vous pourrez utiliser le x de ITEMDEF ou celui de DEFNAME pour faire un ".add". Si vous ne voulez pas un deuxième nom, supprimez cette ligne.

ID=x
Cette ligne donnera tout simplement forme à votre objet. Il vous faudra de ce fait connaître exactement le ID que vous voulez. Par exemple, x=0475 donnera un foyer, x=0dfc donnera un ciseau... etc. Dans les fichiers "sphereitem", vous pourrez les trouver.

NAME=x
Sans vous étonner, x sera ni plus ni moins que le nom qu'aura cet objet.

WEIGHT=x
x sera le poids de l'objet. Faites tout de même attention car Sphere prend les décimales même si vous n'en mettez pas. Donc x=2 ou x=0.2 donnera la même chose. Si vous voulez un poids de 50, mettez x=50.0 ou x=500.

TYPE=x
x sera le type de votre objet. Chaque type d'objet réagit différemment aux événements comme double-click, click, step, à la magie, etc. Par exemple, le type "t_door" réagit par défaut au double click en ouvrant la porte, le type "t_armor" réagit par défaut au double click en équippant cette armure. Il est tout à fait possible de redéfinir le ON = @DCLICK sur un objet t_armor pour que l'objet ne s'équippe pas, mais lance une éclair par exemple, mais tout cela sera vu dans un autre guide. En gros, ce que vous devez savoir, c'est que la définition du type sert uniquement à ce que Sphere sache quoi faire avec un objet lorsqu'un événement survient. Dans le cas contraire, il renvoit un message style "Vous ne savez pas utiliser cet objet". Tous les types sont notés dans le fichier "spheredefs.scp"

RESSOURCES=x
Ici seront inscrits toutes les ressources qui devront être en possession du joueur pour produire cet objet. Si plus d'une ressource est nécessaire à sa construction, ces ressources devront être séparés par une virgule. Par exemple, un instrument de musique pourrait avoir "RESOURCES=5 i_buche_de_bois, 3 i_fil_de_fer". Ceci veut dire que ca prendrait 5 buches de bois ainsi que 3 fils de fer pour produire cet instrument. (Tout ce qui est inscrit ici sera détruit lors de la création de l'objet)

SKILLMAKE=x
Ici seront inscrits tout ce que le joueur devra avoir en sa possession pour produire cet objet comme les skills et les outils. Chaque skill ou outil différent doivent être séparés par des virgules. Par exemple, un instrument de musique pourrait avoir "SKILLMAKE=TINKERING 50.0, MUSICIANSHIP 80.0, t_tinker_tools". Ceci veut dire qu'il faudrait que son skill en bricolage soit de 50.0, en musique de 80.0 et qu'il possède un objet de type "t_tinker_tools", ce qui est un outil de bricoleur. (Tout ce qui est inscrit ici ne sera pas détruit lors de la création de l'objet)

VALUE=x
Ici sera noté la valeur marchande de l'objet en pièces d'or. Si aucune valeur n'est entrée, l'objet sera quand même de valeur égale à la somme de ses "RESSOURCES=x". Si cet objet n'a aucune ressource avec de la valeur ou qu'il n'y a aucune ressource, alors l'objet ne vaudra rien. Faites attention, c'est dans ce cas que les objets disparaissent sur les vendeurs!

TDATA1=x
TDATA2=x
TDATA3=x
TDATA4=x
Ici seront notés des donnée utiles pour certains types d'objet. Par exemple, le type "t_ore" utilise TDATA1 comme objet en quoi le minerai sera transformé, le type "t_door" utilise TDATA1 comme son que fera la porte lorsqu'elle est ouverte ou fermée... etc.

DUPELIST=x
Une liste de tous les items qui partagent ses propriétés. Les items doivent être séparés par des virgules.

DUPEITEM=x
L'objet prendra les propriétés de ce parent.

CATEGORY=x
SUBSECTION=x
DESCRIPTION=x
Tout ceci est pour classer vos items avec Axis. Vous verrez ainsi aisément la catégorie, la classe et la description de chacun des items présent dans vos scripts. Vous pourriez avoir comme catégory "Portes", comme subsection "metal" et description "Porte en metal NE".


Ceci conclut pour les objets simples, il y'a beaucoup d'autres propriétés qui restent à voir, surtout dans les armures, armes et memories. Certaines de ces propriétés sont inclus via l'événement ON = @CREATE qui est appelée quand l'objet est créé.


















Prérequis : Objets simple

Les triggers sont essentiels si vous désirez mettre un peu de vie sur votre serveur.

En effet, ils permettront aux joueurs d'interragir avec les objets et les npc que vous allez créer. Avant d'avancer dans les détails, voici un petit exemple d'un objet qui se trouve être un bâton de téléportation qui vous demande de sélectionner un joueur et ensuite un endroit pour le téléporter.

[ITEMDEF i_baton_teleportation]
NAME=Baton de teleportation
ID=i_staff_black
WEIGHT=50

//QUAND L'OBJET EST CRÉÉ, CECI EST EXÉCUTÉ
ON=@CREATE
COLOR=0481
HITPOINTS={5 10}
ATTR=attr_newbie|attr_move_never|attr_magic

//QUAND UN JOUEUR DOUBLE CLICK L'OBJET CECI EST EXÉCUTÉ
ON=@DCLICK
LINK=04fffffff
TARGET Select the player you would like to move.
RETURN 1

//QUAND UN ITEM EST SÉLECTIONNÉ, CECI EST EXÉCUTÉ
ON=@TARGON_ITEM
SRC.SYSMESSAGE You cannot move <SRC.TARG.NAME> or any other item.
RETURN 1

//QUAND UN PERSONNAGE EST SÉLECTIONNÉ,  CECI EST EXÉCUTÉ
ON=@TARGON_CHAR
LINK=<SRC.TARG.UID>
TARGETG Where would you like to move <SRC.TARG.NAME>?
RETURN 1

//QUAND UNE PARTIE DU DECOR EST SÉLECTIONNÉ, CECI EST EXÉCUTÉ
ON=@TARGON_GROUND
LINK.GO <SRC.TARGP>
LINK=04fffffff
RETURN 1

Il y'a ci-dessus 5 triggers différents, mais il en existe beaucoup d'autres! Certains sont utilisés que sur des objets, d'autres que sur des personnages et d'autres sur les deux. Chaque type d'objet a son trigger prédéfini (une armure s'équipe lorsqu'on double click, une pioche demande de sélectionner le sol pour creuser... etc), mais il est possible de :
1. Les laisser tel quel en ne les scriptant pas.
2. De les écraser en retournant "1" à la fin.
3. De faire une action quelconque avant d'utiliser la fonction prédéfinie en retournant "0" à la fin
Exemple :
Supposons que nous insérons ce script à l'intérieur de l'armure.

//RIEN N'EST AJOUTÉ
==> L'armure va s'équipper comme d'habitude.

ON=@DCLICK
RETURN 0
==> L'armure va s'équipper comme d'habitude. À noter que seulement retourner 0 fait exactement la même chose que de ne rien mettre du tout.

ON=@DCLICK
RETURN 1
==> L'armure ne va pas s'équipper et ne fera rien du tout lorsqu'un joueur va double cliquer dessus. Notez cependant qu'il pourra quand même l'équipper en la glissant sur sa feuille de personnage !

ON=@DCLICK
SRC.SYSMESSAGE Vous équippez l'armure et elle vous va a ravir !
RETURN 0
==> Le joueur recoit un message et ensuite l'armure s'équippe.

ON=@DCLICK
SRC.SYSMESSAGE Vous tentez d'équipper l'armure, mais sans succes !
RETURN 1
==> Le joueur recoit un message, mais l'armure ne s'équippe pas.


Events sur personnages & objets

Le ON=@CLICK
==>Il est utilisé lorsqu'on fait un simple click sur l'objet ou le personnage.
[] = Objet ou personnage se faisant cliquer dessus.
SRC = Celui qui click

ex : affiche simplement le nom de l'objet
ON=@CLICK
MESSAGE <NAME>
RETURN 1

ex : affiche le nom de l'objet suivi de "[verrouillee]". Utile pour un type d'objet dont vous voulez afficher clairement qu'il est verrouillé, telle une porte ou un coffre.
ON=@CLICK
MESSAGE <NAME>[verrouillee]
RETURN 1

ex : le script utilisé sur les ailes pour éviter le vol. Il vérifie premièrement si le joueur a les ailes sur lui, et ensuite vérifie si le LINK de l'objet est bien ce joueur là. Si tel n'est pas le cas, on remet les ailes à son propriétaire. Dans tous les cas, on RETURN 0, donc le nom des ailes sera affiché.
ON=@CLICK
IF <TOPOBJ.UID>==<SRC.UID>
  IF !(<LINK> == <SRC.UID>)
    CONT=<LINK.UID>
  ENDIF
ENDIF
RETURN 0

Le ON=@DCLICK
==>Il est utilisé lorsqu'on fait un double click sur l'objet ou le personnage
[] = Objet ou personnage se faisant double cliquer dessus
SRC = Celui qui double click

ex : conteneur de potion.
ON=@DCLICK
IF !<SRC.FINDID.m_anti_popotage>
  TARGET Sur quelle bouteille voulez-vous utiliser le conteneur?
ELSE
  SRC.SYSMESSAGE Vous devez attendre avant de reutiliser le conteneur
ENDIF
RETURN 1

ex : script de gemme qui demande sur quelle arme on veut le sertir.
ON=@DCLICK
IF <TOPOBJ.UID>==<SRC.UID>
  IF <SRC.FINDID.i_outils_de_sertissage>
    SRC.SYSMESSAGEUA 0481 1 1 0 Quelle arme souhaitez vous sertir de cette gemme ?
    TARGET
  ELSE
    SRC.SYSMESSAGEUA 0481 1 1 0 Vous ne pouvez pas manipuler la gemme sans outils de sertissage
   ENDIF
ELSE
  SRC.SYSMESSAGEUA 0481 1 1 0 Vous devez equiper la gemme avant de l'utiliser !
ENDIF
RETURN 1

ex : Une dalle de teleport qui lorsque le maitre de jeu double click dessus, les coordonnees de teleportation sont enregistrees a l'endroit où il se trouve. Croyez moi, ca facilite grandement la vie quand vous avez un gros labyrinthe à faire...
IF <SRC.ACCOUNT.PLEVEL> > 6
  MOREP=<SRC.P>
  SRC.SYSMESSAGEUA 0481 1 1 0 Coordonnee enregistree pour teleportation
  RETURN 1
ENDIF
RETURN 0

Le ON=@CREATE
==>Il est utilisé lors de la création de l'objet ou du personnage.
[] = L'objet en cours de création
SRC = Celui qui crée l'objet
SRC.ACT = L'objet en cours de création

ex : création d'une amulette. On y met sa couleur ainsi que sa solidité.
ON=@Create
HITPOINTS=1000
COLOR=00ae4
RETURN 0

ex : Lors de la création du banquier. Divers paramètres sont mis comme l'invincibilité, assez de force, lui mettre le bon "brain", des cheveux... etc.
ON=@Create
COLOR=colors_skin
STR=2000
DEX=1
INT=1
INVUL
NPC=BRAIN_BANKER
NEED=i_gold
ITEMNEWBIE=random_male_hair
COLOR=colors_hair
ITEMNEWBIE=random_facial_hair
COLOR=match_hair
RETURN 0

ex : un memory du poker hold'em qui met un timer de 1 seconde lorsque c'est le tour de jouer pour lui faire apparaître un interface.
ON=@CREATE
TIMER=1
RETURN 0

Le ON=@SPELLEFFECT
==> Il est utilisé lorsqu'un joueur ou un objet est "victime" d'un sort. RETURN 1 ignore la magie, tandis qu'avec un RETURN 0, le personnage/item recoit la magie en pleine gueule!
[] = Objet ou personnage qui recoit le sort
SRC = Celui qui a lancé le sort
SRC.ACT = Objet ou personnage qui recoit le sort (Utilisez [])
ARGN = #ID du sort (ex : bless = 17 ; recall = 32... etc)
ARGN2 = Puissance du sort qui est lancé (égal par défaut à la magie du SRC)

ex : Item ou NPC insensible aux sorts
ON=@SPELLEFFECT
RETURN 1

ex : livre de runes qui emmagasine les charges de recall et de gate.
ON=@SPELLEFFECT
//RECALL
IF <ARGN> == 32
  IF <TAG.RECALL_RESTANT> >= 50
    SRC.SYSMESSAGEUA 0481 1 1 0 <NAME> a atteint le nombre maximum de charges de recall !
  ELSE
    EMOTE briller
    TAG.RECALL_RESTANT = <EVAL 0<TAG.RECALL_RESTANT> + 1>
  ENDIF
//GATE
ELSEIF <ARGN> == 52
  IF <TAG.GATE_RESTANT> >= 10
    SRC.SYSMESSAGEUA 0481 1 1 0 <NAME> a atteint le nombre maximum de charges de gate !
  ELSE
    EMOTE briller
    TAG.GATE_RESTANT = <EVAL 0<TAG.GATE_RESTANT> + 1>
  ENDIF
ENDIF
RETURN 0

Le ON=@DROPON_SELF
==> Il est utilisé quand un objet tombe sur un conteneur (personnage ou contenant). RETURN 1 Empêche l'objet d'être glissé dans le contenant.
[] = Contenant
SRC = Celui qui glisse l'objet dedans
ARGO = Objet glissé

ex : Empêcher un joueur de mettre des contenants sur des vendeurs ou mettre un objet qui n'a aucun prix.
ON=@DROPON_SELF
OBJ <ARGO.UID>
IF <OBJ.TYPE>==T_CONTAINER
  SRC.SYSMESSAGE @026 Vous ne pouvez pas vendre des contenants sur des vendeurs.
  RETURN 1
ELSEIF <OBJ.VALUE> == 0
  SRC.SYSMESSAGE @026 Vous ne pouvez pas vendre un objet sans valeur sur des vendeurs.
  RETURN 1
ENDIF
RETURN 0



Events sur les objets seulement

Le ON=@TIMER
==>Il est utilisé quand le timer de l'objet tombe à 0.
[] = L'objet
SRC = Le Serveur...

ex : Script de guérison. Un memory à chaque seconde redonne des points de vie au joueur.
ON=@TIMER
IF <CONT.HITS> < <CONT.STR>
  CONT.HITS = <EVAL <CONT.HITS> + <CONT.HEALING>/1000>
  IF <CONT.HITS> > <CONT.STR>
    CONT.HITS = <CONT.STR>
  ENDIF
ENDIF
TIMER=1
RETURN 1

ex : objet qui disparait quand son timer atteint 0.
ON=@TIMER
REMOVE
RETURN 1

ex : Quand un joueur ne répond pas au test de macrotage... à noter que le LINK est le membre du staff qui vous a eu :D
ON=@TIMER
LINK.SYSMESSAGEUA 0481 1 1 0 <NAME> n'a pas repondu au test de macrotage !
REMOVE
RETURN 1

ex : memory qui teleport le joueur après un certain timer. C'est utilisé dans le livre de rune.
ON=@TIMER
CONT.EFFECT 2,i_fx_gate,0,15
CONT.P <MOREP>
CONT.UPDATE
CONT.EVENTS -e_casse_recall
REMOVE
RETURN 1

Le ON=@STEP
==> Il est utilisé quand un personnage marche dessus l'objet.
[] = L'objet en question
SRC = Personnage qui marche sur l'objet

ex : dalle de teleport. À noter qu'un joueur n'a pas de BRAIN :D
ON=@STEP
IF !<SRC.BRAIN>
  SRC.GO <MOREP>
ENDIF
RETURN 1

ex : une mine. 
ON=@STEP
SRC.SYSMESSAGE Vous sautez sur une mine !
SRC.KILL
RETURN 1

ex : dalle créatrice de monstre dans le dongeon 5.
ON=@STEP
IF (!<SRC.BRAIN>) && (<TAG.STREUM>==1)
    TIMER=60
    TAG.STREUM=0
    SRC.NEWNPC c_damne_d_air
    SRC.ACT.P=<P>
    TAG.UIDMONSTRE=<SRC.ACT.UID>
    SRC.NEWITEM=i_vire_creature
    SRC.ACT.CONT=<TAG.UIDMONSTRE>
ENDIF
RETURN 1

Le ON=@EQUIP
==> Il est utilisé lorsqu'un personnage équippe cet objet (Lorsqu'il tente de l'équipper car on peut lui en empêcher). Lorsqu'on RETURN 0, l'objet s'équippe, mais il ne s'équippe pas lorsqu'on RETURN 1. L'objet va par contre s'équipper quand même avec un double click, mais pas lorsqu'on glisse l'objet sur sa feuille de personnage... le mieux est de carrément appeler UNEQUIP si vous ne voulez pas que le joueur équip l'objet, un exemple est présenté ci-bas.
[] = L'objet en question
SRC = Joueur qui équippe l'objet

ex : arme d'estoc enchantée. Si le joueur n'a pas la force nécessaire, l'arme se UNEQUIP. Il est à noter ici qu'on fait appel à 2 fonctions pour les boosts au lieu de copier-coller chaque fois tout ce qu'elles font. Les 2 fonctions appellées font 130 lignes... multipliez 130 par le nombre d'armes sur APO et vous verrez que le nombre de lignes gagnées est très important.
ON=@EQUIP
SRC.BONUSARMEFENCE1
IF <EVAL <SRC.TAG.FORPURE>> <24
    UNEQUIP
ENDIF
BONUS_ARME_GEMME_EQUIP
RETURN 0

ex : cape de résistance à la magie
ON=@EQUIP
IF <EVAL 0<SRC.TAG.RENAISSANCE>> == 0
    SRC.MagicResistance=<EVAL <SRC.MagicResistance> + <SRC.TAG.MAGICRESISTANCEPURE> * 2>
    IF (<EVAL <SRC.TAG.INTPURE>> <50) || (<EVAL <SRC.TAG.MAGIEPURE>> <105)
        UNEQUIP
    ENDIF
ELSE
    UNEQUIP
ENDIF
RETURN 0


Le ON=@UNEQUIP
==>Lorsqu'un joueur déséquippe cet objet. Même principe que le EQUIP, mais RETURN 0 ou 1 ne va pas empêcher le joueur de se déséquipper de l'objet.
[] = L'objet déséquippé
SRC = Le personnage qui déséquippe l'objet

ex : dague rouillée enchantée... même principe que le premier exemple de EQUIP. On sauve avec les fonctions plus de 130 lignes par arme.
ON=@UNEQUIP
SRC.ENLEVEBONUSFENCE
BONUS_ARME_GEMME_UNEQUIP
RETURN 0

ex : Comme le 2e exemple de EQUIP, mais à l'envers.
ON=@UNEQUIP
IF <EVAL 0<SRC.TAG.RENAISSANCE>> == 0
  SRC.MagicResistance=<EVAL <SRC.MagicResistance> - <SRC.TAG.MAGICRESISTANCEPURE> * 2>
ENDIF
RETURN 0

Le ON=@DAMAGE
==>Il est utilisé lorsque celui portant l'arme frappe un autre personnage avec.
[] = L'arme utilisée
SRC = Ennemi qui est frappé
TOPOBJ ou CONT = Celui qui frappe

Le ON=@TARGON_ITEM
==>Il est utilisé lorsqu'un joueur sélectionne un objet à l'aide de la fonction TARGET.
[] = L'objet qui sert à target
SRC = Le joueur qui sélectionne
SRC.TARGET = L'objet que le joueur sélectionne

ex : baton de téléportation (suite avec TARGON_CHAR et TARGON_GROUND)
ON=@DCLICK
LINK=04fffffff
IF 0<SRC.ACCOUNT.PLEVEL><2
  REMOVE
ELSE
  TARGET Select the player you would like to move.
ENDIF
RETURN 1

ON=@TARGON_ITEM
SRC.SYSMESSAGE You cannot move <SRC.TARG.NAME> or any other item.
RETURN 1

Le ON=@TARGON_CHAR
==> Il est utilisé lorsqu'un joueur sélectionne un personnage à l'aide de la fonction TARGET.
[] = L'objet qui sert à target
SRC = Le joueur qui sélectionne
SRC.TARGET = L'objet que le joueur sélectionne

ex : baton de téléportation (suite)
ON=@TARGON_CHAR
LINK=<SRC.TARG.UID>
TARGETG Where would you like to move <SRC.TARG.NAME>?
RETURN 1

Le ON=@TARGON_GROUND
==>Il est utilisé lorsqu'un joueur sélectionne le sol à l'aide de la fonction TARGETG.
[] = L'objet qui sert à target
SRC = Le joueur qui sélectionne
SRC.TARGP = Coordonnées où le joueur a cliqué.

ex : bâton de téléportation (suite #2)
ON=@TARGON_GROUND
LINK.GO <SRC.TARGP>
LINK=04fffffff
RETURN 1

Events sur les personnages seulement

Le ON=@LOGOUT
==>Il est utilisé lorsqu'un joueur se déconnecte du serveur.
SRC = Le joueur qui déconnecte

ex : Envoyer un message à tous disant que le joueur se déconnecte
ON=@LOGOUT
SERV.B <SRC.NAME> se deconnecte du serveur
RETURN 0

ex : Lorsque le joueur se déconnecte, il faut le retirer de l'équipe !
ON=@LOGOUT
IF <SRC.FINDID.m_exp_equipe>
  TRYP 0 UID.<SRC.FINDID.m_exp_equipe.MORE2>.MESSAGE_TEAM <SRC.NAME> s'est <SRC.SEX deconnecte/deconnectee> et quitte l'equipe
  SRC.FINDID.m_exp_equipe.QUITTER_TEAM
ENDIF
RETURN 0

Le ON=@LOGIN
==> Même principe que pour le LOGOUT. C'est utilisé quand le joueur se connecte. À noter que un RETURN 0 connecte le joueur, mais RETURN 1 empêche le joueur de se connecter disant que son compte est bloqué. (même s'il ne l'est pas)
[] = Le joueur qui se connecte
SRC = Le joueur qui se connecte

ex : Message qui affiche à tous que le joueur se connecte.
ON=@LOGIN
SERV.B <SRC.NAME> se connecte sur le serveur !
RETURN 0

ex : Calcul du % de participation et déconnecter ceux qui n'ont pas assez de ba :D
ON=@LOGIN
IF <EVAL 0<SRC.TAG.HEURESJOUEES>> <1
  SRC.TAG.PARTICIPATION=0
ELSE
  SRC.TAG.PARTICIPATION=<EVAL ((0<SRC.TAG.VERIFCLICK>*400)/(0<SRC.TAG.HEURESJOUEES>))>
ENDIF
//Systeme de delestage
SRC.ANTILAG
RETURN 0

Le ON=@DEATH
==> Il est utilisé quand le personnage meurt.
[] = La victime
SRC = La victime
ACT = L'agresseur
SRC.ACT = L'agresseur

ex : perte de la moitié de l'exp lorsque le joueur se fait tuer par un personnage non joueur et obtient l'anti rez kill lorsque c'est par un joueur.
ON=@DEATH
IF ((<SRC.ACT.BRAIN>) || (0<SRC.ACT.TAG.DEBUTANT> == 0))
  IF !(<SRC.TAG.MILLEXP>==0)
    SRC.TAG.MILLEXP=<EVAL <SRC.TAG.MILLEXP>/2>
  ENDIF
  IF !(<SRC.TAG.XP>==0)
    SRC.TAG.XP=<EVAL <SRC.TAG.XP>/2>
  ENDIF
ELSE
  IF !<SRC.FINDID.m_anti_rez_kill>
    SRC.NEWITEM m_anti_rez_kill
    SRC.ACT.CONT = <SRC.UID>
  ENDIF
ENDIF
RETURN 0

Le ON=@DEATHCORPSE
==>Il est utilisé quand le personnage est mort et qu'il devient fantôme en créant un corps.
[] = Le mort
SRC = Le mort
ACT = Le tueur
SRC.ACT = Le tueur

ex : Pour que le joueur ne soit pas transformé en fantôme et qu'il revienne automatiquement en vie À Minoc.
ON=@DEATHCORPSE
RESURRECT
EFFECT 2,i_fx_explode,0,26
NEWITEM i_tombe
ACT.COLOR=<COLOR>
ACT.ATTR=00012
ACT.NAME Tombe de <NAME>
ACT.P=<P>
P=2458,518,16
UPDATE

Le ON=@GETHIT
==> Il est utilisé lorsqu'un personnage se fait frapper (Par un autre personnage ou un objet). RETURN 1 ignore le coup.
[] = Victime
SRC = Agresseur
SRC.ACT = Victime

ex : Empecher un joueur de frapper un autre joueur dans une zone no-pvp ou s'il a un anti rez-kill.
ON=@GETHIT
IF ((<SRC.ACT.REGION.FLAGS>&08000) || (<SRC.REGION.FLAGS>&08000))
  IF !<SRC.BRAIN>
    SRC.SYSMESSAGEUA 0481 1 1 0 Vous ne pouvez pas effectuer cette action en ces lieux !
  ENDIF
  EFFECT 3,i_fx_glow,0,15
  RETURN 1
ELSEIF (<SRC.ACT.FINDID.m_anti_rez_kill> || <SRC.FINDID.m_anti_rez_kill>)
  IF (!(<SRC.BRAIN>) && (0<SRC.TAG.DEBUTANT> == 1))
    SRC.REZ <SRC.ACT.NAME>
    RETURN 1
  ENDIF
ENDIF
RETURN 0

ex : système d'exp sur un monstre.
ON=@GETHIT
IF <SRC.ISCHAR>
  IF <EVAL 0<SRC.ACT.TAG.TAPER>> > 0
    SRC.ACT.TAG.TAPER=<EVAL <SRC.ACT.TAG.TAPER> - 1>
    VAR.EXPGAIN=<EVAL <SRC.ACT.TAG.XPCOUP>>
    SRC.GAIN_EXP <SRC.ACT.TAG.NIVEAU>
  ENDIF
ENDIF
RETURN 0

ex : rendre insensible aux coups un NPC
ON=@GetHit
HITS=2000
RETURN 1

ON=@HIT
==> Il est utilisé lorsqu'un personnage en frappe un autre.
[] = L'agresseur
ACT = L'agressé
SRC = L'agressé

ex : Un démon qui terrrorise sa proie en l'immobilisant.
ON=@HIT
IF (<EVAL(RAND(8))>==0)
  ACT.STAM=0
  ACT.HITS=1
  ACT.SYSMESSAGEUA 0481 1 1 0 <NAME> vous terrorise !
  RETURN 1
ENDIF
RETURN 0

ex : un monstre du dongeon 7 qui se guérit tout en vous buchant :D
ON=@HIT
IF <EVAL <HITS> + <STR>/100> > <EVAL <STR>>
  HITS=<STR>
ELSE
  HITS = <EVAL <HITS> + <STR>/100 >
ENDIF
RETURN 0

Le ON=@NPCRESTOCK
==> Il es utilisé dans un temps régulier par sphere et lorsque le NPC est créé. Vous pouvez donc créer facilement des objets pour dropper sur les monstres.
[] = NPC
SRC = Le serveur

ex : Une créature ayant une chance de dropper une perle ainsi que l'épée de la rose noire. Pour les malins, j'ai modifié les chiffres :p
ON=@NPCRestock
ITEM={ i_stats_dropp 2300 i_perle_enchantement 3 i_epee_de_la_rose_noire 1 }
RETURN 0

ex : un vendeur de fruits
ON=@NPCRestock
ITEMNEWBIE=i_maillot_manches_longues
COLOR=020
ITEMNEWBIE=i_gants_en_cuir
COLOR=0b36
ITEMNEWBIE=i_pantalon
COLOR=0750
ITEMNEWBIE=i_casquette
COLOR=020
ITEMNEWBIE=i_chaussures
COLOR=0b36
SELL=VENDOR_S_FRUITS
RETURN 0

Le ON=@SPELLCAST
==>Il est utilisé lorsqu'un personnage lance un sort. (Quand il commence à le lancer, pas lorsqu'il est lancé!). RETURN 1 empêche le personnage de lancer le sort.
[] = Celui qui lance le sort
SRC = Celui qui lance le sort
ACT = Cible du sort (Le caster pour les sorts sans target)
SRC.ACT = Cible du sort (Le caster pour les sorts sans target)
ARGN = #ID du sort (ex : bless = 17 ; recall = 32... etc)
ARGN2 = Puissance du sort qui est lancé (égal par défaut à la magie du SRC)

ex : Sorts interdits.
ON=@SPELLCAST
IF (<SRC.ACCOUNT.PLEVEL> <3)
  IF ( <ARGN> == 2 ) || ( <ARGN> == 14 ) || ( <ARGN> == 22 ) || ( <ARGN> == 23 ) || ( <ARGN> == 28 ) || ( <ARGN> == 33 ) || ( <ARGN> == 39 ) || ( <ARGN> == 40 ) || ( <ARGN> == 47 ) || ( <ARGN> == 50 ) || ( <ARGN> == 56 ) || ( <ARGN> == 58 ) || ( <ARGN> == 60 ) || ( <ARGN> == 61 ) || ( <ARGN> == 62 ) || ( <ARGN> == 63 ) || ( <ARGN> == 64 )
    SRC.SYSMESSAGEUA 0481 1 1 0 Fonction desactivee
    RETURN 1
  ENDIF
  IF (<SRC.REGION.FLAGS>&00004)
    IF ( <ARGN> == 22 ) || ( <ARGN> == 52 )
      SRC.SYSMESSAGEUA 0481 1 1 0 Vous ne pouvez pas lancer ce sortilege en ces lieux !
      RETURN 1
    ENDIF
  ENDIF
ENDIF
RETURN 0

ex : Une classe de personnage qui fait plus de dégats qu'il n'a réellement de magie.
ON=@SPELLCAST
ARGN2 = <EVAL (<ARGN2> * 3) / 2>
RETURN 0

ex : classe de personnage ne pouvant pas lancer de magie
ON=@SPELLCAST
SRC.SYSMESSAGEUA 025 1 1 0 Vous ne pouvez pas lancer de sort avec cette classe de personnage !
RETURN 1

Le ON=@SKILLSELECT
==> Il est utilisé lorsque le joueur clique directement dessus une skill dans sa feuille de skills.
[] = Celui qui utilise la compétence
SRC = Celui qui utilise la compétence

ex : Empêcher un joueur d'utiliser une compétence.
ON=@SkillSelect
IF (<SRC.ACTION>==Skill_Snooping) || (<SRC.ACTION>==Skill_Stealing)
  SRC.ACTION=-1
  RETURN 1
ENDIF
RETURN 0

Le ON=@SKILLSTART
==> Il est utilisé lorsqu'un personnage utilise une compétence (Lorsqu'il commence à l'utiliser, pas lorsqu'il termine). RETURN 1 empêche le joueur d'utiliser la compétence.
[] = Le personnage qui utilise la compétence
SRC = Le personnage qui utilise la compétence

ex : Remplir un peu de mana lorsque le joueur utilise la méditation.
ON=@SKILLSTART
IF <SRC.ACTION>==Skill_meditation
  IF <SRC.MEDITATION> < 100.0
    SRC.SYSMESSAGE Vous etes incapable de mediter !
  ELSEIF <SRC.MEDITATION> < 200.0
    IF <EVAL RAND(5)> == 0
      SRC.MANA = <EVAL <SRC.MANA> + 20>
    ENDIF
  ELSE
    SRC.MANA = <EVAL <SRC.MANA> + 20>
  ENDIF
  IF <SRC.MANA> > <SRC.INT>
    SRC.MANA = <SRC.INT>
  ENDIF
ENDIF
RETURN 0

ON=@NPCSEENEWPLAYER
==> Il est utilisé quand un NPC voit un joueur qu'il n'a pas vu. RETURN 1 empêchera le NPC de se rappeler du joueur en question.
[] = Le NPC
SRC = Le joueur qui se fait remarquer

ex : Un NPC heureux de voir quelqu'un.
ON=@NPCSEENEWPLAYER
DORAND 4
  SAY Enfin quelqu'un!
  SAY Ne seriez-vous pas <SRC.NAME>? Heureux de vous revoir
  SAY Venez-vous pour me tenir compagnie?
  SAY Quelqu'un... quelle joie !
ENDDO
RETURN 0

ex : Un joueur qui n'a rien à faire au dongeon 7...
ON=@NPCSEENEWPLAYER
IF ( (<EVAL 0<SRC.TAG.anti_mark_recall>>==0) || (<EVAL 0<SRC.TAG.INSIDE_D7>>==0) )
  SRC.EVENTS -e_anti_mark_recall
  SRC.P=1357,1065
  SRC.UPDATE
ENDIF
RETURN 0

Le ON=@NPCHEARUNKNOWN
==>Il est utilisé lorsque le joueur dit quelque chose qui est absent du SPEECH du NPC.
[] = Le NPC
SRC = Le joueur qui parle au NPC

ex : vendeur d'ingrédients.
ON=@NPCHearUnknown
SAY Quel bon reg vous amene?
RETURN 1

ex : NPC qui ne sais pas quoi répondre
ON=@NPCHearUnknown
SAY Je ne comprends rien a ce que vous dites, <SRC.NAME> !
RETURN 1

ex : Joueur qui a 5 chances de repondre quelque chose de comprehensible.
ON=@NPCHearUnknown
IF 0<SRC.TAG.CHANCES_RATEES> < 5
  SRC.TAG.CHANCES_RATEES = <EVAL 0<SRC.TAG.CHANCES_RATEES> + 1>
ENDIF
IF <SRC.TAG.CHANCES_RATEES>> == 1
  SAY Redites encore 4 choses stupides et je ne vous parlerai plus.
IF <SRC.TAG.CHANCES_RATEES>> < 5
  SAY Encore quelque chose de stupide, encore <EVAL 5 - <SRC.TAG.CHANCES_RATEES>> fois et c'est la porte !
ELSE
  SAY Vous m'avez suffisamment agace, hors de ma vue cloporte !
ENDIF
RETURN 1

Le ON=@ITEMPICKUP_PACK
==> Il est utilisé quand un joueur prend un objet dans ses mains. (Dans tout APO, ce trigger est utilisé à un seul endroit!)
[] = Le joueur qui prend l'objet
SRC = Le joueur qui prend l'objet
ACT = L'objet pris
SRC.ACT = L'objet pris

ex : Script qui fait disparaitre un objet important qui n'est pas destiné aux joueurs.
ON=@ITEMPICKUP_PACK
IF <SRC.ACT.TYPE> == t_objet_secret_gm
  IF <SRC.ACCOUNT.PLEVEL> < 3
    SRC.SYSMESSAGE Vous ne pouvez pas prendre l'objet et il vous est confisque !
    SRC.ACT.REMOVE
    RETURN 1
  ENDIF
ENDIF
RETURN 0

Le ON=@ITEMTARGON_ITEM
==> Il est utilisé lorsqu'un joueur sélectionne quelque chose.
[] = Le joueur qui sélectionne
SRC = Le joueur qui sélectionne
ACT = L'objet qui sert à sélectionner
SRC.ACT = L'objet qui sert à sélectionner
TARG = L'objet sélectionné
SRC.TARG = L'objet sélectionné
ARGO = L'objet sélectionné

ex : Découper la chair d'un cadavre.
ON=@ITEMTARGON_ITEM
IF (<SRC.ACT.TYPE>==t_weapon_sword) || (<SRC.ACT.TYPE>==t_weapon_fence)
  IF <SRC.TARG.BASEID>==i_corpse
    SRC.SYSMESSAGE Vous decoupez la chair de <SRC.TARG.NAME> avec <SRC.ACT.NAME>
    RETURN 1
  ENDIF
ENDIF
RETURN 0

Le ON=@ITEMCLICK
==> Il est utilisé lorsqu'un joueur click sur un objet. Il est mieux d'utiliser le CLICK sur l'objet lui-même. (Utilisé nulle part sur APO)
[] = Le joueur
SRC = Le joueur
ACT = Objet cliqué
SRC.ACT = Objet cliqué

ex : Vous voulez faire fuire tous les joueurs sur votre serveur en floodant.
ON=@ITEMCLICK
SERV.B <SRC.NAME> clique sur <SRC.ACT.NAME> !
RETURN 0

Le ON=@ITEMDCLICK
==> Il est utilisé lorsqu'un joueur double click sur un objet. Il est mieux d'utiliser le DCLICK sur l'objet lui-même. (Utilisé nulle part sur APO)
[] = Le joueur
SRC = Le joueur
ACT = L'objet double cliqué
SRC.ACT = L'objet double cliqué
TARG = L'objet double cliqué
SRC.TARG = L'objet double cliqué

ex : Amusons nous a flooder puisque je n'ai aucune idée à quoi ca peut bien servir...
ON=@ITEMDCLICK
SERV.B <NAME> dclick sur <SRC.ACT.NAME> = <TARG.NAME>
SERV.B <SRC.NAME> double click sur <ACT.NAME> = <SRC.TARG.NAME>
RETURN 0
























LES ITEMS SIMPLES




Les objets simples sont les objets courants que nous pouvons voir en grande quantité sur les serveurs (mur, rabot, , pièce d'or, bourse...). Ces objets, même s'ils sont simples doivent être définis selon plusieurs attributs, les voici : (Si j'en oublie, merci de m'en faire part!)

[ITEMDEF x]
DEFNAME=x
ID=x
NAME=x
WEIGHT=x
TYPE=x
RESOURCES=x
SKILLMAKE=x
VALUE=x
TDATA1=x
TDATA2=x
TDATA3=x
TDATA4=x
DUPELIST=x
DUPEITEM=x
CATEGORY=x
SUBSECTION=x
DESCRIPTION=x


[ITEMDEF x]
Ceci dit à Sphere "Je veux créer un nouvel objet avec comme définition x". En gros, Sphere utilisera les prochaines lignes pour définir chaque attribut de l'objet, c'est ce qui suivra. Vous pourrez faire apparaitre cet objet grâce à la commande ".add x". Il est recommandé de commencer votre nom avec "i" comme dans l'exemple "i_roche" pour montrer que c'est un objet ordinaire. Les objets de type "memory" commenceront avec "m"... etc.

DEFNAME=x
Cette ligne est purement inutile, sauf si vous voulez utiliser un deuxième nom pour votre objet. Vous pourrez utiliser le x de ITEMDEF ou celui de DEFNAME pour faire un ".add". Si vous ne voulez pas un deuxième nom, supprimez cette ligne.

ID=x
Cette ligne donnera tout simplement forme à votre objet. Il vous faudra de ce fait connaître exactement le ID que vous voulez. Par exemple, x=0475 donnera un foyer, x=0dfc donnera un ciseau... etc. Dans les fichiers "sphereitem", vous pourrez les trouver.

NAME=x
Sans vous étonner, x sera ni plus ni moins que le nom qu'aura cet objet.

WEIGHT=x
x sera le poids de l'objet. Faites tout de même attention car Sphere prend les décimales même si vous n'en mettez pas. Donc x=2 ou x=0.2 donnera la même chose. Si vous voulez un poids de 50, mettez x=50.0 ou x=500.

TYPE=x
x sera le type de votre objet. Chaque type d'objet réagit différemment aux événements comme double-click, click, step, à la magie, etc. Par exemple, le type "t_door" réagit par défaut au double click en ouvrant la porte, le type "t_armor" réagit par défaut au double click en équippant cette armure. Il est tout à fait possible de redéfinir le ON = @DCLICK sur un objet t_armor pour que l'objet ne s'équippe pas, mais lance une éclair par exemple, mais tout cela sera vu dans un autre guide. En gros, ce que vous devez savoir, c'est que la définition du type sert uniquement à ce que Sphere sache quoi faire avec un objet lorsqu'un événement survient. Dans le cas contraire, il renvoit un message style "Vous ne savez pas utiliser cet objet". Tous les types sont notés dans le fichier "spheredefs.scp"

RESSOURCES=x
Ici seront inscrits toutes les ressources qui devront être en possession du joueur pour produire cet objet. Si plus d'une ressource est nécessaire à sa construction, ces ressources devront être séparés par une virgule. Par exemple, un instrument de musique pourrait avoir "RESOURCES=5 i_buche_de_bois, 3 i_fil_de_fer". Ceci veut dire que ca prendrait 5 buches de bois ainsi que 3 fils de fer pour produire cet instrument. (Tout ce qui est inscrit ici sera détruit lors de la création de l'objet)

SKILLMAKE=x
Ici seront inscrits tout ce que le joueur devra avoir en sa possession pour produire cet objet comme les skills et les outils. Chaque skill ou outil différent doivent être séparés par des virgules. Par exemple, un instrument de musique pourrait avoir "SKILLMAKE=TINKERING 50.0, MUSICIANSHIP 80.0, t_tinker_tools". Ceci veut dire qu'il faudrait que son skill en bricolage soit de 50.0, en musique de 80.0 et qu'il possède un objet de type "t_tinker_tools", ce qui est un outil de bricoleur. (Tout ce qui est inscrit ici ne sera pas détruit lors de la création de l'objet)

VALUE=x
Ici sera noté la valeur marchande de l'objet en pièces d'or. Si aucune valeur n'est entrée, l'objet sera quand même de valeur égale à la somme de ses "RESSOURCES=x". Si cet objet n'a aucune ressource avec de la valeur ou qu'il n'y a aucune ressource, alors l'objet ne vaudra rien. Faites attention, c'est dans ce cas que les objets disparaissent sur les vendeurs!

TDATA1=x
TDATA2=x
TDATA3=x
TDATA4=x
Ici seront notés des donnée utiles pour certains types d'objet. Par exemple, le type "t_ore" utilise TDATA1 comme objet en quoi le minerai sera transformé, le type "t_door" utilise TDATA1 comme son que fera la porte lorsqu'elle est ouverte ou fermée... etc.

DUPELIST=x
Une liste de tous les items qui partagent ses propriétés. Les items doivent être séparés par des virgules.

DUPEITEM=x
L'objet prendra les propriétés de ce parent.

CATEGORY=x
SUBSECTION=x
DESCRIPTION=x
Tout ceci est pour classer vos items avec Axis. Vous verrez ainsi aisément la catégorie, la classe et la description de chacun des items présent dans vos scripts. Vous pourriez avoir comme catégory "Portes", comme subsection "metal" et description "Porte en metal NE".


Ceci conclut pour les objets simples, il y'a beaucoup d'autres propriétés qui restent à voir, surtout dans les armures, armes et memories. Certaines de ces propriétés sont inclus via l'événement ON = @CREATE qui est appelée quand l'objet est créé.

























LES FONCTIONS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Les fonctions sont essentielles si vous voulez faire du code plus concis et lisible. Elles ont pour but principal d'éviter de retapper les mêmes lignes de code en appelant la fonction plusieurs fois au lieu de "copier-coller" le code plusieurs fois. Ceci m'a souvent aidé à réduire de plus ou moins 10% les lignes de code de mes scripts, et même jusqu'à 90% dans quelques uns d'entre eux! C'est un élément essentiel un peu compliqué à première vue, mais très simple et utile.

Utilisation :
[FUNCTION nomDeFonction]
....
....
RETURN ...

Attributs :
1.     La fonction retourne toujours quelque chose. Si vous ne mettez aucun "RETURN", la fonction retournera "0" à la fin.
2.     L'objet "SRC" est le même que lorsque vous appelez la fonction au départ. Il est déconseillé d'utiliser le "SRC" dans une fonction puisque vous pourriez appeler la fonction à partir de n'importe quel script.
3.     L'objet par défaut (<UID>) est celui sur lequel vous appelez la fonction. Par exemple, si vous utilisez dans un script à l'extérieur de votre fonction "TOPOBJ.fonction", alors votre objet par défaut sera le "TOPOBJ".
4.     Vous pouvez envoyer un seul argument à une fonction qui sera appelé "ARGS". Par exemple, si vous utilisez dans un script à l'extérieur de votre fonction "TOPOBJ.fonction 12", alors à l'intérieur de votre fonction, vous aurez "<ARGS> = 12".
Le RETURN
Le RETURN est ce qui importune bien des scripteurs. Il faut savoir que chaque fonction doit retourner une valeur, que ce soit une lettre, une suite de caractères, un nombre... lorsque uen valeur est retournée, la fonction cesse au même moment.

Vous appelez donc une fonction à partir d'un script quelconque, vous pouvez en toute légalité créer une fonction "double" qui ne fait rien de plus que doubler la valeur envoyée. Je suis d'accord avec vous que c'est bien inutile, mais ca donne un bon example.
//CODE DU SCRIPT
ON=@DCLICK
SRC.SYSMESSAGE <EVAL <DOUBLE 10>>
RETURN 1

Vous devriez voir apparaître sur votre écran la valeur "20". En guise d'example, voici ce que pourrait donner la fonction "DOUBLE".

[FUNCTION DOUBLE]
RETURN <EVAL <ARGS> * 2>

Nous pourrions également ajouter un test pour s'assurer que la fonction a bel et bien un argument. Imaginons que <ARGS> n'existe peut-être pas...

[FUNCTION DOUBLE]
IF <ARGS>
  RETURN <EVAL <ARGS> * 2>
ELSE
  SRC.SYSMESSAGE Aucun argument dans la fonction double !
  RETURN 0
ENDIF

Bien sur, si une phrase est entrée en argument, la fonction va créer une erreur en essayant de calculer "phrase * 2". IF <ARGS> ne fait que vérifier si <ARGS> contient quelque chose, peu importe ce que c'est. Il est souvent recommandé dans la mesure du possible de ne faire qu'un seul "RETURN" par fonction à la toute fin, cela s'appelle de la programmation structurée stricte (une entrée une sortie), sinon dans l'exemple ci-haut est de la programmation structurée laxiste (Une entrée). Lorsque nous pouvons faire un code plus structurée et plus propre, pourquoi pas?

//EXAMPLE DE PROGRAMMATION STRUCTUREE STRICTE
[FUNCTION DOUBLE]
IF <ARGS>
  VAR.TEMP = <EVAL <ARGS> * 2>
ELSE
  VAR.TEMP = 0
  SRC.SYSMESSAGE Aucun argument dans la fonction double !
ENDIF
RETURN <VAR.TEMP>

Nous avons encore un léger problème... nous utilisons la variable globale "<VAR.TEMP>" pour retourner notre valeur, mais nous ne la supprimons pas. Cela n'est pas tellement grave si vous avez assez de mémoire et de vitesse sur votre serveur, mais pourquoi en prendre plus si ce n'est pas nécessaire? Nous pouvons utiliser ARGS ici pour stocker notre valeur de retour.

//EXAMPLE DE PROGRAMMATION STRUCTUREE STRICTE SANS PERTE DE MEMOIRE
[FUNCTION DOUBLE]
IF <ARGS>
  VAR.TEMP = <EVAL <ARGS> * 2>
ELSE
  VAR.TEMP = 0
  SRC.SYSMESSAGE Aucun argument dans la fonction double !
ENDIF
ARGS = <VAR.TEMP>
VAR.TEMP // SUPPRIME LA VARIABLE
RETURN <ARGS>

Pour être plus saint que le pape, nous pouvons une fois de plus optimiser notre fonction. Au lieu d'utiliser une variable VAR.TEMP pour ensuite la remettre dans ARGS, nous pourrions l'enregistrer dans ARGS directement. Faites attention tout de même avec cette technique, car vous allez écraser votre ARGS initial, et vous ne pourrez plus vous en servir par la suite. Dans ce cas-ci, nous l'utilisons qu'une seule fois.

//EXAMPLE DE PROGRAMMATION OPTIMAL
[FUNCTION DOUBLE]
IF <ARGS>
  ARGS = <EVAL <ARGS> * 2>
ELSE
  ARGS = 0
  SRC.SYSMESSAGE Aucun argument dans la fonction double !
ENDIF
RETURN <ARGS>

Comme je disais un peu plus haut, la commande "RETURN" retourne une valeur et ferme immédiatement la fonction, donc tout ce qui suit un RETURN est complètement inutile.

[FUNCTION TOTO]
SRC.SYSMESSAGE blablabla...!
RETURN 15
SYSMESSAGE Message completement inutile qui ne s'affiche pas !
Thornar le Gondorien , Guérrier mineur et forgeron , alchimiste et futur archer :)