Înapoi la blogToate tutorialele Metin2
Tutoriale Metin2 · Lecția 64 din 99

Intrarea în dungeon pentru party: nivel, lider, bilet și verificări pe server

2 noiembrie 2026 6 min de citit

Ușa dungeonului e primul loc unde jucătorii încearcă să „păcălească” regulile: intră cu un personaj prea mic, intră fără bilet sau cer liderului să deschidă intrarea în timp ce el pleacă pe altă hartă. Toate aceste verificări trebuie făcute **pe server**, în quest, nu în client. În lecția aceasta construim un dialog de intrare care verifică grupul, liderul, nivelul fiecărui membru și biletul, și abia apoi îi trimite înăuntru.

Pe scurt: verifici în ordine: are grup, e lider, toți membrii au nivelul cerut, mai are biletul. Abia după ultima verificare iei biletul și trimiți grupul în instanță cu d.new_jump_party.

Cuvinte pe care le vei întâlni

CuvântCe înseamnă
PartyGrupul de jucători. Are un lider.
PIDNumărul unic al unui personaj (player id).
d.new_jump_partyFuncția care creează o instanță nouă și trimite grupul în ea.
Bilet de intrareUn item consumat la intrare (în multe pachete „Pasul” sau „Biletul” dungeonului).
CoreUn proces game care rulează un set de hărți. Un canal poate avea mai multe core-uri.

Ce face, de fapt, d.new_jump_party

Am verificat funcția în sursa serverului (questlua_dungeon.cpp). Ea face trei lucruri:

  1. Creează o instanță nouă a hărții pe care i-o dai.
  2. Dacă jucătorul nu are grup, se oprește și scrie în syserr cannot go to dungeon alone. Nimeni nu e mutat.
  3. Mută în instanță doar membrii grupului aflați pe aceeași hartă cu cel care a pornit questul. Cine e pe altă hartă sau pe alt canal rămâne pe loc.

Al treilea punct e important. La fel se comportă și party.get_member_pids(): întoarce doar membrii de pe aceeași hartă. Deci dacă verifici nivelul „tuturor”, verifici de fapt doar membrii de lângă tine. Pentru dungeon e exact ce vrei.

Pasul 1: Codul dialogului de intrare

Exemplul de mai jos e simplificat după flame_dungeon.quest din pachet. Valorile scrise cu majuscule sunt „etichete” definite la începutul questului cu define; înlocuiește-le cu numerele tale.

lua
define NPC_INTRARE 20094
define BILET 30329
define MAPA_DUNGEON 351
define NIVEL_MINIM 50

quest pestera_intrare begin
    state start begin
        when NPC_INTRARE.chat."Intra in Pestera Lupilor" begin
            if not party.is_party() then
                say("Ai nevoie de un grup ca sa intri.")
                return
            end
            if not party.is_leader() then
                say("Doar liderul grupului poate deschide intrarea.")
                return
            end
            local pids = {party.get_member_pids()}
            local prea_mici = {}
            for i, pid in next, pids, nil do
                q.begin_other_pc_block(pid)
                if pc.get_level() < NIVEL_MINIM then
                    table.insert(prea_mici, pc.get_name())
                end
                q.end_other_pc_block()
            end
            if table.getn(prea_mici) > 0 then
                say("Acesti membri nu au nivelul necesar:")
                for i, nume in next, prea_mici, nil do
                    say(nume)
                end
                return
            end
            local s = select("Intra", "Anulare")
            if s == 2 then
                return
            end
            if pc.count_item(BILET) < 1 then
                say("Nu ai biletul de intrare.")
                return
            end
            pc.remove_item(BILET, 1)
            d.new_jump_party(MAPA_DUNGEON, 7762, 6739)
        end
    end
end

Atenție: 20094, 30329 și 351 sunt doar exemple. Caută VNUM-urile și indexul hărții în pachetul tău, cum ai învățat în lecția despre VNUM.

Pasul 2: Explicat bucată cu bucată

BucatăCe face, pe românește
party.is_party()„Are jucătorul grup?” Dacă nu, oprim totul cu return.
party.is_leader()„E el liderul?” Doar liderul poate porni intrarea.
{party.get_member_pids()}Face o listă cu PID-urile membrilor de pe aceeași hartă.
q.begin_other_pc_block(pid)„De acum, pc.* se referă la membrul acesta.” Așa citești nivelul fiecăruia.
q.end_other_pc_block()„Revino la jucătorul care vorbește cu NPC-ul.” Nu-l uita, altfel restul codului lucrează pe alt personaj.
select("Intra", "Anulare")Cere confirmarea. 1 = Intra, 2 = Anulare.
pc.count_item(BILET) < 1Verifică biletul după confirmare, chiar înainte de a-l lua.
pc.remove_item(BILET, 1)Ia biletul.
d.new_jump_party(351, 7762, 6739)Creează instanța hărții 351 și mută grupul la coordonatele date.

