Référence des fonctions Lua

Cette page recense les fonctions publiques disponibles dans les trajets Jitsuri actuels. Les noms sont sensibles à la casse.

Contrôle du script

printMessage(message, couleur)

Affiche une ligne dans la console du trajet.

printMessage("Départ du trajet.", "green")

delay(millisecondes)

Attend avant de poursuivre.

delay(750)

stopScript()

Arrête proprement le trajet en cours.

État du personnage

Fonction Résultat
getCurrentPos() Coordonnées actuelles.
getMapId() MapID actuel.
getCharacterLevel() Niveau du personnage.
getJobLevel(jobId) Niveau du métier demandé.
getPods() Pods utilisés.
getPodsMax() Pods maximum.
getLifePoints() Points de vie actuels.
getClass() Classe du personnage.
getTeam() Informations sur l’équipe.
getStranger() Personnages étrangers détectés sur la carte.
isFighting() true pendant un combat.
if getPods() >= getPodsMax() * 0.9 then
    printMessage("Inventaire bientôt plein.", "yellow")
end
Fonction Usage
goToCellId(cellId) Déplace le personnage vers une cellule.
changeMapByCellId(cellId) Utilise une cellule de changement de carte.
goToMapId(mapId) Calcule et suit un chemin vers un MapID.
goUseInteractive(cellId) Rejoint et utilise l’élément interactif de la cellule.
teamGoToCellId(cellId) Déplace les membres pilotés vers une cellule.
teamGoUseInteractive(cellId) Utilise l’interactif de la cellule avec l’équipe.
goToAndEnterHouse(...) Rejoint puis ouvre une maison configurée.
goAndOpenChest(...) Rejoint puis ouvre un coffre configuré.
exitDungeon() Tente de quitter le donjon courant.

Les fonctions de navigation retournent une information de réussite. Testez-la avant d’enchaîner une action sensible.

Recherche de zones intelligentes depuis le Lua

Ces fonctions permettent de découvrir les cartes sans les écrire dans le trajet. Elles nécessitent une version de Jitsuri qui expose ces nouvelles fonctions.

Fonction Description
getSmartGatheringPlan(gid) Recherche les lieux de récolte du GID de l'objet produit, dans l'index local maps.bin v3.
getSmartCombatPlan(monsterIds) Recherche les zones d'une liste de GID de monstres séparés par des virgules, via le service utilisé par le mode intelligent.

Le résultat contient success, code, message, mapIds, elementIds, maps (MapID séparés par des virgules) et mapScores (scores du catalogue). La recherche n'entraîne aucun déplacement ni combat.

Exemple fictif : remplacez le GID 0 par celui de votre propre matière première. Il ne correspond pas à un parcours prêt à lancer.

local plan = getSmartGatheringPlan(0) -- GID de ressource à renseigner
if not plan.success then
    printMessage(plan.code .. " : " .. plan.message, "red")
    stopScript()
    return
end

ELEMENTS_TO_GATHER = plan.elementIds
setGatheringGoal(0, 25, "total")
local destination = selectSmartGatheringTargetWithHistory(
    plan.maps, "", 20, plan.mapScores, ""
)

selectSmartGatheringTargetWithHistory(maps, cartesRécentes, exploration, scoresCatalogue, scoresPersonnels) et selectSmartCombatTargetWithHistory(maps, cartesRécentes, exploration, scoresCatalogue) choisissent une destination avec le moteur intelligent existant. exploration va de 0 à 100 ; les cartes récentes sont une chaîne de MapID séparés par des virgules. Une destination 0 signifie qu'aucune carte n'a pu être retenue. Le script doit alors attendre ou s'arrêter, pas lancer un combat sans filtre.

Les plans ne recopient pas automatiquement les paramètres, les stockages, les classements personnels ni l'équipe choisis dans l'interface intelligente. Les niveaux de métiers, les accès et la navigation restent à vérifier. Un échec de l'API ou un index absent renvoie un résultat d'échec ; aucune zone de remplacement arbitraire n'est sélectionnée.

Consultez Zones intelligentes et achats pour combiner ces recherches avec une politique de récolte ou d'achat adaptée à votre trajet.

PNJ et dialogues

Fonction Description
talkNpc(actorId) Ouvre le dialogue avec un acteur présent sur la carte.
talkNpcId(npcId) Cherche le PNJ par son identifiant puis ouvre le dialogue.
replyNpc(index) Sélectionne une réponse visible par son index, à partir de 0.
replyNpcAndChangeMap(index) Répond et attend le changement de carte.
leaveDialog() Ferme le dialogue courant.
if talkNpcId(925) then
    replyNpc(0)
end

Inventaire et équipement

