aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Metin2

Système switchbot Metin2 : changement automatique de bonus

Un système switchbot Metin2 est un mécanisme qui relance les bonus (attributs) d'un objet automatiquement jusqu'à obtenir la combinaison voulue, au lieu de le faire clic par clic. Le joueur définit une cible — par exemple « coup critique 15 % et dégâts moyens 10 % » — et le système dépense des objets de changement, relance les attributs encore et encore, puis s'arrête dès qu'une correspondance est trouvée. Dans ce guide, je montre comment construire un tel système côté serveur, avec le moteur de quêtes Lua, de manière sûre et équilibrée. Le but n'est pas de copier du code tout prêt, mais de saisir la logique pour l'adapter à ton propre serveur.

Qu'automatise exactement un switchbot ?

Dans Metin2, les bonus d'un objet sont stockés sous forme d'attributs : chaque ligne a un type (chance de critique, coup pénétrant, dégâts contre les monstres…) et une valeur. La méthode classique consiste à utiliser un objet de « changement de bonus », à voir toutes les lignes relancées au hasard, et à recommencer si le résultat ne plaît pas. C'est une boucle fastidieuse qui peut demander des centaines de clics.

Un switchbot déplace cette boucle vers le serveur : le joueur choisit une cible une seule fois, et à chaque étape le système dépense un objet de changement, relance les attributs et compare le résultat à la cible. Les avantages sont clairs :

  • Équitable et vérifiable — l'aléatoire et le coût sont calculés sur le serveur, sans jamais faire confiance au client.
  • À l'épreuve des abus — le stock d'objets, la limite de tentatives et le cooldown sont contrôlés en un seul endroit.
  • Traçable — qui a changé quoi, en combien de tentatives ; tout est enregistré.

La base du changement de bonus : change_attribute

Le cœur du système est la fonction du moteur qui relance au hasard toutes les lignes de bonus d'un objet. Dans la plupart des sources, cet appel s'expose sous item.change_attribute() et fait exactement ce que fait l'objet de « changement de bonus », mais depuis une quête. Il faut d'abord sélectionner l'objet à traiter :

-- selectionner l'objet cible par VID, puis relancer ses bonus
item.select(item_vid)
item.change_attribute()

Après la relance, on lit les bonus actuels et on les compare à la cible. Le nom exact de la fonction de lecture peut varier selon la révision de la source (par exemple un item.get_attribute(i) qui renvoie un couple type/valeur) ; l'essentiel est que chaque ligne puisse être obtenue sous forme de couple (type, valeur). Construis ta logique ainsi et le système fonctionne de la même façon, même si le nom de la fonction diffère chez toi.

Architecture : quête serveur ou bot client ?

Le nom « switchbot » désigne parfois une macro/un bot côté client qui clique automatiquement sur l'objet. Je ne recommande pas cette approche. Un bot client simule des paquets, peut être détecté par l'anti-hack, ne peut pas être audité sur le serveur et brise l'équité entre joueurs. La bonne solution est de tout déplacer côté serveur :

  • Source unique de vérité — les bonus, le coût et les limites vivent sur le serveur ; le client n'affiche que l'interface.
  • Sécurité de performance — la boucle avance pas à pas via un minuteur, sans bloquer.
  • Transparence — chaque tentative consomme un objet, liant un coût réel à l'économie.

On construit donc le système comme une quête et on découpe la boucle automatique avec server_timer ; ainsi le serveur ne se fige pas en attendant « jusqu'à ce que le bonus voulu apparaisse ».

Construire la boucle principale avec server_timer

Quand le joueur utilise l'objet de changement, on écrit le VID de l'objet cible et le bonus visé dans les flags du joueur, puis on lance le minuteur. À chaque déclenchement, le minuteur fait une tentative : il vérifie si l'objet est disponible, en dépense un, relance les bonus et contrôle la correspondance.

