Aller au contenu

fm — Forgemagie

API forgemagie MoonBot Lua : améliorer un item, runes, scripts d'FM automatique.

20 fonctions dans ce namespace.

Index


Référence

Constantes slots

fm.BOTTES, fm.CEINTURE, fm.CAPE, fm.CHAPEAU, fm.SAC, fm.ANNEAU, fm.AMULETTE

Skill IDs des ateliers FM (163..169). Le module fm concerne les ateliers solo. Pour la FM cooperative (artisan/client), utiliser craft.forgemagicAction et craft.getState().cooperative_fm ; voir docs/forgemagie-cooperative.md.


fm.isOpen

fm.isOpen()

returns boolean

True si un atelier FM est ouvert (exchange type 3 + skill 163..169).


fm.currentSlot / currentSlotName

fm.currentSlot() / fm.currentSlotName()

returns number | string | nil

Skill id ou nom ("bottes", "amulette"...) de l'atelier courant.


fm.open

fm.open(slot: number | string)

returns boolean

Ouvre un atelier FM sur la map courante. slot = fm.BOTTES..fm.AMULETTE ou "bottes".."amulette". Attend ECK3 (15s max).


fm.leave

fm.leave()

returns boolean

Ferme l'atelier (envoie EV).


fm.canFuse

fm.canFuse()

returns boolean

True si un objet ET une rune (ou potion de forgemagie) sont posés dans l'atelier : la condition du client officiel pour fusionner. Devient false après la fusion qui consomme la dernière rune posée : le serveur ne remet alors pas l'objet dans l'atelier.


fm.putItemByUid / putRuneByUid / removeItemByUid

fm.putItemByUid(uid) / fm.putRuneByUid(uid, qty?) / fm.removeItemByUid(uid, qty?)

returns boolean

Place/retire un objet ou une rune par uid (EMO+/EMO- brut). Sur Rétro, poser la pile entière de runes, comme le client officiel : fm.putRuneByUid(rune.uid, rune.quantity). Chaque fusion n'en consomme qu'une, puis le serveur remet lui-même l'objet et le reste de la pile dans l'atelier. L'objet change d'uid à chaque fusion : relire l'inventaire plutôt que réutiliser un uid gardé d'avant la fusion.


fm.putItem / removeItem

fm.putItem(templateId, qty?) / fm.removeItem(templateId, qty?)

returns boolean

Place/retire par template id (resout l'uid via l'inventaire).


fm.putRunesForStat

fm.putRunesForStat(statName: string, count: number)

returns number

Auto-selection : trouve la meilleure rune dispo ciblant statName et en place count. Ex: fm.putRunesForStat("vitalite", 50). Retourne le nombre pose (0 si aucune rune trouvee). Chaque fusion consomme une des runes posées : avec count = 1, seule la première fusion passe (voir fm.fuseOnce).


fm.clearSlots

fm.clearSlots()

returns boolean

Retire tous les items et runes de l'atelier.


fm.fuseOnce / fuseAll

fm.fuseOnce() / fm.fuseAll(n?)

returns boolean

fuseOnce lance une fusion (EK) : une rune posée est consommée et le serveur recrée l'objet avec un nouvel uid. Comme le client officiel, elle renvoie false sans rien envoyer si l'atelier n'a pas à la fois un objet et une rune (« Fusion non envoyee » dans les logs) : c'est le cas après la fusion qui consomme la dernière rune posée, le serveur ne remettant alors pas l'objet. fuseAll = « Fusionner tout » du client : une fusion puis une boucle côté serveur pour les n-1 suivantes (n = runes posées par défaut, pas de boucle en dessous de 3). Voir l'exemple « monter un métier de forgemagie ».


fm.waitForResult

fm.waitForResult(timeoutMs?: number)

returns table | nil

Attend le résultat d'une fusion. Retourne {successes, total, failures, success, impossible} ou nil si timeout (30s par defaut). success = fusion réussie (EcK) ; impossible = fusion refusée par le serveur (EcEI, « Cette recette ne donne rien » : objet ou rune absent, rien consommé, pas d'XP, atelier vidé ; « Fusion impossible » dans les logs). Un échec normal (EcEF) consomme la rune. Sans success/impossible (worker ancien), vérifier que inventory.countItem(runeId) a baissé.


