Le fichier de description des règles de Magic : l'Assemblée

Comme cela a été précisé plus haut, les règles de ce jeu de cartes sont décrites dans le fichier mtg.xml du répertoire src/main/resources/tbs. Vous chercherez souvent dans ce fichier afin d'obtenir des tests, actions ou capacités déjà écrites, alors analysons la structure de ce fichier.

En-tête

Le fichier mtg.xml commence avec l'élément <tbs>, qui est l'abbréviation de "Turn Based Strategy" (ou stratégie basée sur des tours). Certains attributs spécifient l'emplacement du schéma XML du fichier, l'espace de nommage XML, d'autres spécifient le nom du jeu, la version et l'auteur. On trouvera également des informations concernant le fichier contenant l'image du dos des cartes de ce jeu.

Base de données des informations complémentaires

Magic Project inclu également une base données des informations concernant les cartes qui n'ont pas de relations avec les règles comme l'image d'une carte, le texte d'ambiance ou l'artiste. Toutes ces informations sont téléchargées automatiquement depuis plusieurs sites par la fourniture de fichier XML de proxy valides.

L'élément <database-properties> dans le fichier mtg.xml est utilisé pour déclarer les différentes informations interprétées par Magic Project. Vous trouverez ci-dessous un extrait du contenu de cet élément prélevé depuis le fichier mtg.xml.

<database-properties>
 <property name="card.artist-credit" type="java.lang.String" translate="false" />
 <property name="card.flavor-text" type="java.lang.String" translate="false" />
 <property name="card.sets" type="java.util.List" translate="true" />
 <property name="card.text" type="java.lang.String" translate="false" />
 <property name="card.id" type="java.lang.String" translate="false" />
 <property name="card.set" type="java.lang.String" translate="true" />
 <property name="card.version" type="java.lang.String" translate="false" />
</database-properties>

Les symboles de mana

Magic Project télécharge dynamiquement les symboles de mana nécessaires à l'affichage des capacités depuis le site web de Wizards of the Coast pour des raisons de propriété intellectuelle. L'élément <mana-symbols> permet de fournir à Magic Project toutes les informations permettant de télécharger ces symboles.

Licence

L'élément <license> fourni une description de la licence du jeu auquel est associé le fichier mtg.xml. Vous trouverez ci-dessous un extrait de la description de la license :

<licence>
 This program is not published, produced or supported by Wizards Of The Coast(TM), Inc. Magic
 The Gathering(TM) and Wizards Of The Coast(R) Inc. are registered trademarks owned by
 Wizards Of The Coast(R) Inc., a subsidiary of Hasbro, Inc.
</licence>

Initialisation des registres des joueurs

Une série de registres de valeurs entières (comme les points de vie) est allouée pour chaque joueur. Les éléments <registers-first-player> et <registers-first-player> sont dédiés à l'initialisation de ces registres. Vous trouverez ci-dessous un extrait de ces éléments issus du fichier mtg.xml :

<registers-first-player>
 <register index="life" value="20" />
 <register index="maxi-cards-in-hand" value="7" />
 <register index="land-remain-to-cast" value="1" />
 <register index="hand-vibility-modifiers" value="0" />
 <register index="playedland" value="0" />
 <register index="mulligan" value="7" />
</registers-first-player>
<registers-second-player>
 <register index="life" value="20" />
 <register index="maxi-cards-in-hand" value="7" />
 <register index="hand-vibility-modifiers" value="0" />
 <register index="playedland" value="0" />
 <register index="mulligan" value="7" />
</registers-second-player>

La déclaration des phases

L'élément suivant <phases> déclare les différentes phases qui composent un tour dans le jeu de carte implémenté. Il spécifie également quels types de sorts sont jouables durant ces différentes phases.

Les images associées aux états

