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

Metin2 Switchbot System: Automatic Bonus Switching

A Metin2 switchbot system is a mechanism that re-rolls an item's bonuses (attributes) automatically until the desired combination appears, instead of doing it click by click. The player sets a target — say "critical hit 15% and average damage 10%" — and the system spends change items, re-rolls the attributes again and again, and stops once a match is found. In this guide I'll walk through how to build such a system server-side, with the Lua quest engine, in a safe and balanced way. The goal isn't to copy ready-made code but to grasp the logic and adapt it to your own server.

What exactly does a switchbot automate?

In Metin2 an item's bonuses are stored as attributes: each line has a type (critical chance, piercing hit, damage against monsters…) and a value. The classic way is for the player to use a "bonus change" item, have all lines re-rolled at random, and try again if they don't like the result. It's a tedious loop that can take hundreds of clicks.

A switchbot moves that loop to the server: the player picks a target once, and on each step the system spends one change item, re-rolls the attributes and compares the result against the target. The advantages are clear:

  • Fair and auditable — randomness and cost are computed on the server, never trusting the client.
  • Exploit-proof — item stock, attempt limit and cooldown are controlled from one place.
  • Loggable — who changed what, in how many attempts; all of it is recorded.

The foundation of bonus change: change_attribute

The heart of the system is the engine function that re-rolls all of an item's bonus lines at random. In most sources this call is exposed as item.change_attribute() and does exactly what the "bonus change" item does, but from within a quest. First you need to select the item to operate on:

-- select the target item by VID, then re-roll its bonuses
item.select(item_vid)
item.change_attribute()

After re-rolling, we read the current bonuses and compare them with the target. The exact name of the read function can vary by source revision (for example an item.get_attribute(i) that returns a type/value pair); what matters is that each line can be obtained as a (type, value) pair. Build your logic around that and the system works the same even if the function name differs on your side.

Architecture: server quest or client bot?

The name "switchbot" is sometimes used for a client-side macro/bot that auto-clicks on the item. I don't recommend that approach. A client bot fakes packets, can be caught by anti-hack, can't be audited on the server and breaks fairness between players. The right solution is to move the whole system server-side:

  • Single source of truth — bonuses, cost and limits live on the server; the client only shows the interface.
  • Performance safety — the loop advances step by step via a timer, without blocking.
  • Transparency — every attempt consumes one item, tying a real cost to the economy.

So we build the system as a quest and split the automatic loop with server_timer; that way the server doesn't freeze while waiting "until the desired bonus appears."

Building the core loop with server_timer

When the player uses the change item, we write the target item's VID and chosen target bonus into the player's flags, then start the timer. On each trigger the timer makes one attempt: it checks whether the item is available, spends one, re-rolls the bonuses and checks for a match.

quest switchbot begin
    state start begin
        -- 71109: bonus change stone (example vnum)
        when 71109.use begin
            local target_vid = pc.getqf("sb_target_vid")
            if target_vid == 0 then
                say("Select the item to change first.")
                return
            end
            -- reset attempts and start the loop counter
            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")
            -- do we still have a change item?
            if pc.count_item(change_vnum) < 1 then
                pc.notice("Out of change items. "..tries.." attempts made.")
                return
            end
            if tries >= 200 then
                pc.notice("Attempt limit reached (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("Target bonus hit! Total "..(tries+1).." attempts.")
                return
            end
            -- no match: wait briefly and try again
            server_timer("sb_tick", 1, get_server_timer_arg())
        end
    end
end

The key idea here is to build the loop with a timer rather than a while. Each step is a separate server_timer trigger; because we put one second between them, even hundreds of attempts won't lock the server and other players are unaffected. You can tune the speed to your balance and widen the interval on busier servers.

The target-matching logic

The brain of the system is the helper that answers "do the current bonuses match the target?" It keeps the player's chosen target lines in flags, and after each re-roll it scans the item's lines and checks whether the type matches and the value is at least the requested amount:

-- example: target APPLY_CRITICAL_PCT of at least 12%
function sb_match_target()
    local want_type  = pc.getqf("sb_want_type")   -- apply type
    local want_value = pc.getqf("sb_want_value")  -- minimum value
    -- scan all bonus lines on the item
    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

This example targets a single bonus; to require two or three at once, expand the target list, check each separately and return true only if all of them are satisfied. Using apply types (e.g. APPLY_CRITICAL_PCT, APPLY_PENETRATE_PCT, APPLY_ATTBONUS_MONSTER) by their constant names keeps the code readable. A classic NPC dialog or a simple select menu is enough to let the player pick a target.

Balancing: cost, limits, cooldown and logs

A switchbot that's unlimited and free will collapse the economy instantly; everyone rolls a perfect item within minutes. The real work that keeps the system fair is balancing:

  • Real cost: each attempt should consume one change item (and optionally some yang). The cost must be meaningful enough to make a perfect result feel "earned."
  • Attempt cap: at most N attempts per session (200 in the example). The cap prevents infinite loops and server load.
  • Cooldown: add a short wait after a session ends; enforce it with pc.setqf("sb_cd", get_global_time() + 60).
  • Logging: on each successful hit, write the player name, item, target and attempt count to the database/log file; this is critical for abuse detection and debugging.

Don't neglect the safety checks either: verify throughout that the target item is still in the inventory (the player may have sold or dropped it), warn the user if a +0 item has no bonuses, and use a flag to prevent two switchbot sessions from starting at once. These small checks head off "I spent yang on an empty item" complaints on a live server.

Frequently Asked Questions

Does the switchbot guarantee a bonus value?

No, it doesn't and shouldn't. The system only repeats change_attribute automatically; every attempt is independent and random. A switchbot merely removes the chore of "clicking hundreds of times" — it doesn't change the odds. If you want a guarantee, that's a separate feature (e.g. bonus locking) with a far more delicate balance.

Does this system strain the server?

Not as long as you split the loop into steps with server_timer instead of a while. Putting a short interval between attempts is enough to spread the work out, and the attempt cap limits the worst case. The real load comes from trying to run the loop in a single frame — avoid that.

Isn't a client-side switchbot easier?

In the short term yes, but it bites you later: it can be blocked by anti-hack, can't be audited and breaks fairness between players. Building the system on the server takes a bit more effort but is safe, transparent and sustainable.

Want a balanced, exploit-proof switchbot for your server? From target selection to cost and limits, from logging to the interface, I can build and test the whole system end to end. To discuss your project, get in touch with me.

Bu kategorideki tüm yazılar →

Devamı için