De ce verificăm biletul după „Intra”, nu înainte

Între momentul în care apare fereastra cu butoane și momentul în care jucătorul apasă „Intra” pot trece multe secunde. În acest timp, jucătorul poate arunca biletul, îl poate pune în depozit sau îl poate da altcuiva. Dacă ai verificat biletul doar la început, l-ai lăsa să intre gratis. Regula simplă: verifică chiar înainte de acțiune, în același bloc de cod, fără alte ferestre între verificare și acțiune.

Coordonatele: atenție la două sisteme diferite

În pachetul verificat, d.new_jump_party și d.jump_all primesc coordonate globale (poziția hărții în lume plus poziția în hartă). În schimb, d.spawn_mob primește coordonate locale, din interiorul hărții. În flame_dungeon.quest, intrarea folosește {7762, 6739}, iar bossul e pus la {686, 637}. Dacă amesteci cele două, grupul ajunge în afara hărții sau monstrul nu apare. Detalii în lecția despre coordonate și hărți.

Bilet pentru lider sau pentru toți?

Exemplul nostru ia biletul doar de la lider. Dungeonul de foc din pachet cere bilet de la fiecare membru și îl ia pe rând, în același tip de buclă cu q.begin_other_pc_block. Ambele variante sunt corecte; alege una și scrie-o clar în descrierea dungeonului, ca jucătorii să știe.

Serverele cu mai multe core-uri

Instanța se creează pe core-ul pe care rulează questul. Dacă harta dungeonului nu e încărcată pe acel core (în fișierul CONFIG, la hărțile permise), crearea eșuează. Pe unele surse modificate există funcții separate pentru intrarea pe alt core. Nu le folosi decât dacă le găsești în quest_functions la tine. Despre CONFIG ai citit în lecția despre porturi și canale.

Ce ar trebui să vezi: liderul alege „Intra”, biletul dispare din inventar, iar toți membrii de lângă el sunt teleportați în dungeon.

Cum testezi intrarea

Pe serverul de test, încearcă pe rând:

Ce încerciCe trebuie să se întâmple
Solo, fără grupMesaj „Ai nevoie de un grup”, nimeni nu intră.
Membru, nu liderMesaj „Doar liderul…”.
Un membru sub nivelApare numele lui, nimeni nu intră, biletul rămâne.
Arunci biletul după ce apare fereastraMesaj „Nu ai biletul”, nimeni nu intră.
Un membru pe altă hartăCeilalți intră, el rămâne afară.
Totul corectBiletul dispare o singură dată, grupul intră.

Greșeli des întâlnite

  • Lipsește q.end_other_pc_block(). Restul questului lucrează pe alt personaj, iar biletul se ia de la cine nu trebuie.
  • Biletul se verifică înainte de select. Jucătorul îl poate arunca în timp ce fereastra e deschisă.
  • Biletul se ia înainte de toate verificările. Dacă intrarea eșuează, jucătorul pierde biletul degeaba.
  • Verificarea e doar în client (de exemplu un buton gri). Clientul se poate modifica; serverul decide.
  • Coordonate locale date funcției de intrare. Grupul ajunge într-un loc greșit.

Întrebări frecvente

Pot lăsa un jucător să intre singur?

Da, dar cu altă funcție. În pachet există și d.new_jump și d.new_jump_all, care nu cer grup. Verifică exact cum le folosesc questurile din pachetul tău înainte să le copiezi.

De ce nu intră un membru al grupului?

Cel mai des, era pe altă hartă sau pe alt canal în momentul intrării. Doar membrii de pe aceeași hartă cu liderul sunt mutați.

Unde văd de ce n-a mers?

În syserr-ul core-ului pe care rulează questul. Mesaje ca cannot go to dungeon alone sau cannot create dungeon îți spun exact problema.

Ce urmează

Grupul e înăuntru. Acum construim etapele, pietrele Metin și bossul final. Pentru recapitulare, vezi primul quest Lua.

Toate lecțiile sunt în lista tutorialelor Metin2.

Server Metin2 gata de joc

Găzduire Metin2 în România, cu instalare de serverfiles, bază de date MySQL și protecție Anti-DDoS inclusă.

DiscordWhatsApp