> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dotouch-emu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Premiers pas avec les scripts

> Guide pour débuter avec les scripts Lua dans dotouch-emu : structure, exemples et bonnes pratiques.

## Introduction

Les scripts Lua sont au cœur de l'automatisation dans dotouch-emu. Avec plus de **310 méthodes** réparties dans une dizaine de catégories, vous pouvez automatiser pratiquement tous les aspects du jeu : déplacement, combat, récolte, quêtes, échanges, craft, achat/vente à l'hôtel des ventes, et bien plus encore.

Ce guide vous accompagne de la découverte du langage Lua jusqu'à l'écriture de vos premiers scripts fonctionnels. Que vous soyez débutant en programmation ou développeur expérimenté, vous trouverez ici les bases pour commencer efficacement.

## Langage Lua

Lua est un langage de script léger, rapide et facile à apprendre. Voici les concepts fondamentaux dont vous aurez besoin.

<Accordion title="Variables et types">
  ```lua theme={null}
  -- Variables locales
  local nom = "MonPersonnage"
  local niveau = 150
  local estVivant = true
  local vie = 85.5

  -- Tables (listes et dictionnaires)
  local sorts = {201, 202, 203}
  local config = {mapWait = 3000, potionId = 548}
  ```
</Accordion>

<Accordion title="Conditions">
  ```lua theme={null}
  -- Condition simple
  if character:lifePointsP() < 50 then
    inventory:useItem(potionId)
  end

  -- Condition avec alternatives
  if character:level() >= 100 then
    print("Haut niveau")
  elseif character:level() >= 50 then
    print("Niveau intermédiaire")
  else
    print("Bas niveau")
  end

  -- Opérateurs : ==, ~= (différent), <, >, <=, >=, and, or, not
  ```
</Accordion>

<Accordion title="Boucles">
  ```lua theme={null}
  -- Boucle for numérique
  for i = 1, 10 do
    print(i)
  end

  -- Boucle for sur une table
  local items = {548, 549, 550}
  for _, itemId in ipairs(items) do
    inventory:useItem(itemId)
  end

  -- Boucle while
  while map:currentMapId() ~= 123456 do
    map:changeMap("right")
    global:delay(1000)
  end
  ```
</Accordion>

<Accordion title="Fonctions">
  ```lua theme={null}
  -- Exemple réel — extrait de hiden.lua
  -- ================================================

  -- 1. Fonction simple : changer de script selon le niveau
  function checkLevel()
      if character:level() >= 41 then
          local path = global:getCurrentDirectory() .. "farm_tofus.lua"
          if global:fileExists(path) then
              global:loadAndStart(path)       -- passer au script suivant
          else
              global:printError("Fichier introuvable : farm_tofus.lua")
              global:restartScript(true)      -- redémarrer en cas d'erreur
          end
      end
  end

  -- 2. Fonction avancée : équiper des objets selon la classe
  local itemsByClass = {
      [8] = { { gid = 18969, position = 29 }, { gid = 18939, position = 28 } }, -- Iop
      [9] = { { gid = 18987, position = 29 }, { gid = 18957, position = 28 } }, -- Cra
  }

  function equipItems()
      local breed = character:breed()
      local items = itemsByClass[breed] or {}
      for _, item in ipairs(items) do
          local pos = inventory:itemPosition(item.gid)
          if pos == 63 then                             -- 63 = dans l'inventaire
              inventory:equipItem(item.gid, item.position)
              global:delay(1500)
              global:printSuccess("Équipé GID " .. item.gid .. " → pos " .. item.position)
          elseif pos == item.position then
              global:printMessage("Déjà équipé à la position " .. item.position)
          end
          global:delay(500)
      end
  end

  -- 3. Fonction PNJ : interaction avec un PNJ (extrait de hiden.lua)
  function albueraReturn()
      if inventory:itemCount(14721) == 0 then
          npc:npc(1503, 3)
          global:delay(200)
          npc:reply(41327)
          global:delay(200)
          npc:reply(41326)
          global:delay(200)
          global:leaveDialog()
      end
      npc:npc(3916, 3)
      global:delay(300)
      npc:reply(-1)
      global:delay(200)
  end

  -- Appels
  checkLevel()
  equipItems()
  albueraReturn()
  ```
