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

Metin2 switchbot-systeem: automatisch bonussen wisselen

Een Metin2 switchbot-systeem is een mechanisme dat de bonussen (attributen) van een item automatisch opnieuw rolt totdat de gewenste combinatie verschijnt, in plaats van klik voor klik. De speler stelt een doel in — bijvoorbeeld "kritieke treffer 15% en gemiddelde schade 10%" — en het systeem verbruikt wissel-items, rolt de attributen keer op keer opnieuw en stopt zodra er een match is. In deze gids laat ik zien hoe je zo'n systeem serverzijdig, met de Lua quest-engine, veilig en gebalanceerd bouwt. Het doel is geen kant-en-klare code kopiëren, maar de logica begrijpen en aanpassen aan je eigen server.

Wat automatiseert een switchbot precies?

In Metin2 worden de bonussen van een item opgeslagen als attributen: elke regel heeft een type (kritieke kans, doordringende treffer, schade tegen monsters…) en een waarde. De klassieke manier is dat de speler een "bonuswissel"-item gebruikt, alle regels willekeurig opnieuw laat rollen en het opnieuw probeert als het resultaat niet bevalt. Het is een vervelende lus die honderden klikken kan kosten.

Een switchbot verplaatst die lus naar de server: de speler kiest één keer een doel, en bij elke stap verbruikt het systeem één wissel-item, rolt de attributen opnieuw en vergelijkt het resultaat met het doel. De voordelen zijn duidelijk:

  • Eerlijk en controleerbaar — willekeur en kosten worden op de server berekend, nooit op vertrouwen van de client.
  • Misbruikbestendig — itemvoorraad, pogingslimiet en cooldown worden vanaf één plek beheerd.
  • Logbaar — wie veranderde wat, in hoeveel pogingen; alles wordt vastgelegd.

De basis van bonuswissel: change_attribute

Het hart van het systeem is de engine-functie die alle bonusregels van een item willekeurig opnieuw rolt. In de meeste sources wordt deze aanroep als item.change_attribute() blootgesteld en doet precies wat het "bonuswissel"-item doet, maar vanuit een quest. Eerst moet je het te bewerken item selecteren:

-- selecteer het doel-item op VID, roll daarna zijn bonussen
item.select(item_vid)
item.change_attribute()

Na het rollen lezen we de huidige bonussen en vergelijken ze met het doel. De exacte naam van de leesfunctie kan per source-revisie verschillen (bijvoorbeeld een item.get_attribute(i) die een type/waarde-paar teruggeeft); wat telt is dat elke regel als een (type, waarde)-paar te verkrijgen is. Bouw je logica daarop en het systeem werkt hetzelfde, zelfs als de functienaam bij jou anders is.

Architectuur: server-quest of client-bot?

De naam "switchbot" wordt soms gebruikt voor een client-side macro/bot die automatisch op het item klikt. Die aanpak raad ik af. Een client-bot vervalst packets, kan door anti-hack worden gepakt, is niet op de server te controleren en breekt de eerlijkheid tussen spelers. De juiste oplossing is om het hele systeem naar de server te verplaatsen:

  • Eén bron van waarheid — bonussen, kosten en limieten leven op de server; de client toont alleen de interface.
  • Performance-veiligheid — de lus vordert stap voor stap via een timer, zonder te blokkeren.
  • Transparantie — elke poging verbruikt één item, wat een echte kostprijs aan de economie koppelt.

Daarom bouwen we het systeem als een quest en splitsen we de automatische lus met server_timer; zo bevriest de server niet terwijl hij wacht "tot de gewenste bonus verschijnt".

De kernlus bouwen met server_timer

Wanneer de speler het wissel-item gebruikt, schrijven we de VID van het doel-item en de gekozen doelbonus in de flags van de speler en starten we de timer. Bij elke trigger doet de timer één poging: hij controleert of het item beschikbaar is, verbruikt er één, rolt de bonussen opnieuw en controleert op een match.

