⚔ Créer un scénario pour Hexes Med
Guide complet — aucune connaissance en programmation requise
Comment ça marche ?
Vous créez un dossier sur votre ordinateur contenant plusieurs petits fichiers texte (extension .php, mais ce ne sont que des listes de données à remplir — pas de programmation). Une fois terminé, vous envoyez ce dossier à l'administrateur du site avec quelques informations, et il s'occupe de la mise en ligne et des tests.

Les fichiers PHP sont ouverts avec n'importe quel éditeur de texte (Bloc-notes, Notepad++, VS Code…). Le format est toujours le même : vous remplissez des valeurs entre guillemets ou avec des chiffres, en suivant les exemples de ce guide.

Table des matières

  1. Structure des fichiers
  2. Enregistrement en base de données
  3. meta.php — Période historique
  4. map.php — Carte hexagonale
  5. units.php — Unités
  6. gamedatas.php — Configuration générale
  7. victory.php — Conditions de victoire
  8. ai.php — Intelligence artificielle
  9. context.php — Texte historique
  10. Images du scénario

1. Créer le dossier du scénario

Créez un dossier sur votre ordinateur. Son nom est le slug de votre scénario : choisissez un identifiant court, tout en minuscules, avec des underscores (tirets bas) à la place des espaces, sans accents.

Exemples de noms de dossier :
  battle_of_agincourt
  crecy_1346
  bataille_de_poitiers

À l'intérieur de ce dossier, vous créerez les fichiers décrits dans ce guide. Les fichiers obligatoires sont indispensables pour que le scénario fonctionne. Les fichiers optionnels enrichissent l'expérience mais le jeu marche sans eux.

mon_scenario/
├── meta.php          # Période historique (2 lignes) obligatoire
├── map.php           # Grille de terrain obligatoire
├── units.php         # Liste des unités des deux camps obligatoire
├── gamedatas.php    # Noms des camps, nombre de tours… obligatoire
├── victory.php      # Comment gagner obligatoire
├── ai.php            # Comportement de l'IA optionnel
├── context.php      # Texte historique affiché sur le site optionnel
├── context_img.jpg  # Image d'illustration (ajoutée via l'admin) optionnel
└── context_map.jpg  # Carte de déploiement (ajoutée via l'admin) optionnel

2. Transmettre le scénario à l'administrateur

Une fois vos fichiers prêts, envoyez le dossier complet à l'administrateur du site (par email, partage de fichier ou autre), accompagné des informations suivantes :

Information à fournirDescriptionExemple
Nom du dossier (slug) Le nom exact du dossier que vous avez créé battle_of_crecy
Nom affiché Le nom tel qu'il apparaîtra dans les menus du site Bataille de Crécy — 1346
Accès premium ? Ce scénario doit-il être réservé aux comptes payants ? Non
L'administrateur activera d'abord le scénario en mode bêta (visible uniquement à lui) pour le tester, puis le rendra public une fois validé. Il vous contactera si quelque chose ne fonctionne pas.

3. meta.php — Période historique Obligatoire

Classe le scénario dans un groupe affiché dans le menu de création de partie.

<?php return ['period' => 'hundred_years_war'];
ValeurGroupe affiché
'hundred_years_war'Guerre de Cent Ans
'misc'Divers (par défaut si valeur inconnue)

Pour ajouter une nouvelle période, déclarez-la dans games/hexes_med/create.php ($periodLabels et $periodOrder).

4. map.php — Carte hexagonale Obligatoire

Définit la grille de terrain. La carte est un tableau 2D de valeurs entières, chaque ligne représentant une rangée d'hexagones (de haut en bas).

<?php return [

    'rotation_default'    => 0,           // Rotation initiale : 0, 90, 180 ou 270 degrés
    'type_draw_default'   => 'generic',   // Style graphique (laisser 'generic')
    'type_ground_default' => 'greenlands',// Fond de carte (laisser 'greenlands')
    'special_tiles'       => [],          // Tuiles spéciales (laisser [] pour l'instant)

    'offset_x' => 280,   // Décalage horizontal en pixels (centrage de la carte)
    'offset_y' => 215,   // Décalage vertical en pixels

    // La carte : tableau de lignes, chaque ligne = tableau de colonnes
    // Conseil : ajouter les numéros de colonnes en commentaire pour s'y retrouver
    'map' => [
    //   1    2    3    4    5
      [  0,   0,   1,   2,   0 ],  // ligne 1
      [  0,   5,   0,   0,   0 ],  // ligne 2
      [ -1,   0,   3,   0,  -1 ],  // ligne 3 (-1 = case inexistante)
    ],

];