Fonction Description
getInventoryItemCount(gid) Quantité totale du GID dans l’inventaire.
getTeamInventoryItemCount(gid) Quantité du GID dans les inventaires de toute l’équipe pilotée, meneur inclus. Renvoie nil si le comptage n’est pas disponible.
getInventoryItemByGid(gid) Retourne notamment uid, gid et quantity.
getEquippedItemAtPosition(position) Lit l’objet porté à une position.
useInventoryItem(gid, quantity) Utilise une quantité d’objets.
teamUseInventoryItem(gid, quantity) Utilise l’objet pour l’équipe pilotée.
equipItem(uid, position) Équipe l’UID à la position demandée.
unequipItem(uid) Déséquipe l’objet.
deleteItem(gid) Supprime définitivement la pile du GID.
DropItem(gid, quantity) Jette une quantité au sol.
local item = getInventoryItemByGid(12345)

if item ~= nil then
    equipItem(item.uid, 0)
end

Compter une ressource dans toute l’équipe

getTeamInventoryItemCount(gid) fonctionne depuis le trajet du meneur : les suiveurs n’ont pas besoin d’exécuter leur propre Lua. Elle additionne toutes les piles du GID dans les inventaires des membres pilotés par ce trajet, meneur inclus et sans compter deux fois un personnage. En solo, elle lit uniquement l’inventaire du personnage qui exécute le script.

-- GID fictif : remplacez-le par celui de votre ressource.
local GID_RESSOURCE = 12345
local OBJECTIF_EQUIPE = 10

function objectifEquipeAtteint()
    local total = getTeamInventoryItemCount(GID_RESSOURCE)
    if total == nil then
        printMessage("Comptage équipe indisponible : attendre puis revérifier.", "yellow")
        return nil
    end

    printMessage("Stock équipe : " .. total .. "/" .. OBJECTIF_EQUIPE, "green")
    return total >= OBJECTIF_EQUIPE
end

-- Dans votre logique de trajet, hors combat :
local atteint = objectifEquipeAtteint()
if atteint == nil then
    -- Ne pas décider de farmer davantage avec un total incomplet.
    -- Réessayer au prochain point sûr du trajet.
elseif atteint then
    -- Passer à votre prochaine étape.
else
    -- Continuer la recherche de cette ressource.
end

Le GID doit être un entier positif. Ce compteur lit le stock actuel, y compris les objets déjà possédés avant le trajet, et non le cumul des drops. Il ne consulte pas les banques, coffres ou inventaires de joueurs externes à l’équipe pilotée. Il ne compte pas les ressources contenues dans des sacs non ouverts et ne transfère aucun objet entre les personnages.

Stockage

Fonction Description
putAllItems() Dépose tout ce qui peut l’être.
putExistingItems() Dépose les objets déjà présents dans le stockage.
getAllItems() Retire tous les objets disponibles.
getExistingItems() Retire les objets déjà présents dans l’inventaire.
getMaxQuantitesByGid(gid) Retire du stockage la quantité maximale possible du GID et renvoie la réussite.
openGuildChest(number) Ouvre un coffre de guilde numéroté.
takeGuildChestItems(number, maxPods, delayMs) Retire les objets d’un coffre jusqu’au seuil de pods.
openBank() Ouvre la banque sur la carte actuelle sans déposer automatiquement l'inventaire.
isStorageOpen() Confirme que le contenu du stockage courant est chargé.
getStorageItemCount(gid) Compte le GID dans le stockage courant.
getStorageItems() Liste les piles du stockage courant.
withdrawStorageItem(gid, quantity) Retire une quantité précise.
withdrawCraftIngredients(itemGid, quantity) Retire les ingrédients manquants d'une recette.
depositStorageItem(gid, quantity) Dépose une quantité précise, ou tout le GID avec 0.
closeStorage() Ferme le stockage par requête de dialogue, sans action sur l'interface via Frida, et attend la confirmation serveur.

Pour retirer uniquement les ingrédients d'une recette, suivre une quantité récoltée ou composer un parcours banque → récolte → atelier, consultez Récolter puis fabriquer.

Un retrait qui rejoint une pile déjà présente dans l'inventaire est reconnu, même si son UID diffère de celui de la pile bancaire. Les piles retirées entièrement disparaissent également du stock local.

Les transferts distinguent SERVER_REJECTED (refus reçu) de TRANSFER_UNCONFIRMED (confirmation manquante). Dans le second cas, vérifiez l'inventaire avant de réessayer : le transfert peut avoir eu lieu. closeStorage() retourne CLOSE_UNCONFIRMED si la fermeture n'est pas confirmée, et réussit sans nouvelle action si le stockage est déjà fermé. Utilisez closeCraftWorkshop() pour les ateliers.

Hôtel de vente et artisanat

