.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.
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.
À 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.
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 à fournir | Description | Exemple |
|---|---|---|
| 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 |
Classe le scénario dans un groupe affiché dans le menu de création de partie.
<?php return ['period' => 'hundred_years_war'];
| Valeur | Groupe 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).
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)
],
];
| Valeur | Constante | Nom | Défense | Mouvement | Charge |
|---|---|---|---|---|---|
-1 | — | Case inexistante (hors carte) | — | — | — |
0 | T_CLEAR | Plaine | +0 | ×1 | Oui |
1 | T_WOOD | Forêt | +2 | ×2 | Non |
2 | T_HILL | Colline | +1 | ×2 | Non |
3 | T_VILLAGE | Village | +2 | ×1 | Non |
4 | T_RIVER | Rivière | +1 | ×3 | Non |
5 | T_ROAD | Route | +0 | ×0.5 | Oui |
6 | T_FORT | Fort | +3 | ×1 | Non |
7 | T_SWAMP | Marécage | +0 | ×3 | Non |
8 | T_PREPARED | Terrain préparé | +0 | ×1 | Non |
Le moteur identifie chaque hexagone par colonne × 100 + ligne.
Exemple : colonne 5, ligne 3 → hex ID 503.
Les colonnes et lignes commencent à 1.
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],
];
| Champ | Type | Description |
|---|---|---|
id | int | Identifiant unique. Commencer à 1, ne pas réutiliser. |
name | string | Nom affiché sur l'interface et dans les logs de combat. |
camp | 1 ou 2 | Camp de l'unité. Camp 1 joue en premier. |
sprite | int | 0 = sprite générique automatique. N > 0 = ligne N dans units.png. |
type | constante | Type d'unité (voir tableau ci-dessous). Détermine toutes les stats. |
side | 1 ou 2 | 1 = recto (pleine force). 2 = verso (déjà affaiblie au départ). |
is_leader | 0 ou 1 | Chef : +1 mêlée recto et verso. Affiche une couronne en mode générique. |
hex | int | Hex de départ : col×100 + ligne. Ex : col 5 ligne 3 → 503. |
in_game | 0 ou 1 | Toujours 1 pour les unités actives au départ. |
| Constante | Mêlée R/V | Tir R/V | Portée | Mvt | Charge | Usage |
|---|---|---|---|---|---|---|
T_ELITE_CAVALRY | 6 / 3 | — | — | 5 | Oui | Chevaliers, Templiers, Hospitaliers |
T_HEAVY_CAVALRY | 5 / 2 | — | — | 5 | Oui | Cavalerie lourde non-chevaleresque |
T_LIGHT_CAVALRY | 3 / 1 | — | — | 6 | Oui | Cavalerie légère, nomades |
T_ELITE_INFANTRY | 6 / 3 | — | — | 2 | Non | Garde d'élite, vétérans |
T_HEAVY_INFANTRY | 5 / 2 | — | — | 2 | Non | Hommes d'armes, infanterie lourde |
T_LIGHT_INFANTRY | 3 / 1 | — | — | 3 | Non | Infanterie légère, milice agile |
T_MILITIA | 2 / 1 | — | — | 2 | Non | Milice, paysans armés |
T_ARCHER | 2 / 1 | 4 / 2 | 2 | 2 | Non | Archers standard |
T_HEAVY_ARCHER | 3 / 1 | 5 / 2 | 3 | 2 | Non | Longbow, archers lourds |
T_CROSSBOWMAN | 2 / 1 | 4 / 2 | 2 | 2 | Non | Arbalétriers |
T_MOUNTED_ARCHER | 3 / 1 | 4 / 2 | 2 | 5 | Non | Archers montés occidentaux |
T_HORSE_ARCHER | 2 / 1 | 4 / 2 | 3 | 4 | Non | Archers à cheval steppiques |
is_leader=1) ajoute +1 à la mêlée recto ET verso.
<?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',
],
];
ai.php est présent, les paramètres ai de gamedatas.php
sont ignorés. Gardez-les quand même comme valeurs de secours.
<?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
],
],
];
| Type | Description | Champs 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 |
when| Valeur | Moment 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.
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.
<?php return [
1 => ['strategy' => 'hold', 'aggression' => 2],
2 => ['strategy' => 'charge', 'aggression' => 4],
];
| Stratégie | Mouvement | Combat | Exemple historique |
|---|---|---|---|
'hold' | Ne bouge pas | Attaque si adjacent | Anglais à Azincourt |
'advance' | Approche prudemment | Attaque si favorable | Infanterie standard |
'charge' | Fonce vers l'ennemi | Attaque même défavorable | Français à Azincourt |
'retreat' | S'éloigne | N'attaque pas | Génois en déroute à Crécy |
'skirmish' | Maintient portée de tir | Tir à distance seulement | Archers à cheval |
<?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],
],
],
];
| Condition | Dé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 |
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]...",
];
'es', 'de', 'it'…).
Si une langue est manquante, le moteur affiche le texte français par défaut.
Une fois le scénario en ligne, l'administrateur peut compléter la page publique
sans modifier context.php, directement depuis le panneau admin :
context.php)context_img.jpg et context_map.jpg (voir section suivante)Ces enrichissements sont stockés dans context_override.json (généré automatiquement, ne pas créer à la main).
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.
| Fichier | Rôle | Conseils |
|---|---|---|
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. |
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.