Types de terrain disponibles

ValeurConstanteNomDéfenseMouvementCharge
-1Case inexistante (hors carte)
0T_CLEARPlaine+0×1Oui
1T_WOODForêt+2×2Non
2T_HILLColline+1×2Non
3T_VILLAGEVillage+2×1Non
4T_RIVERRivière+1×3Non
5T_ROADRoute+0×0.5Oui
6T_FORTFort+3×1Non
7T_SWAMPMarécage+0×3Non
8T_PREPAREDTerrain préparé+0×1Non

Identifiants d'hexagones (hex ID)

Le moteur identifie chaque hexagone par colonne × 100 + ligne. Exemple : colonne 5, ligne 3 → hex ID 503. Les colonnes et lignes commencent à 1.

5. units.php — Unités Obligatoire

Définit toutes les unités des deux camps avec leur position de départ.

<?php

require_once __DIR__ . '/../../unit_types.php'; // indispensable pour les constantes

return [

    // Chaque unité est un tableau associatif
    ['id'=>1, 'name'=>'Nom affiché', 'camp'=>1, 'sprite'=>0,
     'type'=>T_ELITE_CAVALRY, 'side'=>1, 'is_leader'=>0, 'hex'=>503, 'in_game'=>1],

    ['id'=>2, 'name'=>'Chef de guerre', 'camp'=>1, 'sprite'=>0,
     'type'=>T_HEAVY_INFANTRY, 'side'=>1, 'is_leader'=>1, 'hex'=>504, 'in_game'=>1],

    // Camp 2
    ['id'=>10, 'name'=>'Ennemi', 'camp'=>2, 'sprite'=>0,
     'type'=>T_LIGHT_INFANTRY, 'side'=>1, 'is_leader'=>0, 'hex'=>509, 'in_game'=>1],

];

Champs d'une unité

ChampTypeDescription
idintIdentifiant unique. Commencer à 1, ne pas réutiliser.
namestringNom affiché sur l'interface et dans les logs de combat.
camp1 ou 2Camp de l'unité. Camp 1 joue en premier.
spriteint0 = sprite générique automatique. N > 0 = ligne N dans units.png.
typeconstanteType d'unité (voir tableau ci-dessous). Détermine toutes les stats.
side1 ou 21 = recto (pleine force). 2 = verso (déjà affaiblie au départ).
is_leader0 ou 1Chef : +1 mêlée recto et verso. Affiche une couronne en mode générique.
hexintHex de départ : col×100 + ligne. Ex : col 5 ligne 3 → 503.
in_game0 ou 1Toujours 1 pour les unités actives au départ.

Types d'unités disponibles

ConstanteMêlée R/VTir R/VPortéeMvtChargeUsage
T_ELITE_CAVALRY6 / 35OuiChevaliers, Templiers, Hospitaliers
T_HEAVY_CAVALRY5 / 25OuiCavalerie lourde non-chevaleresque
T_LIGHT_CAVALRY3 / 16OuiCavalerie légère, nomades
T_ELITE_INFANTRY6 / 32NonGarde d'élite, vétérans
T_HEAVY_INFANTRY5 / 22NonHommes d'armes, infanterie lourde
T_LIGHT_INFANTRY3 / 13NonInfanterie légère, milice agile
T_MILITIA2 / 12NonMilice, paysans armés
T_ARCHER2 / 14 / 222NonArchers standard
T_HEAVY_ARCHER3 / 15 / 232NonLongbow, archers lourds
T_CROSSBOWMAN2 / 14 / 222NonArbalétriers
T_MOUNTED_ARCHER3 / 14 / 225NonArchers montés occidentaux
T_HORSE_ARCHER2 / 14 / 234NonArchers à cheval steppiques
R = recto (face 1, pleine force) · V = verso (face 2, floor(R/2))
Un chef (is_leader=1) ajoute +1 à la mêlée recto ET verso.

6. gamedatas.php — Configuration générale Obligatoire