Fonction Description
openSellerHdv(cellId) Ouvre le mode vendeur de l’HDV courant.
closeSellerHdv() Ferme l’interface vendeur.
sellAllItems() Met en vente les objets compatibles selon la configuration.
buyMissingResource(gid, targetQuantity, hdvMapId, maximumKamas) Rejoint l'HDV choisi et achète le manque pour atteindre un objectif d'inventaire, au coût minimal des lots disponibles, sans surplus.
craftItem(itemGid, bankMapId, workshopMapId, specialCraft, returnBank) Prépare et exécute une fabrication.
getCraftRecipe(itemGid) Lit la recette locale et ses ingrédients.
getCraftableQuantity(itemGid) Calcule la quantité fabricable depuis l'inventaire.
getMissingCraftIngredients(itemGid, quantity, source) Liste les ingrédients manquants.
openCraftWorkshop(itemGid) Ouvre l'atelier compatible présent sur la carte.
craftFromInventory(itemGid, quantity) Fabrique depuis l'inventaire déjà préparé.
closeCraftWorkshop() Ferme l'atelier courant.

Les fonctions de craft séparées (getCraftRecipe, openCraftWorkshop, craftFromInventory, etc.) sont décrites dans le guide Récolter puis fabriquer. craftItem(...) reste disponible pour les anciens trajets.

Pour une gestion régulière de plusieurs stocks et catégories d’HDV, utilisez plutôt le bot HDV, qui ajoute les protections de prix et le routage des objets.

La quantité passée à buyMissingResource est un stock cible, pas une quantité supplémentaire. Son budget s'applique à cet appel, hors frais de trajet. Le script choisit quand acheter et gère lui-même un budget partagé entre plusieurs ressources. Voir les paramètres, résultats et exemples.

Objectifs de récolte

Fonction Description
setGatheringGoal(gid, quantity, mode) Crée un objectif total ou additional.
getGatheringGoal(gid) Lit l'état complet d'un objectif.
getGatheringGoals() Liste tous les objectifs actifs.
isGatheringGoalReached(gid) Indique si le GID a atteint son objectif.
areAllGatheringGoalsReached() Indique si tous les objectifs sont terminés.
clearGatheringGoal(gid) Retire un objectif.
clearAllGatheringGoals() Retire tous les objectifs.
createGatheringGoalsForCraft(itemGid, quantity) Crée les objectifs récoltables depuis une recette.
requestRouteRefresh() Demande au trajet de recalculer sa phase.

Les callbacks facultatifs onInventoryItemChanged, onItemGathered, onGatheringGoalProgress et onGatheringGoalReached permettent de suivre ces changements en direct.

Suspendre le suivi de l’équipe

Fonction Description
setTeamFollowingEnabled(false) Suspend les actions de suivi du trajet : les déplacements et actions collectives concernés sont exécutés uniquement par le meneur.
setTeamFollowingEnabled(true) Réactive un suivi suspendu et attend le regroupement avant de renvoyer true. Si le suivi est déjà actif, ne force pas une nouvelle vérification. En cas d’échec de la reprise, renvoie false et conserve la pause. Pour préparer un échange, utilisez teamRegroup().
isTeamFollowingEnabled() Indique si le suivi du trajet est activé.

Appelez ces commandes depuis une action custom du meneur, hors combat. En solo, elles ne déclenchent aucun déplacement de groupe. Les membres restent dans l’équipe : leurs inventaires restent consultables et aucun paramètre de déplacement enregistré n’est modifié. La pause est remise à zéro à l’arrêt et au démarrage d’un nouveau trajet.

-- Exemple générique : encadrer une phase de récolte de votre propre trajet.
local carteAttente = nil

function commencerRecolteSolo()
    if getTeamSize() <= 1 or carteAttente ~= nil then return true end
    if not setTeamFollowingEnabled(false) then return false end
    carteAttente = getMapId()
    return true
end

function terminerRecolteSolo()
    if carteAttente == nil then return true end
    -- Revenir chercher les équipiers évite de les envoyer vers une zone de récolte.
    if getMapId() ~= carteAttente and not goToMapId(carteAttente) then return false end
    if not setTeamFollowingEnabled(true) then return false end
    carteAttente = nil
    return true
end

Appeler la première fonction avant de produire les actions de récolte, puis la seconde avant les échanges ou les combats. Si une fonction renvoie false, arrêtez le trajet ou gérez l’échec explicitement ; ne poursuivez pas le combat. Pendant la pause, le trajet ne lance pas de combat automatique. Le détour bancaire individuel décrit ci-dessous reste actif si TEAM_BANK est configuré : la mule retourne ensuite sur sa carte d’attente, sans rejoindre la zone de récolte.

