> For the complete documentation index, see [llms.txt](https://shadybot.gitbook.io/shadybot/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://shadybot.gitbook.io/shadybot/shadybot-api.md).

# Shadybot API Documentation

Ce guide explique comment configurer et utiliser un script de trajet en C# pour automatiser les déplacements, récoltes, combats, mines, zaaps/zaapis, dialogues PNJ et passages en banque.

***

## 📋 Structure de base

```csharp
using System.Collections.Generic;
using Shadybot.Services.CustomAi;

public sealed class MyScript : CSharpRouteScript
{
    public override string Id   => "my_script";
    public override string Name => "My Script";
    public override bool   Loop => true;

    public override BuiltInCustomAiBankingProfile Banking() => Banking(
        podsPercent: 80
    );

    public override BuiltInCustomAiRestProfile Rest() => Rest(
        startHpPercent: 50,
        resumeHpPercent: 100,
        hpPerSecond: 0.5
    );

    public override int[] ResourceToGather() => ResourceToGather(7520);

    public override IReadOnlyList<CSharpRouteMoveStep> Bank() => Route(
        Move("2,-1", "top", fight: false),
        Bank("2,-2", "AmaknaBank")
    );

    public override IReadOnlyList<CSharpRouteMoveStep> Move() => Route(
        Move("2,-2", "bottom", gather: true),
        Move("2,-1", "top", gather: true)
    );
}
```

***

## ⚙️ Paramètres généraux

### Identifiant & Nom

```csharp
public override string Id   => "my_script";  // Identifiant unique du script
public override string Name => "My Script";  // Nom affiché
public override bool   Loop => true;         // Recommencer le trajet après la dernière étape
```

> **Important :** chaque script doit avoir un `Id` unique. Le `Name` est seulement le nom affiché dans Shadybot.

***

## 🎒 Gestion des PODs — `Banking()`

```csharp
public override BuiltInCustomAiBankingProfile Banking() => Banking(
    podsPercent: 80
);
```

Le bot passe en mode banque dès que ses PODs atteignent le pourcentage indiqué.

### Restreindre la vérification à certaines maps

Utile pour éviter que le bot tente d’aller en banque depuis un endroit dangereux ou depuis l’intérieur d’un donjon.

```csharp
public override BuiltInCustomAiBankingProfile Banking() => Banking(
    podsPercent: 80,
    checkMaps: new[] { 1856 }
);
```

| Paramètre     | Description                                                         |
| ------------- | ------------------------------------------------------------------- |
| `podsPercent` | Pourcentage de PODs à partir duquel le bot part en banque           |
| `checkMaps`   | Liste optionnelle de maps où la vérification des PODs est autorisée |

> **Note :** si votre script possède une méthode `Bank()`, Shadybot utilisera ce chemin `Bank()` lorsque le seuil de PODs est atteint.

***

## ❤️ Récupération de vie — `Rest()`

```csharp
public override BuiltInCustomAiRestProfile Rest() => Rest(
    startHpPercent: 50,
    resumeHpPercent: 100,
    hpPerSecond: 0.5
);
```

| Paramètre         | Description                                                          |
| ----------------- | -------------------------------------------------------------------- |
| `startHpPercent`  | Seuil de vie (%) en dessous duquel le script se met en pause         |
| `resumeHpPercent` | Seuil de vie (%) à partir duquel le script reprend                   |
| `hpPerSecond`     | Vitesse de régénération simulée (`0.5` = 1 HP toutes les 2 secondes) |

***

## 🏦 Chemin vers la banque — `Bank()`

La méthode `Bank()` définit le trajet utilisé quand le personnage doit se vider à la banque.

```csharp
public override IReadOnlyList<CSharpRouteMoveStep> Bank() => Route(
    Move("2,-1", "top", fight: false),
    Bank("2,-2", "AmaknaBank")
);
```

Une fois arrivé à la banque, Shadybot ouvre le banquier, dépose l’inventaire, ressort si nécessaire, puis reprend le trajet `Move()`.

### Banques disponibles

```csharp
Bank("4,-16", "AstrubBank")
Bank("2,-2", "AmaknaBank")
Bank("-31,-57", "BontaBank")
Bank("-26,35", "BrakmarBank")
Bank("24,-35", "PandalaBank")
```

| Nom du profil | Description       |
| ------------- | ----------------- |
| `AstrubBank`  | Banque d’Astrub   |
| `AmaknaBank`  | Banque d’Amakna   |
| `BontaBank`   | Banque de Bonta   |
| `BrakmarBank` | Banque de Brâkmar |
| `PandalaBank` | Banque de Pandala |

***

## 🚶 Trajet principal — `Move()`

Définit les étapes de déplacement, de récolte et de combat.

```csharp
public override IReadOnlyList<CSharpRouteMoveStep> Move() => Route(
    Move("1,-34", "left", fight: true),
    Move("1,-35", "right", gather: true)
);
```

### `Move()` — Se déplacer

```csharp
Move("map", "direction", fight: true/false, gather: true/false)
```

| Paramètre     | Type     | Description                                                               |
| ------------- | -------- | ------------------------------------------------------------------------- |
| `"map"`       | `string` | Coordonnées ou ID de la map                                               |
| `"direction"` | `string` | Direction de sortie (`"left"`, `"right"`, `"top"`, `"bottom"`) ou cellule |
| `fight`       | `bool`   | Activer les combats sur cette map                                         |
| `gather`      | `bool`   | Activer la récolte sur cette map                                          |
| `slot`        | `int`    | Optionnel : utiliser un raccourci/slot avant l’action                     |

**Exemples :**

```csharp
Move("1,-34", "left", fight: true)
Move("1,-34", "left", gather: true)
Move("4,-18", "top", fight: false, slot: 4)
Move(5971, "44", gather: true) // sortie par cellule précise
```

***

## 🌀 Zaap — `Zaap()`

```csharp
Zaap("map", cellId, "NomDuZaap")
```

Exemple :

```csharp
Zaap("1,-31", 297, "Astrub")
```

Le bot clique le zaap, tape le nom de destination et sélectionne la destination.

***

## 🏙️ Zaapi — `Zaapi()`

```csharp
Zaapi("map", cellZaapi, menuIndex, "destination")
Zaapi(mapId, cellZaapi, menuIndex, "destination")
```

Exemples :

```csharp
Zaapi(4263, 161, 2, "tour des ordres")
Zaapi("-32,-58", 161, 2, "tour des ordres")
```

| Paramètre       | Description                             |
| --------------- | --------------------------------------- |
| `map` / `mapId` | La map où se trouve le zaapi            |
| `cellZaapi`     | La cellule du zaapi à ouvrir            |
| `menuIndex`     | Onglet/menu à choisir : `1`, `2` ou `3` |
| `destination`   | Texte à taper dans la recherche         |

Le bot fait automatiquement :

1. Clic droit sur la cellule du zaapi.
2. Attend l’ouverture du menu.
3. Clique l’onglet/menu choisi.
4. Clique la barre de recherche.
5. Tape la destination.
6. Clique le premier résultat.

***

## 🐦 Phénix — `Phenix()` / `Phoenix()`

`Phenix()` permet de gérer automatiquement la résurrection quand le personnage n'a plus d'énergie.

```csharp
Phenix("map", cellId)
Phenix(mapId, cellId)
Phenix("map", cellId, slotNumber)
Phenix(mapId, cellId, slotNumber)
Phenix("map", cellId, "direction")
Phenix(mapId, cellId, "direction")
```

Exemples :

```csharp
Phenix(8534, 252, 2)
Phenix("-2,-4", 252, 2)
Phenix(8534, 252, "right")
```

| Paramètre       | Description                                                                                      |
| --------------- | ------------------------------------------------------------------------------------------------ |
| `map` / `mapId` | La map du Phénix                                                                                 |
| `cellId`        | La cellule du Phénix à cliquer pour se réincarner                                                |
| `slotNumber`    | Optionnel : slot/raccourci à utiliser après la résurrection                                      |
| `direction`     | Optionnel : direction de sortie après la résurrection (`"left"`, `"right"`, `"top"`, `"bottom"`) |

Le bot fait automatiquement :

1. Détecte le manque d'énergie après un combat.
2. Attend d'être sur une map configurée avec `Phenix()`.
3. Clique la cellule du Phénix.
4. Attend la résurrection.
5. Utilise le `slotNumber` si indiqué, sinon utilise la `direction` si indiquée.
6. Reprend ensuite le trajet normal.

> **Note :** `Phoenix()` est aussi accepté comme alias de `Phenix()`.

Exemple dans un trajet :

```csharp
public override IReadOnlyList<CSharpRouteMoveStep> Move() => Route(
    Phenix(8534, 252, 2),
    Zaapi(4263, 116, 2, "tour des ordres"),
    Move("-1,-32", "right", fight: true)
);
```

***

## 🗣️ Dialogue PNJ personnalisé — `TalkNPC()`

`TalkNPC()` permet de créer vos propres interactions avec des PNJ directement dans le script, sans attendre qu’un profil prédéfini existe dans Shadybot.

Il sert à remplacer les cas fixes comme `BoufPNJ`, `BlopPNJ`, `MeulouDJ`, etc., lorsque vous connaissez déjà où cliquer.

### Variante 1 — Par ID de PNJ

```csharp
TalkNPC(map, npcId, Dialog(x, y))
```

Exemple :

```csharp
TalkNPC(1234, 100, Dialog(119, 289))
```

Cette ligne veut dire :

1. Sur la map `1234`, chercher le PNJ avec l’ID `100`.
2. Faire un clic droit sur ce PNJ.
3. Attendre l’ouverture du dialogue.
4. Cliquer sur `X=119`, `Y=289` dans la fenêtre du client Dofus.

### Variante 2 — Par coordonnées X/Y

Si le PNJ ou l’objet ne peut pas être identifié facilement par ID, vous pouvez donner directement l’endroit où faire le clic droit.

```csharp
TalkNPC(map, rightClickX, rightClickY, Dialog(x, y))
```

Exemple :

```csharp
TalkNPC(1234, 476, 169, Dialog(119, 289))
```

Cette ligne veut dire :

1. Sur la map `1234`, faire un clic droit en `X=476`, `Y=169`.
2. Attendre l’ouverture du dialogue/menu.
3. Cliquer sur `X=119`, `Y=289`.

### Plusieurs choix de dialogue

Vous pouvez enchaîner plusieurs clics de dialogue dans la même étape.

```csharp
TalkNPC(1234, 100,
    Dialog(119, 289),
    Dialog(180, 320),
    Dialog(220, 360)
)
```

Le bot fera :

1. clic droit sur le PNJ ;
2. clic sur le premier choix ;
3. pause courte ;
4. clic sur le deuxième choix ;
5. pause courte ;
6. clic sur le troisième choix.

### Exemple dans un trajet

```csharp
public override IReadOnlyList<CSharpRouteMoveStep> Move() => Route(
    Move("1,-34", "left", fight: false),

    // Interaction avec un PNJ par ID
    TalkNPC("0,-34", 100,
        Dialog(119, 289)
    ),

    // Interaction avec un PNJ/objet par coordonnées absolues
    TalkNPC("0,-35", 476, 169,
        Dialog(119, 289),
        Dialog(180, 320)
    ),

    Move("0,-35", "right", fight: true)
);
```

| Élément                      | Description                                              |
| ---------------------------- | -------------------------------------------------------- |
| `map` / `mapId`              | Map où l’action doit être exécutée                       |
| `npcId`                      | ID du PNJ à clic droit                                   |
| `rightClickX`, `rightClickY` | Coordonnées absolues du clic droit dans le client Dofus  |
| `Dialog(x, y)`               | Coordonnées absolues du choix de dialogue/menu à cliquer |

> **Important :** les coordonnées `X/Y` sont les coordonnées affichées dans le `GameClientWindow`, pas les cellules de la map. Placez votre souris sur le bon choix et copiez les valeurs affichées en haut de la fenêtre.

> **Astuce :** utilisez `TalkNPC()` pour les donjons ou menus spéciaux. Les anciens profils `Pnj(...)` restent utilisables, mais `TalkNPC()` est plus flexible pour partager des scripts entre utilisateurs.

## 🐲 Filtres de monstres — `MandatoryMonster()` / `ForbiddenMonster()`

Ces méthodes permettent de choisir quels groupes de monstres le bot peut attaquer pendant un trajet C#. Elles s'appliquent aux maps où le combat est activé avec `fight: true`.

```csharp
public override int[] MandatoryMonster() => MandatoryMonster(61, 134);
public override int[] ForbiddenMonster() => ForbiddenMonster(48);
public override CSharpRouteMonsterCountFilter MaxMinMonster() => MaxMinMonster(1, 6);
```

| Méthode              | Description                                                                            |
| -------------------- | -------------------------------------------------------------------------------------- |
| `MandatoryMonster()` | Le bot attaque seulement les groupes qui contiennent au moins un des monstres indiqués |
| `ForbiddenMonster()` | Le bot ignore les groupes qui contiennent un des monstres indiqués                     |
| `MaxMinMonster()`    | Filtre optionnel sur le nombre de monstres dans le groupe                              |

### `MandatoryMonster()` — Monstres obligatoires

```csharp
public override int[] MandatoryMonster() => MandatoryMonster(61, 134);
```

Dans cet exemple, le bot cherchera uniquement les groupes contenant le monstre `61` ou le monstre `134`. Si vous ne voulez pas imposer de monstre obligatoire, ne mettez pas cette méthode ou retournez une liste vide.

### `ForbiddenMonster()` — Monstres interdits

```csharp
public override int[] ForbiddenMonster() => ForbiddenMonster(48);
```

Dans cet exemple, le bot n'attaquera jamais un groupe contenant le monstre `48`. C'est utile pour éviter certains monstres dangereux ou trop longs à tuer.

### `MaxMinMonster()` — Nombre minimum / maximum de monstres

```csharp
public override CSharpRouteMonsterCountFilter MaxMinMonster() => MaxMinMonster(1, 6);
```

Dans cet exemple, le bot attaque seulement les groupes contenant entre `1` et `6` monstres.

### Exemple complet

```csharp
using System.Collections.Generic;
using Shadybot.Services.CustomAi;

public sealed class MonstreFiltre : CSharpRouteScript
{
    public override string Id   => "filter_monster";
    public override string Name => "Test Filtre Monstre";
    public override bool   Loop => true;

    public override int[] MandatoryMonster() => MandatoryMonster(61, 134);
    public override int[] ForbiddenMonster() => ForbiddenMonster(48);
    public override CSharpRouteMonsterCountFilter MaxMinMonster() => MaxMinMonster(1, 6);

    public override BuiltInCustomAiBankingProfile Banking() => Banking(
        podsPercent: 80
    );

    public override IReadOnlyList<CSharpRouteMoveStep> Move() => Route(
        Phenix(8534, 252, 2),
        Zaapi(4263, 116, 2, "tour des ordres"),
        Move("-1,-32", "right", fight: true)
    );
}
```

> **Important :** les valeurs sont les IDs des monstres, pas leurs noms. Vous pouvez les récupérer depuis vos logs/packets ou depuis les outils de debug de Shadybot.

***

## 🌿 Récolte de ressources

Pour activer la récolte, définissez les identifiants des ressources à collecter :

```csharp
public override int[] ResourceToGather() => ResourceToGather(7500, 7501, 7520);
```

Puis activez `gather: true` sur les maps concernées :

```csharp
public override IReadOnlyList<CSharpRouteMoveStep> Move() => Route(
    Move(5971, "44", gather: true),
    Move(6003, "44", gather: true)
);
```

***

## 🎯 Clics personnalisés de récolte — `HarvestClicks()`

Certaines ressources ne sont pas parfaitement centrées sur leur cellule en jeu. Dans ce cas, vous pouvez forcer Shadybot à cliquer sur des coordonnées précises pour une map et une cellule donnée.

Format :

```csharp
public override IReadOnlyList<CSharpRouteHarvestClickOverride> HarvestClicks() => HarvestClickOverrides(
    Map(mapId,
        Cell(cellId, x, y),
        Cell(cellId, x, y)
    )
);
```

Exemple :

```csharp
public override IReadOnlyList<CSharpRouteHarvestClickOverride> HarvestClicks() => HarvestClickOverrides(
    Map(5971,
        Cell(334, 32, 286),
        Cell(320, 55, 272),
        Cell(306, 81, 259),
        Cell(292, 103, 247),
        Cell(278, 127, 233),
        Cell(264, 162, 211),
        Cell(250, 195, 195),
        Cell(286, 546, 226),
        Cell(301, 574, 239),
        Cell(316, 602, 250),
        Cell(331, 625, 260),
        Cell(346, 653, 275),
        Cell(361, 676, 288),
        Cell(376, 706, 299),
        Cell(152, 377, 102),
        Cell(138, 404, 90),
        Cell(124, 432, 79),
        Cell(110, 454, 67),
        Cell(96, 481, 54),
        Cell(82, 507, 38),
        Cell(68, 534, 28)
    ),
    Map(2222,
        Cell(330, 200, 300)
    )
);
```

| Élément              | Description                                                              |
| -------------------- | ------------------------------------------------------------------------ |
| `Map(5971, ...)`     | La map où appliquer les clics personnalisés                              |
| `Cell(334, 32, 286)` | Quand une ressource est sur la cellule `334`, cliquer en `X=32`, `Y=286` |
| `x, y`               | Coordonnées du clic dans la fenêtre du client Dofus                      |

> **Important :** ces clics personnalisés s’appliquent uniquement à la **récolte**. Les déplacements normaux continuent d’utiliser le clic de cellule classique.

### Comment trouver les coordonnées X/Y ?

Ouvrez le `GameClientWindow` et regardez l’affichage des coordonnées de souris en haut de la fenêtre. Placez votre souris exactement sur le bon endroit de la ressource, puis copiez les valeurs `X` et `Y`.

***

## ⛏️ Route de mine — `Mine()`

`Mine()` sert à décrire une mine comme un réseau de maps reliées entre elles. C’est pratique pour les mines où il y a plusieurs branches et où le bot doit pouvoir revenir au point principal pour aller en banque.

Exemple :

```csharp
public override MineRouteDefinition Mine() => MineRoute(
    5953,

    Link(5953, 316, 5971, 450),

    Link(5971, 44, 6003, 463),
    Link(6003, 44, 6020, 463),

    Link(5971, 448, 6013, 44),
    Link(6013, 463, 6022, 44),

    Link(5971, 42, 6062, 450),
    Link(6062, 57, 6018, 450),

    Link(6018, 44, 6015, 463),
    Link(6015, 44, 6023, 463),

    Link(6018, 42, 6080, 450),

    IgnoreExit(6080, 98)
);
```

### Explication simple

```csharp
MineRoute(5953, ...)
```

`5953` est la map racine/principale de la mine. C’est le point de référence utilisé pour organiser le chemin et pour revenir vers la sortie/banque si nécessaire.

```csharp
Link(5953, 316, 5971, 450)
```

Cette ligne veut dire :

| Élément | Description                                                  |
| ------- | ------------------------------------------------------------ |
| `5953`  | Map de départ                                                |
| `316`   | Cellule à cliquer sur la map `5953` pour aller vers `5971`   |
| `5971`  | Map de destination                                           |
| `450`   | Cellule à cliquer sur la map `5971` pour revenir vers `5953` |

Donc chaque `Link(fromMap, fromCell, toMap, returnCell)` décrit un passage entre deux maps.

### Plusieurs branches

```csharp
Link(5971, 44, 6003, 463)
Link(6003, 44, 6020, 463)
```

Ici, le bot sait que depuis `5971`, il peut aller à `6003`, puis à `6020`, et il connaît aussi les cellules à utiliser pour revenir.

### Ignorer une sortie — `IgnoreExit()`

```csharp
IgnoreExit(6080, 98)
```

Cela indique au bot de ne pas utiliser la sortie cellule `98` sur la map `6080`.

C’est utile si :

* une sortie mène au mauvais endroit ;
* une sortie est trop dangereuse ;
* une cellule est visible mais ne doit pas être utilisée par la route ;
* le pathfinding détecte une sortie qui n’est pas bonne pour votre trajet.

### Exemple mine + récolte + clics personnalisés

```csharp
public sealed class MineBrakmar : CSharpRouteScript
{
    public override string Id => "mine_brakmar";
    public override string Name => "Mine Brakmar";
    public override bool Loop => true;

    public override BuiltInCustomAiBankingProfile Banking() => Banking(
        podsPercent: 80
    );

    public override int[] ResourceToGather() => ResourceToGather(7520, 7521, 7522);

    public override MineRouteDefinition Mine() => MineRoute(
        5953,
        Link(5953, 316, 5971, 450),
        Link(5971, 44, 6003, 463),
        Link(6003, 44, 6020, 463),
        IgnoreExit(6080, 98)
    );

    public override IReadOnlyList<CSharpRouteHarvestClickOverride> HarvestClicks() => HarvestClickOverrides(
        Map(5971,
            Cell(334, 32, 286),
            Cell(320, 55, 272)
        )
    );
}
```

Dans cet exemple :

* `Mine()` indique comment les maps de la mine sont reliées ;
* `ResourceToGather()` indique les ressources à récolter ;
* `HarvestClicks()` corrige les clics de récolte mal placés ;
* `Banking()` déclenche le retour banque quand les PODs atteignent le seuil.

***

## 📚 Annexe — Ressources disponibles

#### 🪵 Bois

| ID   | Ressource   |
| ---- | ----------- |
| 7500 | Frêne       |
| 7501 | Châtaignier |
| 7502 | Noyer       |
| 7503 | Chêne       |
| 7504 | Érable      |
| 7505 | If          |
| 7506 | Merisier    |
| 7507 | Ébène       |
| 7508 | Charme      |
| 7509 | Orme        |

#### 🌾 Céréales

| ID   | Ressource |
| ---- | --------- |
| 7511 | Blé       |
| 7512 | Houblon   |
| 7513 | Lin       |
| 7514 | Chanvre   |
| 7515 | Orge      |
| 7516 | Seigle    |
| 7517 | Avoine    |
| 7518 | Malt      |
| 7550 | Riz       |

#### ⛏️ Minerais

| ID   | Ressource |
| ---- | --------- |
| 7519 | Puits     |
| 7520 | Fer       |
| 7521 | Étain     |
| 7522 | Cuivre    |
| 7523 | Bronze    |
| 7524 | Manganèse |
| 7525 | Kobalte   |
| 7526 | Argent    |
| 7527 | Or        |
| 7528 | Bauxite   |
| 7555 | Dolomite  |
| 7556 | Silicate  |

#### 🐟 Poissons

| ID   | Ressource                 |
| ---- | ------------------------- |
| 7529 | Petits poissons (rivière) |
| 7530 | Petits poissons (mer)     |
| 7531 | Poissons (mer)            |
| 7532 | Poissons (rivière)        |
| 7537 | Gros poissons (rivière)   |
| 7538 | Gros poissons (mer)       |
| 7539 | Poissons géants (rivière) |
| 7540 | Poissons géants (mer)     |

#### 🌺 Plantes & divers

| ID   | Ressource           |
| ---- | ------------------- |
| 7533 | Trèfle à 5 feuilles |
| 7534 | Menthe Sauvage      |
| 7535 | Orchidée Freyesque  |
| 7536 | Edelweiss           |
| 7541 | Bombu               |
| 7542 | Oliviolet           |
| 7544 | Pichon              |
| 7551 | Pandouille          |
| 7552 | Bambou sacré        |
| 7553 | Bambou              |
| 7554 | Bambou sombre       |
| 7557 | Kaliptus            |