<?php return [

    // Couleurs des camps (hexadécimal sans #, pour les pions et l'interface)
    'campColor1'   => 'cc0000',   // couleur du texte / bordure camp 1
    'campColor2'   => '003399',   // couleur du texte / bordure camp 2
    'campBgColor1' => 'e88080',   // couleur de fond des pions camp 1
    'campBgColor2' => '7090cc',   // couleur de fond des pions camp 2

    // Noms des camps affichés dans l'interface
    'campName1' => 'Francs',
    'campName2' => 'Sarrasins',

    // Nombre de tours maximum par joueur (total de tours = turn_max × 2)
    'turn_max' => 6,

    // Camp qui joue en premier (1 ou 2)
    'first_camp' => 1,

    // Personnalité IA de base (utilisé si pas de ai.php)
    // aggression 0-5 : témérité au combat
    // pursuit    0-5 : agressivité des déplacements vers l'ennemi
    // objectives 0-5 : priorité aux hexes objectifs
    'ai' => [
        1 => ['aggression' => 3, 'pursuit' => 3, 'objectives' => 2],
        2 => ['aggression' => 3, 'pursuit' => 3, 'objectives' => 2],
    ],

    // Noms traduits du scénario (affichés dans les menus)
    'names' => [
        'fr' => 'Mon Scénario',
        'en' => 'My Scenario',
    ],

];
Si ai.php est présent, les paramètres ai de gamedatas.php sont ignorés. Gardez-les quand même comme valeurs de secours.

7. victory.php — Conditions de victoire Obligatoire

<?php return [

    // Camp vainqueur par défaut si aucun objectif n'est rempli au dernier tour
    // 0 = match nul, 1 = camp 1 gagne, 2 = camp 2 gagne
    'default' => 1,

    // Unités commandantes affichées sur l'écran de victoire
    // Format : [camp => id_de_l_unité_dans_units.php]
    'commanders' => [1 => 1, 2 => 10],

    // Objectifs de victoire (vérifiés à chaque fin de tour sauf 'endgame')
    'objectives' => [

        // --- Tuer un chef ---
        [
            'type' => 'leader_killed',
            'camp' => 1,            // camp qui gagne si cette condition est remplie
            'name' => 'Saladin',    // nom exact de l'unité (champ 'name' dans units.php)
            'when' => 'per_turn',   // vérifié après chaque tour
        ],

        // --- Destruction d'un pourcentage de l'armée adverse ---
        [
            'type'   => 'destruction_pct',
            'camp'   => 2,          // camp qui gagne
            'target' => 1,          // camp dont on compte les pertes
            'value'  => 50,         // 50 % des forces (en valeur de mêlée) éliminées
            'when'   => 'per_turn',
        ],

        // --- Contrôle d'hexagones ---
        [
            'type'  => 'control',
            'camp'  => 1,
            'hexes' => [503, 504, 505], // IDs des hexes à contrôler (tous nécessaires)
            'when'  => 'endgame',       // vérifié seulement au dernier tour
        ],

    ],

];

Types d'objectifs

TypeDescriptionChamps requis
leader_killed Victoire quand l'unité nommée est éliminée camp, name, when
destruction_pct Victoire quand X % de la force de mêlée ennemie est détruite camp, target, value, when
control Victoire quand toutes les cases listées sont occupées camp, hexes, when

Valeur when

ValeurMoment de vérification
'per_turn'Après chaque fin de tour (les deux camps)
'endgame'Uniquement au dernier tour
destruction_pct compare la somme des valeurs de mêlée des unités éliminées avec le total initial. Exemple : armée de 10 unités de mêlée 5 = total 50. 50 % = 25 points de mêlée à détruire.

8. ai.php — Intelligence artificielle Optionnel

Ce fichier remplace les paramètres ai de gamedatas.php par des comportements précis et historiquement réalistes. Le fichier contient sa propre documentation complète — il suffit d'ouvrir le fichier de n'importe quel scénario pour y trouver le guide intégral.

Cas simple (une stratégie fixe par camp)

<?php return [
    1 => ['strategy' => 'hold',   'aggression' => 2],
    2 => ['strategy' => 'charge', 'aggression' => 4],
];

Stratégies disponibles

StratégieMouvementCombatExemple historique
'hold'Ne bouge pasAttaque si adjacentAnglais à Azincourt
'advance'Approche prudemmentAttaque si favorableInfanterie standard
'charge'Fonce vers l'ennemiAttaque même défavorableFrançais à Azincourt
'retreat'S'éloigneN'attaque pasGénois en déroute à Crécy
'skirmish'Maintient portée de tirTir à distance seulementArchers à cheval