Banque individuelle des équipiers

Pour permettre à un équipier aux pods pleins de se vider sans arrêter le Lua du meneur, déclarez TEAM_BANK au début du script, avant le premier appel à move(). Le seuil utilisé est MAX_PODS.

-- Exemple fictif : remplacer les identifiants par ceux de votre propre trajet.
MAX_PODS = 85
TEAM_BANK = {
    mapId = 123456789,        -- carte intérieure de la banque, avec son PNJ accessible
    depositGids = { 100001, 100002 }, -- seuls ces objets peuvent être déposés
    keepGids = { 100003 },   -- objets à conserver, prioritaires sur la liste de dépôt
    -- recipeGid = 100004,   -- facultatif : donner les ingrédients au meneur AVANT la banque
    exchangeTimeoutMs = 15000, -- délai par étape d'échange (1 000 à 60 000 ms)
}

Entre deux actions, hors combat, le meneur attend pendant que seul l’équipier plein rejoint la banque, dépose les objets autorisés, ferme le dialogue et revient. Le Lua reste actif et reprend après confirmation du retour et de la baisse des pods sous le seuil. Plusieurs équipiers pleins sont traités l’un après l’autre. Si le suivi est suspendu, chacun revient sur sa carte d’attente.

Les objets équipés, favoris, de quête et ceux de keepGids sont conservés. Avec recipeGid, l’objet fabriqué est également conservé. Avant de rejoindre la banque, l’équipier donne au meneur toutes les piles transférables des ingrédients de cette recette, pas seulement la quantité d’un lot. Les autres membres ne participent pas à cet échange. Si nécessaire, seul cet équipier rejoint d’abord la carte du meneur ; le suivi suspendu n’est pas réactivé et il revient ensuite sur sa carte d’attente. Sans ingrédients à donner, l’échange est ignoré.

La réception doit être confirmée avant le départ en banque. Si le meneur manque de pods ou si l’échange échoue, aucun dépôt bancaire n’est lancé : le trajet attend sans réessayer en boucle. Vérifiez l’échange et libérez de la place chez le meneur, puis relancez le Lua. Les ingrédients utiles sont exclus des dépôts, même s’ils figurent aussi dans depositGids. Aucun dépôt global n’est effectué. Chaque équipier utilise sa propre banque : les dépôts ne deviennent pas accessibles dans l’inventaire ou la banque du meneur.

Si la configuration, le dépôt, la fermeture ou le retour échoue, un message [BANQUE EQUIPE] indique le motif. Le trajet reste en attente, sans répéter les requêtes. Pour reprendre, libérez les pods de l’équipier et ramenez-le sur la carte d’attente, banque fermée ; ou corrigez la configuration puis relancez le Lua. Un arrêt manuel annule le détour.

Cette option concerne les équipiers d’un trajet Lua, pas le mode atelier dédié. En solo, et pour le meneur lui-même, la fonction bank() conserve son rôle. Sans TEAM_BANK, les anciens trajets conservent leur gestion bancaire existante.

Échanges entre personnages

Les échanges Lua utilisent les confirmations du serveur : une fonction ne renvoie true que lorsque l'étape correspondante a réellement été confirmée. Les deux personnages doivent être connectés au même serveur, présents sur la même carte et visibles l'un pour l'autre.