fm.lastBatch / successRate

fm.lastBatch() / fm.successRate()

returns table / number

lastBatch()→{successes, total, failures}. successRate()→% (0..100) de la derniere batch.


fm.itemEffects

fm.itemEffects()

returns table

Parse le jet actuel de l'objet pose (la pièce qui n'est ni une rune ni une potion de forgemagie, même si une rune seule est posée avant elle). Chaque entree: {id, label, value, max}. Labels normalises: "vitalite", "force", "intelligence", "sagesse", "chance", "agilite", "pa", "pm", "portee", "cc", "dommages", "prospection", "soins", "invocations", "res_per_feu", etc.


fm.itemStat

fm.itemStat(name: string)

returns number

Valeur actuelle d'un stat precis sur l'objet pose. Accepte les alias : "vitalite"/"vita"/"vi", "force"/"fo", "intelligence"/"int"/"ine", etc. Retourne 0 si le stat est absent.


fm.slotRunes

fm.slotRunes()

returns table

Runes actuellement dans l'atelier. Chaque entree: {uid, name, quantity, stat?, perFuse?}.


fm.availableRunes

fm.availableRunes(statFilter?: string)

returns table

Runes disponibles dans l'inventaire, filtrables par stat cible. Entree: {uid, templateId, name, quantity, stat?, perFuse?}.


fm.runeStat

fm.runeStat(name: string)

returns table | nil

Decode une rune par son nom. Ex: fm.runeStat("Rune Pa Vi") → {stat="vitalite", perFuse=1}. Retourne nil si inconnue.


fm.fuseUntil

fm.fuseUntil(stat: string, target: number, maxAttempts?: number)

returns table

Fusionne en boucle jusqu'a ce qu'un stat atteigne target (ou manque de runes). Retourne {reached: bool, attempts: number, final: number}. maxAttempts par defaut = 500. Poser avant l'objet et la pile entière de runes : la boucle s'arrête dès que l'atelier n'a plus d'objet ou de rune.


Exemple — monter un métier de forgemagie (Rétro)

-- Atelier ouvert (fm.open), objet dans le sac, runes dans l'inventaire.
local OBJET, RUNE = 2411, 1519 -- Coiffe du Bouftou, Rune Fo
local function dansAtelier(templateId)
  for _, it in ipairs(exchange.myItems()) do
    if it.id == templateId then return it.quantity end
  end
  return 0
end
local function objetDuSac(templateId)
  for _, it in ipairs(inventory.list()) do
    if it.templateId == templateId and it.position < 0 then return it end
  end
end
for _ = 1, 50 do
  if dansAtelier(OBJET) == 0 then
    local objet = objetDuSac(OBJET)
    if not objet then break end
    fm.putItemByUid(objet.uid) -- nouvel uid après chaque fusion
  end
  local rune = inventory.findByTemplate(RUNE)
  if not rune then break end
  if dansAtelier(RUNE) == 0 then
    fm.putRuneByUid(rune.uid, rune.quantity) -- toute la pile
  end
  local avant = inventory.countItem(RUNE)
  fm.fuseOnce()
  fm.waitForResult(10000)
  global.delay(global.random(350, 700))
  if inventory.countItem(RUNE) >= avant then
    global.printError("Fusion refusée : aucune rune consommée")
    break
  end
end

50 fusions, une rune consommée à chaque fois, comme dans le client officiel : la pile entière est posée une fois, puis le serveur remet lui-même l'objet (nouvel uid) et le reste de la pile après chaque fusion. Pour alterner deux runes, retirer la pile posée avec fm.removeItemByUid(uid, quantite) puis poser l'autre. L'XP de métier ne vient que des fusions réussies. Un « Craft echoue » répété sans rune consommée ni XP est un refus du serveur (objet ou rune absent de l'atelier), pas un objet « saturé » : l'exemple s'arrête dans ce cas.