# Mods de jeu

> Un schéma n’est pas forcément une IA qui joue à votre place : ce peut aussi être un ensemble de règles. Vous jouez vous-même dans la fenêtre du jeu ; le mod prépare le début de partie, fait apparaître les monstres, distribue les récompenses, vous présente boutons et cartes de choix à l’écran et décide de l’issue. Héritez de openwar3.Mod : un fichier, un gameplay complet.

Source: https://war3ai.com/fr/docs/mods/

Les [schémas d’IA](https://war3ai.com/fr/docs/schemes/) sont de deux sortes : `kind: bot` est une IA qui joue à votre place ; `kind: mod` est **un ensemble de règles** — vous jouez vous-même dans la fenêtre du jeu, et le mod vous lance les défis : comment la partie est préparée, quand les monstres apparaissent (selon le temps ou les événements), quelles récompenses sont données, quels boutons et cartes de choix s’affichent à l’écran, quand la partie est gagnée.

Un mod n’utilise que des capacités existantes : [Interface et entrées](https://war3ai.com/fr/docs/ui-input/) (boutons et cartes cliquables, raccourcis clavier, clics au sol), le [canevas](https://war3ai.com/fr/docs/canvas/) (panneaux, barres de progression, tracés), le [canal JASS](https://war3ai.com/fr/docs/jass/) (faire apparaître des unités, modifier des caractéristiques, donner des objets) et le flux d’événements (morts, montées de niveau, sorts lancés, chat).

## Deux exemples

À choisir dans Farsight, sous « Schémas d’IA » → « Intégrés » :

| Mod | Principe | Capacités utilisées |
|---|---|---|
| **Roguelike de héros** `builtin/hero-roguelike` | Vous n’avez qu’un paladin, et les monstres arrivent par vagues de tous les côtés ; à chaque niveau gagné, choisissez un bonus parmi trois au centre de l’écran (le jeu est en pause pendant le choix) ; tenez 10 vagues pour gagner ; si le héros meurt, c’est perdu | `g.ui.choice` (cartes cliquables + pause), événements `hero.levelup` / `killed` / `spell.cast`, `-help` dans le chat, JASS pour modifier les caractéristiques du héros et donner des objets |
| **Défense sans fin** `builtin/endless-defense` | Les monstres partent du point de départ opposé et foncent vers votre bâtiment principal en suivant une ligne rouge tracée au sol ; chaque vague repoussée rapporte de l’or ; cliquez sur le bouton à l’écran ou appuyez sur F7 pour appeler la vague suivante plus tôt, avec une récompense ×1.5 ; appuyez sur F8 puis faites un clic gauche au sol pour poser une tour de garde gratuite (clic droit pour annuler) | `g.ui.button`, `g.ui.hotkey`, `g.ui.mouse` (capture des clics au sol), panneau / barre de progression / tracé du canevas, JASS pour faire apparaître les monstres et ajouter de l’or |

Chacun des deux exemples fait environ 150 lignes ; le code se trouve dans `brains/examples/mod_hero_roguelike.py` et `brains/examples/mod_endless_defense.py`.

```bash
python tools/play.py --bot brains/examples/mod_hero_roguelike.py --inst 9     # lance une partie, le mod prend la main, vous jouez dans la fenêtre du jeu
```

## Écrire un mod

```python
from openwar3 import Mod

class Survive(Mod):
    name = "survive"

    def on_start(self, g):
        super().on_start(g)                        # vérifie qu'on est en solo + neutralise l'ordinateur adverse
        self.foe = self.wave_player(g)             # un emplacement libre devient le « joueur des vagues » : allié de personne, sans IA d'ordinateur
        self.every(30, self.wave)                  # une vague toutes les 30 secondes de jeu (rien ne s'écoule pendant la pause)
        g.ui.hotkey("F7", lambda g, ev: self.wave(g))

    def wave(self, g):
        self.spawn_ring(g, self.foe, "ugho", 6, self.home(g), 1400, attack_to=self.home(g))

    def on_event(self, g, ev):
        if ev.kind == "unit.died" and ev.type == "htow":
            self.finish("loss", "L'hôtel de ville est tombé")
```

Par rapport à `Bot`, `Mod` ajoute :

| Méthode / attribut | Description |
|---|---|
| `on_start / on_tick / on_event / on_end` | Comme pour Bot ; si vous surchargez `on_start` / `on_tick`, appelez d’abord `super()` |
| `every(secondes, fn, first=)` / `after(secondes, fn)` | Minuteurs qui suivent le **temps de jeu** ; le callback est `fn(g)` |
| `finish(result, reason)` | Termine la partie (`'win'` / `'loss'` / `'unknown'`) : l’exécuteur s’arrête au tick suivant, un panneau de résultat est dessiné au centre de l’écran, et le bilan du schéma est enregistré d’après ce résultat |
| `wave_player(g)` | Le premier emplacement de joueur libre, à utiliser comme joueur des vagues |
| `spawn_ring(g, joueur, unité, nombre, centre, rayon, attack_to=)` | Fait apparaître des unités sur un cercle, sans à-coups même par dizaines à chaque vague ; renvoie les handles JASS |
| `alive_of(g, joueur)` / `attack_move_all(g, joueur, point)` | Les unités vivantes d’un joueur / toutes en attaque-déplacement vers un point (appelez-la toutes les quelques secondes pour que les monstres vous poursuivent) |
| `home(g)` / `hud(g, titre, lignes)` | Position de notre bâtiment principal / panneau d’informations en haut à droite |
| `neutralize_ai = True` | Neutralise l’ordinateur adverse en début de partie : ses unités sont mises en pause toutes les 5 secondes, son or et son bois remis à zéro. Une carte de mêlée a toujours un ordinateur ; quand le mod fixe ses propres règles, il ne doit pas venir perturber la partie |
| `single_player_only = True` | Refuse de s’exécuter s’il y a d’autres joueurs humains (le JASS qui modifie le monde les désynchroniserait) |
| `linger_s = 6` | Une fois l’issue décidée, nombre de secondes passées sur l’écran de résultat avant de terminer |

`finish()` fonctionne aussi sur `Bot` : un Bot ordinaire peut lui aussi annoncer lui-même la fin de la partie.

## En faire un schéma et le partager

Écrivez `"kind": "mod"` dans `scheme.json`, et définissez une sous-classe de `Mod` dans le fichier d’entrée :

```json
{"id": "survive", "name": "Tenir 10 vagues", "kind": "mod", "entry": "survive.py", "class": "Survive"}
```

Un mod **n’est jamais en mode équitable** (c’est l’arbitre qui pose les défis : il doit voir toute la carte et modifier le monde), et **son issue n’est jamais jugée selon les règles de mêlée** (c’est `finish` qui la signale) ; `fair` / `judge` dans le manifeste sont sans effet. Export en zip, import, confiance et bilan fonctionnent exactement comme pour les schémas de Bot : voir [Schémas d’IA](https://war3ai.com/fr/docs/schemes/). Un mod, c’est aussi du code : avant la première exécution du mod de quelqu’un d’autre, il faut également confirmer votre confiance.

## Mesures

2026-09-25, sur une instance de test :

- **Roguelike de héros** : la première vague apparaît, le panneau en haut à droite se met à jour ; héros monté au niveau 3 → des cartes s’affichent au centre de l’écran et l’horloge du jeu s’arrête ; deux clics sur des cartes → deux bonus appliqués (force 22 → 27), l’horloge repart.
- **Défense sans fin** : panneau, tracé au sol et bouton sont bien là ; F8 + clic au sol → une tour de défense apparaît à côté du bâtiment principal ; clic sur le bouton alors que la vague en cours n’est pas terminée → message « cette vague n’est pas encore terminée ».

## Limites

- **Parties solo uniquement** : faire apparaître des unités et modifier des caractéristiques passe par le canal JASS, ce qui désynchronise une partie multijoueur. C’est une conséquence du modèle lockstep ; un gameplay multijoueur devra attendre un canal de synchronisation (voir la [feuille de route](https://war3ai.com/fr/roadmap/)).
- Le mod voit toute la carte — c’est lui qui pose les défis, ce n’est pas un joueur.
- Dans une carte de mêlée, l’ordinateur adverse est seulement « neutralisé », pas retiré (le retirer déclencherait la victoire selon les règles de mêlée).