Fonction Description
getCharacterId() Identifiant du personnage qui exécute le trajet.
getTeam() Membres de l'équipe du trajet : name, id (identifiant du personnage), level et breedId. Dans la liaison NLua actuelle, le résultat est un tableau C# indexé de 0 à Length - 1.
exchangeExpect(characterId, timeoutMs) Autorise temporairement une invitation provenant exactement de ce personnage.
exchangeWaitIncoming(characterId, timeoutMs) Autorise puis attend son invitation.
exchangeRequest(characterId, timeoutMs) Demande un échange et attend son ouverture.
exchangeAccept(characterId, timeoutMs) Accepte l'invitation reçue du personnage attendu.
exchangeSetKamas(quantity, timeoutMs) Définit les kamas proposés par le personnage local.
exchangeMoveItem(objectUid, quantity) Ajoute ou retire une quantité d'une pile grâce à son UID. Une quantité négative la retire de l'échange.
exchangeReady(timeoutMs) Valide l'offre locale et attend sa confirmation.
exchangeWaitResult(timeoutMs) Attend la fermeture réussie de l'échange.
exchangeCancel() Annule l'échange courant.
exchangeGetState() Retourne les participants, les kamas, les états de validation et le résultat.
exchangeTransferKamas(recipientId, quantity, reserve, timeoutMs) Depuis le donneur, réalise tout l'échange avec un autre bot Jitsuri connecté.
exchangeRequestKamas(soldeCible, reserveDonneur, timeoutMs) Depuis le receveur, choisit un autre compte Jitsuri disponible sur la carte et demande uniquement le montant manquant.
getTeamSize() Nombre de personnages pilotés par le trajet, meneur inclus ; 1 en solo.
teamRegroup() Depuis le meneur, réactive le suivi et force le regroupement sur sa carte, même si le suivi était déjà actif. Attend ensuite des personnages immobiles et des inventaires stabilisés. Renvoie success, reason et details. En solo, ne fait rien.
teamCollectItems(gids, timeoutMs) Depuis le meneur, récupère toutes les piles non équipées des GID sélectionnés auprès des suiveurs. Renvoie une table de résultat.
teamCollectAllItems(timeoutMs) Depuis le meneur, récupère les objets des inventaires des mules sans fournir de GID. Exclut les équipements portés, favoris et objets de quête. Ne transfère pas les kamas. Renvoie success, reason et completedMembers.
teamTransferItemsAndKamas(donorId, recipientId, items, kamas, timeoutMs) Depuis le meneur, pilote un échange unique entre deux membres précis : quantités par GID et kamas. items est une liste de { gid = ..., quantity = ... }. Renvoie une table de résultat.
teamCollectAllItemsAndKamas(timeoutMs, reserveKamas) Depuis le meneur, récupère les objets non protégés et les kamas de chaque mule dans un même échange par mule. reserveKamas est le montant conservé par chacune ; 0 transfère tout son solde. Renvoie une table de résultat.

Regrouper l'équipe avant un échange

Un inventaire d'équipe peut être compté à distance : un total disponible ne garantit pas que les mules soient sur la carte du meneur. Avant un transfert, notamment après une visite en banque, appelez teamRegroup() depuis le custom du meneur, hors combat et après fermeture du stockage.

local regroupement = teamRegroup()
if not regroupement.success then
    printMessage("Regroupement impossible : " .. regroupement.reason ..
        " | " .. regroupement.details, "red")
    stopScript()
    return
end
local resultat = teamCollectItems({ 12345 }, 15000) -- GID fictif
if not resultat.success then
    printMessage(resultat.reason .. " | " .. resultat.details, "red")
    stopScript()
    return
end

Le regroupement utilise la navigation habituelle de chaque mule, avec ses zaaps connus lorsque le calcul de trajet les retient. Si cette navigation échoue, une tentative à pied est conservée depuis sa position actuelle, uniquement si elle est disponible (hors combat, déplacement et chargement). Une annulation du trajet ne déclenche pas ce repli. Les logs indiquent la navigation puis, si nécessaire, le repli à pied.

La destination reste le MapID exact du meneur, y compris l'intérieur d'une banque ou d'un bâtiment accessible. L'extérieur aux mêmes coordonnées ne compte pas comme une arrivée : les mules empruntent la transition d'entrée connue du navigateur. Une porte inaccessible ou une condition d'accès non remplie ne sont pas contournées ; le regroupement doit être confirmé avant de poursuivre les échanges.

La récupération des suiveurs conserve sa fenêtre de 120 secondes sur une carte du meneur inchangée, puis attend jusqu'à 15 secondes leur immobilité et la stabilisation des inventaires. Elle ne lance aucun échange. Un échec de regroupement conserve le suivi en pause ; aucun transfert ne doit être lancé avant un résultat positif. Si les mules étaient volontairement garées ailleurs, ramenez d'abord le meneur sur leur carte d'attente.

Si un personnage est sur la carte mais que sa position reste non synchronisée, le regroupement demande au serveur un rafraîchissement de sa carte, sans le déplacer. Ce contrôle concerne aussi le meneur et s'applique aux attentes de groupe des trajets Lua et du mode intelligent. Les demandes sont limitées à trois par personnage et épisode d'attente, espacées de dix secondes après une attente initiale de deux secondes. Aucune position n'est supposée valide pour forcer la reprise.

Pour diagnostiquer un blocage persistant, conservez les lignes [TEAM POSITION STATE], [TEAM POSITION REFRESH] et [TEAM POSITION READY]. Elles précisent la carte, la présence du personnage dans les données reçues, la cellule connue, l'état du complément de carte et la source de position.

En cas de team_not_ready, le champ details des fonctions de transfert indique les personnages bloquants et leur état observé : carte différente, déplacement, combat, chargement, déconnexion, serveur inconnu/différent ou inventaire non synchronisé/en stabilisation. Un contrôle réussi n'empêche pas un changement d'état ultérieur : vérifiez aussi le résultat du transfert.

Trouver l'identifiant d'un membre de l'équipe