</Accordion>

## Structure d'un script

Un script dotouch-emu suit une structure logique simple. Voici un exemple annoté illustrant les principaux éléments.

<CodeGroup>
  ```lua Script de récolte basique theme={null}
  -- ==================================
  -- Script de récolte basique
  -- ==================================

  -- Configuration
  local POTION_ID = 548          -- Identifiant de la potion
  local SEUIL_VIE = 50           -- Pourcentage de vie minimum
  local DELAI_CARTE = 1500       -- Délai entre les changements de carte

  -- Vérifier et restaurer la santé
  if character:lifePointsP() < SEUIL_VIE then
    inventory:useItem(POTION_ID)
    global:delay(500)
  end

  -- Se déplacer vers la droite
  map:changeMap("right")
  global:delay(DELAI_CARTE)

  -- Récolter toutes les ressources de la carte
  map:gather()
  ```

  ```lua Script avec boucle de récolte theme={null}
  -- ==================================
  -- Boucle de récolte avec retour banque
  -- ==================================

  local PODS_MAX = 90  -- Pourcentage de poids maximum

  -- Vérifier le poids
  if inventory:podsP() >= PODS_MAX then
    -- Aller à la banque
    map:changeMap("top")
    global:delay(1000)
    npc:openBank()
    global:delay(500)
    inventory:putAllItems()
    npc:closeDialog()
  else
    -- Continuer la récolte
    map:gather()
    global:delay(500)
    map:changeMap("right")
  end
  ```
</CodeGroup>

<Note>
  La fonction `delay(ms)` est indispensable entre les actions. Elle attend le nombre de millisecondes spécifié et simule le temps de réaction d'un joueur humain. Ne chaînez jamais des actions sans délai.
</Note>

## Catégories de méthodes

dotouch-emu expose plus de 310 méthodes organisées en catégories. Chaque catégorie correspond à un aspect du jeu.

<CardGroup cols={3}>
  <Card title="Navigation" icon="map" href="/methodes/navigation">
    **35 méthodes** pour le déplacement, les changements de carte, la récolte, la détection de monstres et la navigation sur la carte du monde.
  </Card>

  <Card title="Combat" icon="swords" href="/methodes/combat">
    **50+ méthodes** pour gérer les combats : lancer des sorts, se déplacer, cibler des ennemis, gérer les placements et les invocations.
  </Card>

  <Card title="Personnage" icon="user" href="/methodes/personnage">
    **20+ méthodes** pour accéder aux informations du personnage : santé, niveau, statistiques, position, métiers et état actuel.
  </Card>

  <Card title="Inventaire" icon="backpack" href="/methodes/economie/inventaire">
    **29 méthodes** pour gérer l'inventaire : utiliser, équiper, déplacer et supprimer des objets, vérifier le poids et les quantités.
  </Card>

  <Card title="Global" icon="globe" href="/methodes/systeme/global">
    **50+ méthodes utilitaires** : délais, mémoire persistante, journalisation, gestion du temps, conditions avancées et variables globales.
  </Card>

  <Card title="PNJ" icon="comments" href="/methodes/communication/npc">
    Interagir avec les PNJ : ouvrir des dialogues, répondre, ouvrir la banque, acheter et vendre.
  </Card>

  <Card title="Hôtel des ventes" icon="shop" href="/methodes/economie/vente">
    Acheter et vendre des objets aux hôtels des ventes, gérer les prix et les quantités.
  </Card>

  <Card title="Quêtes" icon="scroll" href="/methodes/activites/quete">
    Suivre et accomplir des quêtes, vérifier les objectifs et les conditions de progression.
  </Card>

  <Card title="Chat" icon="message" href="/methodes/communication/chat">
    Envoyer et recevoir des messages sur les différents canaux de chat du jeu.
  </Card>

  <Card title="Craft" icon="hammer" href="/methodes/activites/craft">
    Automatiser les recettes de craft : ouvrir un atelier, sélectionner une recette et fabriquer en boucle.
  </Card>

  <Card title="Monture" icon="horse" href="/methodes/activites/monture">
    Gérer les montures et les familiers : monter, démonter, nourrir et accéder aux informations.
  </Card>

  <Card title="Mode développeur" icon="code" href="/methodes/systeme/developpeur">
    **30+ méthodes avancées** pour le débogage, l'inspection des paquets réseau et le développement de scripts complexes.
  </Card>