quest switchbot begin
    state start begin
        -- 71109: pierre de changement de bonus (vnum d'exemple)
        when 71109.use begin
            local target_vid = pc.getqf("sb_target_vid")
            if target_vid == 0 then
                say("Selectionne d'abord l'objet a changer.")
                return
            end
            -- remettre les tentatives a zero et lancer le compteur
            pc.setqf("sb_tries", 0)
            server_timer("sb_tick", 1, get_server_timer_arg())
        end

        when sb_tick.server_timer begin
            local change_vnum = 71109
            local tries = pc.getqf("sb_tries")
            -- a-t-on encore un objet de changement ?
            if pc.count_item(change_vnum) < 1 then
                pc.notice("Plus d'objets de changement. "..tries.." tentatives.")
                return
            end
            if tries >= 200 then
                pc.notice("Limite de tentatives atteinte (200).")
                return
            end

            pc.remove_item(change_vnum, 1)
            pc.setqf("sb_tries", tries + 1)
            item.select(pc.getqf("sb_target_vid"))
            item.change_attribute()

            if sb_match_target() then
                pc.notice("Bonus cible obtenu ! Total "..(tries+1).." tentatives.")
                return
            end
            -- pas de correspondance : attendre un peu et reessayer
            server_timer("sb_tick", 1, get_server_timer_arg())
        end
    end
end

L'idée clé ici est de construire la boucle avec un minuteur plutôt qu'avec un while. Chaque étape est un déclenchement server_timer distinct ; comme on place une seconde entre elles, même des centaines de tentatives ne bloqueront pas le serveur et les autres joueurs ne sont pas affectés. Tu peux ajuster la vitesse à ton équilibre et élargir l'intervalle sur les serveurs très fréquentés.

La logique de correspondance avec la cible

Le cerveau du système est la fonction d'aide qui répond à « les bonus actuels correspondent-ils à la cible ? » Elle conserve les lignes cibles choisies par le joueur dans des flags, et après chaque relance elle parcourt les lignes de l'objet pour vérifier si le type correspond et la valeur vaut au moins le montant demandé :

-- exemple : viser APPLY_CRITICAL_PCT d'au moins 12%
function sb_match_target()
    local want_type  = pc.getqf("sb_want_type")   -- type d'apply
    local want_value = pc.getqf("sb_want_value")  -- valeur minimale
    -- parcourir toutes les lignes de bonus de l'objet
    for i = 0, 6 do
        local atype, avalue = item.get_attribute(i)
        if atype == want_type and avalue >= want_value then
            return true
        end
    end
    return false
end

Cet exemple vise un seul bonus ; pour en exiger deux ou trois à la fois, étends la liste cible, vérifie chacun séparément et ne renvoie true que si tous sont satisfaits. Utiliser les types d'apply (p. ex. APPLY_CRITICAL_PCT, APPLY_PENETRATE_PCT, APPLY_ATTBONUS_MONSTER) par leurs noms de constantes rend le code lisible. Un dialogue PNJ classique ou un simple menu select suffit pour laisser le joueur choisir une cible.

Équilibrage : coût, limites, cooldown et logs

Un switchbot illimité et gratuit fera s'effondrer l'économie instantanément ; tout le monde obtient un objet parfait en quelques minutes. Le vrai travail qui garde le système équitable, c'est l'équilibrage :

  • Coût réel : chaque tentative doit consommer un objet de changement (et éventuellement un peu de yang). Le coût doit être assez significatif pour qu'un résultat parfait soit « mérité ».
  • Plafond de tentatives : au plus N tentatives par session (200 dans l'exemple). Le plafond évite les boucles infinies et la charge serveur.
  • Cooldown : ajoute une courte attente après la fin d'une session ; applique-la avec pc.setqf("sb_cd", get_global_time() + 60).
  • Journalisation : à chaque réussite, écris le nom du joueur, l'objet, la cible et le nombre de tentatives dans la base/le fichier de log ; c'est crucial pour détecter les abus et déboguer.

Ne néglige pas non plus les contrôles de sécurité : vérifie tout du long que l'objet cible est toujours dans l'inventaire (le joueur a pu le vendre ou le jeter), avertis l'utilisateur si un objet +0 n'a pas de bonus, et utilise un flag pour empêcher le démarrage simultané de deux sessions switchbot. Ces petits contrôles évitent les plaintes du type « j'ai dépensé du yang sur un objet vide » sur un serveur en production.

Questions fréquentes

Le switchbot garantit-il une valeur de bonus ?

Non, il ne le fait pas et ne le doit pas. Le système répète seulement change_attribute automatiquement ; chaque tentative est indépendante et aléatoire. Un switchbot supprime juste la corvée de « cliquer des centaines de fois » — il ne change pas les probabilités. Si tu veux une garantie, c'est une fonctionnalité distincte (p. ex. le verrouillage de bonus) à l'équilibre bien plus délicat.

Ce système sollicite-t-il le serveur ?

Non, tant que tu découpes la boucle en étapes avec server_timer au lieu d'un while. Mettre un court intervalle entre les tentatives suffit à étaler le travail, et le plafond de tentatives borne le pire cas. La vraie charge vient de l'exécution de la boucle en une seule frame — à éviter.

Un switchbot côté client n'est-il pas plus simple ?

À court terme oui, mais il se retourne contre toi plus tard : il peut être bloqué par l'anti-hack, ne peut pas être audité et brise l'équité entre joueurs. Construire le système sur le serveur demande un peu plus d'effort mais reste sûr, transparent et durable.

Tu veux un switchbot équilibré et à l'épreuve des abus pour ton serveur ? Du choix de la cible au coût et aux limites, de la journalisation à l'interface, je peux construire et tester tout le système de bout en bout. Pour discuter de ton projet, contacte-moi.

Bu kategorideki tüm yazılar →

Devamı için