Un identifiant de personnage sert à cibler le receveur d'un échange. Ce n'est ni son nom de compte, ni son ProcessID, ni le GID ou l'UID d'un objet. Lancez ce petit trajet sur le meneur avec l'équipe configurée pour afficher les noms et identifiants à reporter dans les exemples suivants :

function move()
    return {{ map = tostring(getMapId()), custom = function()
        printMessage("Meneur : ID=" .. tostring(getCharacterId()), "yellow")
        local equipe = getTeam()
        -- getTeam() renvoie actuellement un tableau C#, pas une table Lua.
        for i = 0, equipe.Length - 1 do
            local membre = equipe[i]
            printMessage(membre["name"] .. " : ID=" .. tostring(membre["id"]), "yellow")
        end
        stopScript()
    end }}
end

Pour retrouver un membre par son nom de personnage exact, utilisez la même lecture dans une action custom :

local function identifiantMembre(nom)
    local equipe = getTeam()
    for i = 0, equipe.Length - 1 do
        local membre = equipe[i]
        if membre["name"] == nom then return membre["id"] end
    end
    return nil -- absent : ne pas choisir un autre destinataire par défaut
end

Hors trajet d'équipe, cette liste peut être vide : getCharacterId() reste le moyen de lire l'identifiant du personnage local. Ne parcourez pas ce tableau C# avec ipairs comme s'il s'agissait d'une table Lua.

Exemple : X donne 20 objets d'un GID et 10 000 kamas à Y

Lancez un seul trajet sur le meneur de l'équipe. X et Y peuvent être deux mules, ou l'un d'eux peut être le meneur. Les deux personnages doivent appartenir à l'équipe pilotée et être présents sur la même carte. Aucun script séparé n'est nécessaire sur le donneur ou le receveur.

Les noms X et Y et le GID ci-dessous sont fictifs : remplacez-les par ceux de vos personnages et de l'objet souhaité.

local DONNEUR = "X"
local RECEVEUR = "Y"
local OBJETS = { { gid = 12345, quantity = 20 } } -- GID fictif
local KAMAS = 10000
local tentativeEffectuee = false

local function identifiantMembre(nom)
    local equipe = getTeam()
    for i = 0, equipe.Length - 1 do
        if equipe[i]["name"] == nom then return equipe[i]["id"] end
    end
    return nil
end

function move()
    return {{ map = tostring(getMapId()), custom = function()
        if tentativeEffectuee then stopScript(); return end
        tentativeEffectuee = true
        local donneurId = identifiantMembre(DONNEUR)
        local receveurId = identifiantMembre(RECEVEUR)
        if donneurId == nil or receveurId == nil or donneurId == receveurId then
            printMessage("Donneur ou receveur absent/invalide dans l'équipe.", "red")
            stopScript(); return
        end
        local resultat = teamTransferItemsAndKamas(
            donneurId, receveurId, OBJETS, KAMAS, 15000)
        printMessage("Échange " .. DONNEUR .. " -> " .. RECEVEUR .. " : " .. resultat.reason,
            resultat.success and "green" or "red")
        stopScript()
    end }}
end

Les 20 objets et les 10 000 kamas sont proposés dans le même échange, puis validés ensemble. La quantité demandée peut être répartie sur plusieurs piles : Jitsuri retrouve les UID et ne prend que les quantités indiquées. Pour plusieurs GID, ajoutez des entrées à OBJETS :

local OBJETS = {
    { gid = 12345, quantity = 20 },
    { gid = 12346, quantity = 5 },
}

Chaque GID ne doit apparaître qu'une fois ; les GID et quantités doivent être des entiers strictement positifs. Avec KAMAS = 0, seuls les objets sont transférés. Avec OBJETS = {} et un montant positif, seuls les kamas le sont. Les équipements portés, favoris et objets de quête ne sont pas sélectionnés. Si le donneur n'a pas les quantités transférables ou les kamas nécessaires, ou si le receveur manque de pods, aucun échange n'est lancé.

Exemple : X, Y et Z donnent leurs objets et kamas à B, le meneur

Configurez l'équipe B (meneur), X, Y, Z et lancez ce trajet uniquement sur B. Il vérifie la composition de l'équipe, puis effectue un échange par mule : objets et kamas de X vers B, puis de Y vers B, puis de Z vers B. L'ordre exact des mules suit l'ordre de l'équipe, sans échanges simultanés.

local MENEUR = "B"
local DONNEURS = { "X", "Y", "Z" }
local RESERVE_KAMAS_PAR_MULE = 0 -- 0 = tout ; 50000 = garder 50 000 par mule
local tentativeEffectuee = false