</CardGroup>

## Patterns courants

Voici les patterns de programmation que vous utiliserez le plus souvent dans vos scripts.

### Vérifier avant d'agir

Le pattern le plus basique : vérifier une condition avant d'effectuer une action.

```lua theme={null}
-- Se soigner si nécessaire
if character:lifePointsP() < 50 then
  inventory:useItem(548)
end

-- Changer de carte uniquement s'il n'y a pas de ressources
if not map:hasGatherableResource() then
  map:changeMap("right")
end
```

### Itérer sur des objets

Parcourir une liste d'objets pour effectuer une action sur chacun.

```lua theme={null}
-- Déposer une liste d'objets à la banque
local objets = {289, 401, 548, 1782}
for _, objetId in ipairs(objets) do
  if inventory:itemCount(objetId) > 0 then
    inventory:putItem(objetId, inventory:itemCount(objetId))
    global:delay(300)
  end
end
```

### Persistance entre les exécutions

Sauvegarder et lire des données entre les exécutions de script grâce aux fonctions de fichier.

```lua theme={null}
-- Sauvegarder un compteur dans un fichier
local dir = global:getCurrentScriptDirectory()
local file = dir .. "\\compteur.txt"

local compteur = 0
if global:fileExists(file) then
    -- lire la valeur précédente (le fichier contient uniquement le nombre)
    local f = io.open(file, "r")
    if f then
        compteur = tonumber(f:read("*n")) or 0
        f:close()
    end
end

compteur = compteur + 1
global:writeFile(file, tostring(compteur))

if compteur >= 100 then
    global:printSuccess("100 récoltes atteintes !")
    global:writeFile(file, "0")   -- réinitialiser
end
```

### Délais variables

Ajouter de l'aléatoire aux délais pour simuler un comportement humain.

```lua theme={null}
-- Délai aléatoire entre 800 et 2000 ms
global:delay(math.random(800, 2000))

-- Après un changement de carte
map:changeMap("bottom")
global:delay(math.random(1000, 3000))
```

## Script de récolte complet

Voici un exemple de script de récolte complet avec gestion du poids, de la santé et retour automatique à la banque.

<Accordion title="Voir le script complet">
  ```lua theme={null}
  -- =========================================================
  -- Script de récolte complet — style hiden.lua / farm_tofus
  -- Déplacement en circuit + retour banque automatique
  -- =========================================================

  -- Configuration
  local POTION_ID   = 548    -- Identifiant de la potion
  local SEUIL_VIE   = 40     -- % de santé minimum avant de se soigner
  local MAX_FIGHTS  = 19     -- nombre max de combats par carte avant forcer le changement

  -- Circuit de cartes à suivre
  local circuit = {
      { map = "145752576", fight = true,  path = "top"    },
      { map = "145752833", fight = true,  path = "bottom" },
      { map = "145752064", fight = false, path = "right"  },
  }

  -- Marquer toutes les cartes comme non visitées
  for _, c in ipairs(circuit) do c.done = false end

  local fightCounter = 0

  -- Trouver la prochaine carte à visiter
  local function nextMap()
      for _, c in ipairs(circuit) do
          if map:onMap(c.map) and not c.done then
              c.done = true
              return c
          end
      end
      -- Circuit complet : réinitialiser
      for _, c in ipairs(circuit) do c.done = false end
      return nextMap()
  end

  -- Aller à la banque via PNJ
  local function goBank()
      npc:npcBank()
      global:delay(500)
      exchange:putAllItems()
      global:delay(500)
      global:leaveDialog()
      global:printSuccess("Banque : inventaire vidé")
  end

  -- Se soigner si nécessaire
  local function healIfNeeded()
      if character:lifePointsP() < SEUIL_VIE then
          if inventory:itemCount(POTION_ID) > 0 then
              inventory:useItem(POTION_ID)
              global:delay(global:random(400, 800))
          end
      end
  end

  -- === Point d'entrée appelé par le bot à chaque tour ===
  function move()
      healIfNeeded()

      -- Après un combat : vérifier si on reste sur cette carte
      if global:afterFight() then
          fightCounter = fightCounter + 1
          if fightCounter < MAX_FIGHTS then
              return  -- rester sur la carte
          end
          fightCounter = 0  -- assez de combats ici, continuer le circuit
      end

      -- Vérifier le poids (inventaire plein → banque)
      if inventory:podsPercent() >= 85 then
          goBank()
          return
      end

      -- Changer de carte selon le circuit
      local next = nextMap()
      if next then
          global:printMessage("→ Carte " .. next.map .. " | chemin : " .. (next.path or "?"))
          return { { map = next.map, path = next.path, fight = next.fight, done = false } }
      end
  end
  ```