Pour chaque carte en jeu avec un état spécique (comme le mal d'invocation), Magic Project interprète l'élément <state-pictures> pour récupérer et associer une image relative à cet état. Si les attributs index et state sont fournis, Magic Project va faire une comparaison bit à bit entre la valeur entière à la position désignée par index dans les registres de la carte et la valeur contenue dans state. Les attributs width et height permettent de renseigner Magic Project sur respectivement la largeur et la hauteur de l'image à afficher sur la carte. Il est possible de faire en sorte que Magic Project positionne automatiquement les images (en les séquençant) en mettant la valeur -1 pour les attributs x et y.

Les images associées aux actions

Dans le jeu de cartes Magic : l'Assemblée, certaines actions sont liées à une image. Cela est vrai pour l'action "engager" par exemple. L'élément <action-pictures> déclare les différentes images associées aux actions.

Les filtres des informations affichées sur les cartes

L'élément <tooltip-filters> informe Magic Project de la quantité d'informations à afficher sur les cartes en fonction de tests divers (par exemple, il est inutile d'afficher les couleurs d'un terrain étant donné qu'ils sont tous incolores).

Les modifieurs statiques

Les modifieurs statiques sont des modifications qui s'appliquent automatiquement à certaines cartes à partir du moment où ces dernières vérifient les règles qui sont attachées à ces modifieurs. Il sont déclarés au sein de l'élément <static-modifiers>. On trouve par exemple dans cette élément un modifieur statique qui permer à tout terrain basique en jeu de produire un mana de la couleur à laquelle il est associée, un modifieur statique pour pouvoir jouer les cartes avec la capacité morph ou un modifieur statique qui permet aux cartes qui ont la capacité flash d'être jouées à tout moment où un éphémère pourrait être joué.

Vous trouverez ci-dessous l'exemple du modifieur statique relatifs aux crétures avec la capacité mue :

<static-modifier zone="play">
 <modifiers>
  <register-indirection index="power" value="2" operation="set" />
  <register-indirection index="toughness" value="2" operation="set" />
  <idcard-modifier idcard="creature" operation="set" />
  <property-modifier operation="remove" property="all" />
  <property-modifier operation="add" property="morph" />
  <color-modifier operation="clear" />
 </modifiers>
 <while>
  <and>
   <has-property property="morph" />
   <not>
    <is-face-up />
   </not>
  </and>
 </while>
</static-modifier>

La déclaration des capacités

Dans l'élément <abilities>, on peut trouver toutes les capacités directement associées avec la gestion générale du jeu.

Le contenu de cet élément débute avec les capacités système (déclarées à l'aide d'éléments <system-ability>) qui permettent entre autres aux joueurs de jouer durant la phase d'attaque, d'initialiser le jeu, d'implémenter les phases de pioche et de défausse, d'implémenter le mulligan, de gérer et d'initialiser le tour, de gérer les dommages mortels ou les brûlures de mana, d'implémenter la règle des légendes, d'implémenter la règles des enchantements du monde ou encore d'imposer la limitation concernant le nombre de terrains que l'on peut jouer par tour.

Ces déclarations sont suivies par les capacités de remplacement, qui sont des capacités qui se déclenchent sur l'occurence de certaines actions et remplacent dynamiquement ces actions par d'autres actions. Elles sont déclarées via l'élément <replacement-ability>. On trouve entre autres les capacités de remplacement qui gère le déplacement d'une carte jeton vers le cimetière (en réalité une telle carte est retirée de la partie à la place), qui gère le fait de jouer une carte avec la capacité flashback (lorsque le sort se résout, la carte associée est retirée de la partie) ou qui gère le fait de jouer une carte avec la capacité buyback (lorsque le sort se résout, la carte associée retourne dans la main de son propriétaire).

Disposition de l'espace de jeu

La disposition de l'espace de jeu est également décrite dans le fichier XML à l'aide de l'élément <layout>. Les zones et cadres communs y sont déclarés.

Contraintes d'actions

Magic Project est également capable d'appliquer des contraintes sur les actions si elles correspondent aux éléments fils de l'élément <action>. Ces contraintes sont ajoutées dynamiquement à l'aide de l'opération fournie (génégalement renseignée à "and") au test associé au sein de l'action correspondante. Ces contraintes sont déclarées via l'élément <action-constraints>. Vous trouverez ici par exemple les contraintes concernant la capacité d'un équipement d'équiper une créature (il est impossible pour un équipement qui est également une créature d'équiper une créature) :

<constraint operation="and">
 <test>
  <and>
   <not>
    <has-idcard idcard="creature" card="this" />
   </not>
   <has-property property="equipment" card="this" />
  </and>
 </test>
 <actions>
  <attach name="equip" />
 </actions>
</constraint>
<constraint operation="and">
 <test>
  <and>
   <not>
    <has-idcard idcard="creature" card="this" />
   </not>
   <has-property property="equipment" card="this" />
  </and>
 </test>
 <actions>
  <pay-mana />
 </actions>
</constraint>

Coûts additionnels

Magic Project est capable de gérer les coûts additionnels à l'aide de l'élément <additional-costs>.

Les objets

La dernière partie du fichier XML est dédiée aux objets, qui peuvent être considérés comme des compteurs (glace, poison, +1/+1, etc.). Ils sont déclarés via l'élément <objects>.

Les fichiers des règles des cartes de Magic : l'Assemblée

Comme cela a été précisé avant, chaque carte dans un jeu comme Magic : l'Assemblée peut faire référence à ses propres règles spécifiques. Dans Magic Project, il faut écrire un fichier XML par carte à implémenter. Le contenu du fichier décrit les règles de la carte dans la même syntaxe utilisée dans le fichier mtg.xml.

Description des règles de syntaxe XML des règles des cartes

La meilleure façon de décrire la structure de ces fichier est d'examiner un exemple. Pourquoi ne pas coder la carte Angel of Light de l'édition Starter ?

Cet exemple vous permettra de connaître les parties les plus importantes qui constituent un fichier XML de description des règles d'une carte. Vous trouverez ci-dessous l'image de cette carte :

Commençons par observer le code de cette carte :

<?xml version="1.0" encoding="ISO-8859-1"?>
<card xmlns="http://sourceforge.net/projects/magic-project"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://sourceforge.net/projects/magic-project ../../mpvalidator.xsd"
 name="Angel of Light">
 <rules-author-comment>riclas</rules-author-comment>
 <init>
  <registers>
   <register index="white" value="1"/>
   <register index="colorless" value="4"/>
   <register index="power" value="3"/>
   <register index="toughness" value="3"/>
  </registers>
  <colors>white</colors>
  <idcards>creature</idcards>
  <properties>vigilance flying angel</properties>
 </init>
 <abilities>
  <ability ref="cast-spell"/>
 </abilities>
</card>

La déclaration d'une carte commence toujours avec l'élément <card>. Il doit spécifier les paramètres xmlns (l'espace de nommage XML du fichier courant), xmlns:xsi (l'espace de nommage XML des éléments et attributs relatif au schéma), xsi:schemaLocation (qui spécifie l'emplacement du fichier XML de schéma utilisé pour valider la structure du fichier) et le nom (c'est à dire le nom de la carte en Anglais sans remplacer ni effacer aucun caractère).

<card xmlns="http://sourceforge.net/projects/magic-project"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://sourceforge.net/projects/magic-project ../../mpvalidator.xsd"
 name="Angel of Light">

Cet élément est immédiatement suivi par l'élément <rules-author-comment> qui donne des informations à propos de l'auteur du fichier XML des règles de la carte (généralement son nom ou pseudo).

<rules-author-comment>riclas</rules-author-comment>

Cet élément peut être suivi d'un commentaire qui rappelle la version de l'Oracle des règles de la carte si cette carte a été générée par le convertisseur Oracle vers XML.

L'élément suivant est l'élément <init> qui contient toutes les informations statiques de la carte. On trouvera dans cet élément :

  • L'élément <registers> qui est utilisé pour initialiser un certain nombre de registres associés à la carte. Cet élément contient des éléments <register> qui ont généralement deux attributs : index pour le nom logique du registre (qui en réalité est un index entier, ainsi le nom logique utilisé doit être déclaré dans l'élément <aliases> du fichier XML mtg.xml) et value pour la valeur affectée. and value for the affected value. Veuillez noter que la valeur ou l'index peuvent être imbriqués sous la forme d'éléments. On utilise généralement ces registres pour les cartes :
    • white pour la quantité de mana blanc dans le coût d'invocation,
    • blue pour la quantité de mana bleu dans le coût d'invocation,
    • black pour la quantité de mana noir dans le coût d'invocation,
    • green pour la quantité de mana vert dans le coût d'invocation,
    • red pour la quantité de mana rouge dans le coût d'invocation,
    • colorless pour la quantité de mana incolore dans le coût d'invocation,
    • power pour la force de la créature si cette carte est une créature,
    • toughness pour l'endurance de la créature si cette carte est une créature,

    Dans l'exemple, la carte a un coût d'invocation de 4W et un couple force/endurance de 3/3.

    <registers>
     <register index="white" value="1"/>
     <register index="colorless" value="4"/>
     <register index="power" value="3"/>
     <register index="toughness" value="3"/>
    </registers>
    
  • L'élément <colors> permet d'ajouter des couleurs à la carte. Il peut contenir jusqu'à cinq alias de couleurs, séparés par un espace.

    Dans notre example, la carte est une carte blanche.

    <colors>white</colors>
    
  • L'élément <idcards> permet de préciser les types principaux de la carte, il peut contenir les valeurs suivantes :
    • plains pour une plaine,
    • island pour une île,
    • swamp pour un marais,
    • forest pour une forêt,
    • mountain pour une montagne,
    • land pour un terrain non-basique,
    • creature pour une créature,
    • artifact pour un artefact,
    • local-enchantment pour une aura,
    • global-enchantment pour un enchantement,
    • instant pour un éphémère,
    • sorcery pour un sortilège.

    L'exemple nous montre que la carte est une créature.

    <idcards>creature</idcards>
    
  • L'élément <properties> contient tous les sous-types de la carte comme le type de créature ou des capacité additionnelles comme l'initiative. Vous êtes invité à consulter le fichier XML mtg.xml pour l'ensemble des valeurs possibles en recharchant la chaîne "<!-- properties -->".

    L'exemple nous montre que la créature est un Ange avec le Vol et la Vigilance (attaquer ne fait pas cette créature s'engager).

    <properties>vigilance flying angel</properties>
    

L'élément suivant est dédié aux capacités. L'unique capacité déclarée est une référence à la capacité cast-spell du fichier mtg.xml. Cette capacité permet au propriétaire de la carte de payer le coût d'invocation de la carte afin de la jouer depuis sa main.

<abilities>
 <ability ref="cast-spell"/>
</abilities>

Autre exemples

Maintenant que vous connaissez la structure de base d'une carte, il serait judicieux de regarder des exemples de cartes un peu plus complexes à implémenter.

Cloudstone Curio

Cette carte est quelque peu compliquée à implémenter : elle a des interactions avec les événements concernant le mouvement des cartes et elle doit également vérifier si deux cartes partagent un type de permanent. Vous trouverez ci-dessous l'image de cette carte :

Commençons par observer le code de cette carte :

<?xml version="1.0" encoding="ISO-8859-1"?>
<card xmlns="http://sourceforge.net/projects/magic-project" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://sourceforge.net/projects/magic-project ../../mpvalidator.xsd"
 name="Cloudstone Curio">
 <rules-author-comment>Hoani CROSS</rules-author-comment>
 <init>
  <registers>
   <register index="colorless" value="3"/>
  </registers>
  <idcards>artifact</idcards>
 </init>
 <abilities>
  <ability ref="cast-spell"/>
  <triggered-ability zone="play">
   <moved-card>
    <source-test>
     <not>
      <in-zone zone="play"/>
     </not>
    </source-test>
    <destination-test>
     <and>
      <in-zone zone="play"/>
      <controller player="you"/>
      <not>
       <has-idcard idcard="artifact"/>
      </not>
     </and>
    </destination-test>
   </moved-card>
   <cost>
    <choice cancel="true">
     <either>
      <target type="card" mode="choose" restriction-zone="play" raise-event="false">
       <test>
        <and>
         <controller player="you"/>
         <not>
          <is targetable="context.card"/>
         </not>
         <sup right="0">
          <left>
           <and>
            <left>
             <card-types card="context.card"/>
            </left>
            <right>
             <card-types card="tested"/>
            </right>
           </and>
          </left>
         </sup>
        </and>
       </test>
      </target>
     </either>
    </choice>
   </cost>
   <effects>
    <action ref="return-to-hand"/>
   </effects>
  </triggered-ability>
 </abilities>
</card>

L'élément <init> nous montre que cette carte est un artefact avec un coût d'invocation de 3.

<init>
 <registers>
  <register index="colorless" value="3"/>
 </registers>
 <idcards>artifact</idcards>
</init>

Observons les capacités de cette carte car elles contiennent les parties les plus importantes concernant l'implémentation de la carte.

La première capacité est bien sûr celle qui permet au propriétaire de cette carte de l'invoquer.

<ability ref="cast-spell"/>

La capacité principale de la carte est une capacité déclenchée qui se déclenche uniquement pendant que la carte est en jeu :

<triggered-ability zone="play">

La capacité de la carte commence par "À chaque fois qu'un permanent non-artefact arrive en jeu sous votre contrôle". Ainsi la capacité va se déclencher si une carte est déplacée depuis une zone différente de la zone de jeu vers la zone de jeu et seulement si la carte déplacée est une carte non-artefact que vous contrôlez.

<moved-card>
 <source-test>
  <not>
   <in-zone zone="play"/>
  </not>
 </source-test>
 <destination-test>
  <and>
   <in-zone zone="play"/>
   <controller player="you"/>
   <not>
    <has-idcard idcard="artifact"/>
   </not>
  </and>
 </destination-test>
</moved-card>

Cette capacité a un coût caché : cibler un permanent valide pour éventuellement le faire retourner dans la main de son propriétaire. C'est pourquoi l'élément suivante est un élément <cost> :

<cost>
 <choice cancel="true">
  <either>
   <target type="card" mode="choose" restriction-zone="play" raise-event="false">
    <test>
     <and>
      <controller player="you"/>
      <not>
       <is targetable="context.card"/>
      </not>
      <sup right="0">
       <left>
        <and>
         <left>
          <card-types card="context.card"/>
         </left>
         <right>
          <card-types card="tested"/>
         </right>
        </and>
       </left>
      </sup>
     </and>
    </test>
   </target>
  </either>
 </choice>
</cost>

Le contrôlleur de carte a le choix de cibler ou non le permanent, c'est pourquoi vous trouverez l'élément suivante avec l'attribut cancel renseigné à true :

<choice cancel="true">
 <either>
  <target type="card" mode="choose" restriction-zone="play" raise-event="false">
   <test>
    <and>
     <controller player="you"/>
     <not>
      <is targetable="context.card"/>
     </not>
     <sup right="0">
      <left>
       <and>
        <left>
         <card-types card="context.card"/>
        </left>
        <right>
         <card-types card="tested"/>
        </right>
       </and>
      </left>
     </sup>
    </and>
   </test>
  </target>
 </either>
</choice>

Laisser le contrôleur cibler un permanent est est réalisé par l'élément suivant (l'attribut raise-event est renseigné avec false car la capacité n'est pas ciblée) :

<target type="card" mode="choose" restriction-zone="play" raise-event="false">
 <test>
  <and>
   <controller player="you"/>
   <not>
    <is targetable="context.card"/>
   </not>
   <sup right="0">
    <left>
     <and>
      <left>
       <card-types card="context.card"/>
      </left>
      <right>
       <card-types card="tested"/>
      </right>
     </and>
    </left>
   </sup>
  </and>
 </test>
</target>

Le test doit vérifier que le permanent ciblé ("tested") est contrôlé par vous et qu'il n'est pas la carte qui vient de déclencher cette capacité ("context.card") et qu'il partage un type de carte avec la carte qui vient de déclencher cette capacité :

<and>
 <controller player="you"/>
 <not>
  <is targetable="context.card"/>
 </not>
 <sup right="0">
  <left>
   <and>
    <left>
     <card-types card="context.card"/>
    </left>
    <right>
     <card-types card="tested"/>
    </right>
   </and>
  </left>
 </sup>
</and>

Les effets de cette capacité déclenchée sont déclarés avec l'élément suivant :

<effects>
 <action ref="return-to-hand"/>
</effects>

La référence d'action "return-to-hand" retourne les cartes de la liste des cibles dans la main de leurs propriétaires respectifs.