quest switchbot begin
    state start begin
        -- 71109: bonuswissel-steen (voorbeeld-vnum)
        when 71109.use begin
            local target_vid = pc.getqf("sb_target_vid")
            if target_vid == 0 then
                say("Selecteer eerst het te wijzigen item.")
                return
            end
            -- pogingen resetten en de lus-teller starten
            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")
            -- hebben we nog een wissel-item?
            if pc.count_item(change_vnum) < 1 then
                pc.notice("Wissel-items op. "..tries.." pogingen gedaan.")
                return
            end
            if tries >= 200 then
                pc.notice("Pogingslimiet bereikt (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("Doelbonus geraakt! Totaal "..(tries+1).." pogingen.")
                return
            end
            -- geen match: even wachten en opnieuw proberen
            server_timer("sb_tick", 1, get_server_timer_arg())
        end
    end
end

Het kernidee hier is om de lus met een timer te bouwen in plaats van met een while. Elke stap is een aparte server_timer-trigger; omdat we er één seconde tussen zetten, vergrendelen zelfs honderden pogingen de server niet en hebben andere spelers er geen last van. Je kunt de snelheid op je balans afstemmen en het interval verbreden op drukke servers.

De doel-matchlogica

Het brein van het systeem is de hulpfunctie die de vraag "komen de huidige bonussen overeen met het doel?" beantwoordt. Ze bewaart de door de speler gekozen doelregels in flags en scant na elke roll de regels van het item om te controleren of het type overeenkomt en de waarde minstens het gevraagde bedrag is:

-- voorbeeld: richt op APPLY_CRITICAL_PCT van minstens 12%
function sb_match_target()
    local want_type  = pc.getqf("sb_want_type")   -- apply-type
    local want_value = pc.getqf("sb_want_value")  -- minimumwaarde
    -- scan alle bonusregels op het 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

Dit voorbeeld richt zich op één bonus; om er twee of drie tegelijk te eisen, breid je de doellijst uit, controleer je elk afzonderlijk en geef je alleen true terug als aan alle is voldaan. Apply-types (bijv. APPLY_CRITICAL_PCT, APPLY_PENETRATE_PCT, APPLY_ATTBONUS_MONSTER) bij hun constantennamen gebruiken houdt de code leesbaar. Een klassiek NPC-dialoogvenster of een eenvoudig select-menu volstaat om de speler een doel te laten kiezen.

Balanceren: kosten, limieten, cooldown en logs

Een switchbot die onbeperkt en gratis is, laat de economie meteen instorten; iedereen rolt binnen minuten een perfect item. Het echte werk dat het systeem eerlijk houdt, is balanceren:

  • Echte kosten: elke poging moet één wissel-item verbruiken (en eventueel wat yang). De kosten moeten betekenisvol genoeg zijn om een perfect resultaat "verdiend" te laten voelen.
  • Pogingsplafond: maximaal N pogingen per sessie (200 in het voorbeeld). Het plafond voorkomt oneindige lussen en serverbelasting.
  • Cooldown: voeg een korte wachttijd toe na het einde van een sessie; handhaaf die met pc.setqf("sb_cd", get_global_time() + 60).
  • Logging: schrijf bij elke geslaagde hit de spelernaam, het item, het doel en het aantal pogingen naar de database/het logbestand; dit is cruciaal voor misbruikdetectie en debuggen.

Verwaarloos ook de veiligheidscontroles niet: controleer gedurende het hele proces of het doel-item nog in de inventaris zit (de speler kan het hebben verkocht of weggegooid), waarschuw de gebruiker als een +0-item geen bonussen heeft, en gebruik een flag om te voorkomen dat er tegelijk twee switchbot-sessies starten. Deze kleine controles voorkomen klachten als "ik heb yang uitgegeven aan een leeg item" op een live server.

Veelgestelde vragen

Garandeert de switchbot een bonuswaarde?

Nee, dat doet hij niet en hoort hij niet te doen. Het systeem herhaalt alleen change_attribute automatisch; elke poging is onafhankelijk en willekeurig. Een switchbot neemt alleen het karwei van "honderden keren klikken" weg — het verandert de kansen niet. Wil je een garantie, dan is dat een aparte functie (bijv. bonusvergrendeling) met een veel delicatere balans.

Belast dit systeem de server?

Nee, zolang je de lus in stappen splitst met server_timer in plaats van een while. Een kort interval tussen de pogingen volstaat om het werk te spreiden, en het pogingsplafond begrenst het ergste geval. De echte belasting komt van het proberen de lus in één frame uit te voeren — vermijd dat.

Is een client-side switchbot niet makkelijker?

Op de korte termijn wel, maar het keert zich later tegen je: hij kan door anti-hack worden geblokkeerd, is niet te controleren en breekt de eerlijkheid tussen spelers. Het systeem op de server bouwen kost wat meer moeite maar is veilig, transparant en duurzaam.

Wil je een gebalanceerde, misbruikbestendige switchbot voor je server? Van doelselectie tot kosten en limieten, van logging tot interface, ik kan het hele systeem van begin tot eind bouwen en testen. Om je project te bespreken, neem contact met me op.

Bu kategorideki tüm yazılar →

Devamı için