</Accordion>

## Script de combat complet

Voici un exemple de script de combat avec gestion des sorts et des déplacements.

<Accordion title="Voir le script de combat">
  ```lua theme={null}
  -- ================================================
  -- Script de combat — utilise l'API fightAction
  -- Approche : frapper l'ennemi le plus proche
  -- ================================================

  -- Identifiants des sorts (à ajuster selon votre classe)
  local SORT_PRINCIPAL = 8139   -- sort d'attaque principal
  local SORT_BOOST     = 201    -- sort de buff (optionnel)

  -- Cette fonction est appelée automatiquement par le bot à chaque tour
  function playTurn()

      -- 1. Récupérer tous les combattants
      local entities = fightAction:getAllEntities()

      -- 2. Trouver l'ennemi avec le moins de PV
      local target = nil
      local minHP = math.huge
      for _, e in ipairs(entities) do
          if e["Team"] == false and e["LifePoints"] < minHP then
              minHP  = e["LifePoints"]
              target = e
          end
      end

      if target == nil then
          fightDebug:print("Aucun ennemi trouvé")
          return
      end

      local myCell    = fightCharacter:getCellId()
      local enemyCell = target["CellId"]

      -- 3. Se rapprocher si nécessaire
      if fightAction:getDistance(myCell, enemyCell) > 3 then
          fightAction:moveToWardCell(enemyCell)
          myCell = fightCharacter:getCellId()   -- position mise à jour
      end

      -- 4. Vérifier la portée et lancer le sort
      local err = fightAction:canCastSpellOnCell(myCell, SORT_PRINCIPAL, enemyCell)
      if err == 0 then
          fightAction:castSpellOnCell(SORT_PRINCIPAL, enemyCell)
      else
          fightDebug:print("Impossible de lancer le sort, code d'erreur : " .. err)
      end
  end

  -- Appel du tour (fightBasic:playTurn() appelle playTurn())
  fightBasic:playTurn()
  ```
</Accordion>

## Conseils pour écrire de bons scripts

<Tip>
  **Commencez simplement.** Écrivez d'abord un script minimal qui fonctionne, puis ajoutez des fonctionnalités progressivement. Déboguer un script de 20 lignes est bien plus facile qu'un script de 200 lignes.
</Tip>

<Steps>
  <Step title="Utiliser des variables de configuration">
    Regroupez toutes les valeurs modifiables (identifiants d'objets, seuils, délais) en haut du script. Cela facilite les ajustements sans avoir à chercher dans le code.
  </Step>

  <Step title="Toujours ajouter des délais">
    Ne déclenchez jamais deux actions consécutives sans un `delay()` entre elles. Utilisez `math.random()` pour varier les délais et simuler un comportement humain.
  </Step>

  <Step title="Gérer les cas d'erreur">
    Vérifiez toujours qu'une action est possible avant de l'exécuter. Par exemple, vérifiez qu'un objet existe dans l'inventaire avant de l'utiliser.
  </Step>

  <Step title="Tester étape par étape">
    Testez chaque partie de votre script individuellement avant de tout assembler. Utilisez `print()` pour afficher des informations de débogage.
  </Step>

  <Step title="Consulter la documentation de l'API">
    Chaque méthode est documentée avec ses paramètres, ses valeurs de retour et des exemples. Consultez les pages API pour découvrir toutes les possibilités.
  </Step>
</Steps>

<Warning>
  N'oubliez pas les bonnes pratiques d'[anti-détection](/guide/anti-detection). Un script techniquement parfait qui se comporte de manière suspecte entraînera quand même un bannissement.
</Warning>