Cas complexe (phases séquentielles)

<?php return [
    1 => ['strategy' => 'hold', 'aggression' => 2],
    2 => [
        'aggression' => 4,
        'phases' => [
            [
                'label'    => 'Arbalétriers en avant',
                'active'   => ['Arbalétriers génois'], // noms dans units.php
                'others'   => 'hold',                  // les autres attendent
                'strategy' => 'advance',
                'exit'     => [                        // plusieurs conditions : passe si l'une est vraie
                    ['losses_pct'    => ['Arbalétriers génois' => 50]],
                    ['turn'          => 4],
                ],
            ],
            [
                'label'    => 'Fuite des Génois',
                'active'   => ['Arbalétriers génois'],
                'others'   => 'hold',
                'strategy' => 'retreat',
                'exit'     => ['all_eliminated' => ['Arbalétriers génois']],
            ],
            [
                'label'    => '1ère charge',
                'active'   => 'group:vague_1',
                'others'   => 'hold',
                'strategy' => 'charge',
                'exit'     => ['group_broken' => 'vague_1', 'threshold' => 50],
            ],
            [
                'label'    => '2ème vague',
                'active'   => 'group:vague_2',
                'strategy' => 'charge',
                // Pas de 'exit' : reste ici jusqu'à la fin
            ],
        ],
        'groups' => [
            'vague_1' => [16, 17, 18, 19, 20],  // IDs d'units.php
            'vague_2' => [21, 22, 23, 24, 25],
        ],
        // Modifications historiques de stats (valeur affichée en gris sur les pions)
        'unit_overrides' => [
            'Arbalétriers génois' => ['melee_malus' => -2],
        ],
    ],
];

Conditions de sortie de phase

ConditionDéclenchement
['losses_pct' => ['Nom' => 50]]Quand ≥ 50 % des unités "Nom" sont perdues
['all_eliminated' => ['Nom A', 'Nom B']]Quand toutes ces unités sont éliminées
['group_broken' => 'g', 'threshold' => 50]Quand le groupe a perdu ≥ 50 % de ses unités
['turn' => 3]Quand le tour atteint ce numéro

9. context.php — Texte historique Optionnel

Texte affiché sur la page publique du scénario. Il doit expliquer le contexte historique, les forces en présence, et peut mentionner les modifications de stats (unit_overrides) si besoin.

<?php return [

    'fr' => "En [date], [résumé historique court, 2-4 phrases].

Ce scénario reconstitue [moment clé]. Les [camp 1] doivent [objectif],
tandis que les [camp 2] cherchent à [objectif adverse].

Note historique : [expliquer ici les unit_overrides si utilisés,
ex : les arbalétriers génois avaient laissé leurs boucliers sur les chariots,
réduisant leur valeur de défense de 2 points].",

    'en' => "In [date], [short historical summary].

This scenario recreates [key moment]...",

];
Ajoutez autant de langues que nécessaire ('es', 'de', 'it'…). Si une langue est manquante, le moteur affiche le texte français par défaut.

Enrichissement depuis le panneau d'administration

Une fois le scénario en ligne, l'administrateur peut compléter la page publique sans modifier context.php, directement depuis le panneau admin :

Ces enrichissements sont stockés dans context_override.json (généré automatiquement, ne pas créer à la main).

10. Images du scénario Optionnel

Deux images peuvent illustrer la page publique du scénario. Elles sont uploadées directement depuis le panneau d'administration — pas besoin de les créer dans le dossier.

FichierRôleConseils
context_img.jpg Image d'illustration principale affichée en tête de page Peinture ou reconstitution de la bataille. Format paysage recommandé (16:9 ou similaire).
context_map.jpg Carte ou plan de déploiement historique Carte du champ de bataille, plan d'ordre de bataille, ou capture d'écran de la carte en jeu.
Format accepté : JPEG uniquement. L'image est renommée automatiquement lors de l'upload. Si vous fournissez des images avec le dossier du scénario, indiquez-le à l'administrateur qui les uploadera via le panneau.
Vous avez une idée de scénario ?

Vous connaissez une bataille qui mériterait d'être jouée sur Hexes Med ?
Contactez-nous via le formulaire — choisissez le sujet « Créer un scénario » et décrivez votre idée (bataille, époque, sources disponibles). Nous vous répondrons pour vous accompagner dans la création.

Nous contacter