function move()
    return {{ map = tostring(getMapId()), custom = function()
        if tentativeEffectuee then stopScript(); return end
        tentativeEffectuee = true
        local ids = {}
        local equipe = getTeam()
        for i = 0, equipe.Length - 1 do
            local membre = equipe[i]
            ids[membre["name"]] = membre["id"]
            printMessage(membre["name"] .. " : ID=" .. tostring(membre["id"]), "yellow")
        end
        local valide = getTeamSize() == 4 and ids[MENEUR] == getCharacterId()
        for _, nom in ipairs(DONNEURS) do
            if ids[nom] == nil then valide = false end
        end
        if not valide then
            printMessage("Lancer sur B avec exactement B, X, Y et Z dans l'équipe.", "red")
            stopScript(); return
        end
        local resultat = teamCollectAllItemsAndKamas(15000, RESERVE_KAMAS_PAR_MULE)
        printMessage("Objets et kamas vers B : " .. resultat.reason ..
            " | Mules terminées : " .. resultat.completedMembers,
            resultat.success and "green" or "red")
        stopScript()
    end }}
end

« Tous les objets » conserve les protections : équipements portés, favoris et objets de quête restent sur les mules. Les autres objets, y compris les équipements non portés et non favoris, sont concernés. Si une mule possède moins que la réserve, elle conserve tout son solde ; ses objets peuvent quand même être transférés. Une mule n'ayant que des kamas peut aussi être traitée ; une mule n'ayant rien à donner est ignorée.

Le meneur doit pouvoir recevoir l'ensemble des objets avant le premier échange. La fonction ne lance aucun dépôt bancaire pour libérer de la place. En solo, la collecte ne fait rien. Elle ne cible jamais un personnage extérieur à l'équipe du trajet.

Regrouper les ingrédients avant un craft

Appelez cette fonction depuis une action custom du trajet du meneur, hors combat et avant d’ouvrir une banque ou un atelier. Les personnages doivent être sur la même carte, visibles et immobiles ; la fonction attend brièvement les retardataires mais ne calcule pas de trajet pour les rejoindre. Les suiveurs n’ont pas besoin d’exécuter leur propre Lua.

-- GID fictifs, à remplacer par les ingrédients de votre recette.
local INGREDIENTS = { 12345, 12346 }

function preparerLesIngredients()
    if getTeamSize() > 1 then
        local resultat = teamCollectItems(INGREDIENTS, 15000)
        if not resultat.success then
            printMessage("Collecte interrompue : " .. resultat.reason ..
                " / équipiers terminés : " .. resultat.completedMembers, "red")
            return false -- ne pas continuer vers le craft avec un bilan incomplet
        end
    end
    -- Maintenant seulement : lire getInventoryItemCount pour chaque ingrédient,
    -- vérifier votre banque si nécessaire, puis calculer ce qu’il reste à obtenir.
    return true
end

La collecte prend toutes les quantités disponibles des GID choisis, pas seulement le manque de la recette. Les kamas, équipements portés et autres GID ne sont pas transférés. Chaque mule termine son échange avant la suivante. La fonction vérifie les offres des deux côtés, le succès serveur et les quantités reçues ; elle envoie ensuite une fermeture de dialogue unique sur chaque personnage pour nettoyer les fenêtres résiduelles. En solo, même un appel direct renvoie immédiatement { success = true, reason = "solo", completedMembers = 0 }, sans échange ni attente.

Le résultat contient success, reason et completedMembers (nombre de mules dont le transfert et le nettoyage ont terminé). reason vaut notamment ok, nothing_to_transfer, team_not_ready, insufficient_pods, unknown_item_weight, offer_not_confirmed, exchange_refused, inventory_not_confirmed ou cleanup_failed. Le délai, en millisecondes, est borné de 1 à 60 secondes par étape, pas pour l’équipe entière. L’arrêt du trajet interrompt les attentes.

Vider les inventaires des mules vers le meneur

teamCollectAllItems(15000) détecte automatiquement les piles présentes dans les inventaires des suiveurs. Lancez le trajet sur le meneur avec son équipe configurée. Tous les personnages doivent être connectés, sur le même serveur, sur la même carte, visibles et hors combat. La fonction ne les déplace pas.

-- Transfert unique : lancer sur le meneur avec l'équipe configurée.
local tentativeEffectuee = false

function move()
    return {{ map = tostring(getMapId()), custom = function()
        if tentativeEffectuee then stopScript(); return end
        tentativeEffectuee = true
        local resultat = teamCollectAllItems(15000)
        printMessage("Transfert : " .. resultat.reason ..
            " | Mules terminées : " .. resultat.completedMembers,
            resultat.success and "green" or "red")
        stopScript()
    end }}
end

Les kamas, équipements portés, favoris et objets de quête restent sur les mules. Les autres objets, y compris les équipements non portés et non favoris, sont concernés. Le meneur doit disposer de suffisamment de pods pour l'ensemble des objets sélectionnés : la vérification précède le premier échange. Si le poids d'un objet est inconnu, aucun transfert n'est lancé.

Les mêmes confirmations, délais et règles de transfert partiel que teamCollectItems s'appliquent. En solo, l'appel ne fait rien. Aucun dépôt, destruction, découpage selon les pods ou nouvel essai automatique n'est effectué. Un objet non échangeable peut faire échouer le transfert : vérifiez le résultat avant de relancer. Marquez les objets à conserver comme favoris.

Sur une version ne proposant pas encore teamCollectAllItems, utilisez teamCollectItems({ gid1, gid2 }, 15000) avec une liste de GID connus. getTeamInventoryItemCount(gid) compte un type d'objet ; il ne permet pas d'énumérer les GID ni les UID de tous les inventaires. Une liste vide passée à teamCollectItems reste invalide et ne signifie jamais « tout transférer ».

Transfert automatique entre deux bots Jitsuri

Le donneur peut piloter les deux côtés sans second script. La réserve empêche son solde de descendre sous le montant choisi.

local RECEVEUR_ID = 4205379938
local MONTANT = 12345
local RESERVE_DONNEUR = 50000

if not exchangeTransferKamas(RECEVEUR_ID, MONTANT, RESERVE_DONNEUR, 15000) then
    printMessage("Échange de kamas annulé ou refusé.", "red")
end

Le receveur peut aussi demander à atteindre un solde. Jitsuri recherche alors le compte distinct possédant le plus de kamas sur la même carte et le même serveur, sans entamer sa réserve.

exchangeRequestKamas(100000, 50000, 15000)

Échange piloté étape par étape

Sur le receveur :

local DONNEUR_ID = 57757270370

if exchangeWaitIncoming(DONNEUR_ID, 15000)
    and exchangeAccept(DONNEUR_ID, 15000)
    and exchangeReady(15000) then
    exchangeWaitResult(15000)
end

Sur le donneur :

local RECEVEUR_ID = 4205379938

if exchangeRequest(RECEVEUR_ID, 15000)
    and exchangeSetKamas(12345, 10000)
    and exchangeReady(15000) then
    exchangeWaitResult(15000)
end

Caractéristiques

Les valeurs sont passées dans l’ordre : agilité, force, vitalité, chance, intelligence et sagesse.

upgradeCharacterStatsBatch(0, 0, 100, 0, 0, 0)
upgradeCharacterStatsBatchByName("Pandawa", 0, 0, 100, 0, 0, 0)

Le mode Starter n’appelle pas ces fonctions automatiquement : la répartition des caractéristiques reste votre choix.

Combat Lua

Si le script déclare fight(), Jitsuri l’appelle pendant les tours de combat. Sans cette fonction, les sorts configurés dans l’interface restent la méthode habituelle.

Lire le combat

Fonction Description
getCharacterTurn() Personnage actuellement jouable, ou nil.
getAttackers() Combattants du côté allié.
getDefenders() Combattants du côté ennemi.
getTeamMemberReachableCells(name) Cellules atteignables par le membre.

Les combattants exposent notamment actorId, gid, cellId, isAlive, isSummon, teamId, lifePct et leurs caractéristiques disponibles.

Déplacer et lancer un sort

Fonction Description
teamMemberMoveToCellId(name, cellId) Déplace le membre courant.
teamMemberCastSpellOnCellId(name, spellId, cellId) Lance un sort sur une cellule.
getTeamMemberSpellPossibleCells(name, spellId) Cellules de lancement possibles.
getTeamMemberSpellPossibleCellsOnCellId(name, spellId, cellId) Cellules permettant de viser la cellule demandée.
getTeamMemberSpellZoneOnCellId(name, spellId, cellId) Zone couverte par le sort sur cette cellule.
teamMemberFinishTurn(name) Termine le tour du membre.
local ATTACK_SPELL = 1234

function fight()
    local character = getCharacterTurn()

    if character == nil then
        return
    end

    local enemies = getDefenders()

    for _, enemy in ipairs(enemies) do
        if enemy.isAlive and teamMemberCastSpellOnCellId(
            character.name,
            ATTACK_SPELL,
            enemy.cellId
        ) then
            break
        end
    end

    teamMemberFinishTurn(character.name)
end

Bonnes pratiques

  • Vérifiez toujours les valeurs nil et les résultats des actions.
  • Évitez les boucles sans limite et ajoutez un délai lorsque vous attendez un état serveur.
  • Utilisez les MapID pour les intérieurs et les étages.
  • Conservez les mots de passe et informations privées hors des scripts partagés.
  • Testez un trajet avec un personnage et un inventaire adaptés avant de le déployer à une équipe.