Un quest are nevoie de memorie. Trebuie să știe dacă jucătorul a acceptat misiunea, câți monștri a omorât, dacă a luat deja recompensa, când a făcut-o ultima dată. Toată această memorie se ține în **quest flag-uri**. În lecțiile anterioare le-ai folosit deja (`ucisi`, `primit`). Acum le înțelegem complet, împreună cu condițiile de nivel, și construim o misiune care se poate face o dată la 24 de ore.
pc.setqf("nume", valoare) salvează un număr pentru jucător în questul curent, pc.getqf("nume") îl citește (0 dacă nu există). Condițiile de nivel le pui în with pc.get_level() >= X și le verifici din nou înainte de recompensă. Flag-urile se scriu doar din acțiuni în joc, niciodată în when login.Cuvinte pe care le vei întâlni
| Cuvânt | Ce înseamnă |
|---|---|
| Quest flag | Un număr întreg salvat pentru un jucător, legat de un quest. |
| Event flag | Un număr salvat pentru tot serverul, nu pentru un jucător. Îl folosim la evenimente. |
| Timestamp | Un moment în timp scris ca număr de secunde. get_time() îți dă momentul de acum. |
| Cooldown | Timpul de așteptare până poți repeta ceva. |
Trei feluri de „memorie” într-un quest
| Ce folosești | Pentru cine ține minte | Exemplu |
|---|---|---|
pc.setqf / pc.getqf | Un jucător, în questul curent | Câți lupi a omorât |
pc.setf / pc.getf | Un jucător, dar în alt quest | Ai terminat misiunea „gheare_lup”? |
game.set_event_flag / game.get_event_flag | Tot serverul | Evenimentul e pornit? |
set_state(...) | Un jucător: etapa questului | „vânează”, „predă”, „terminat” |
Toate funcțiile de mai sus există în lista quest_functions a pachetului de referință. Event flag-urile le folosim în lecțiile despre NPC-ul care pornește un eveniment și evenimentul cu timer.
Cum se salvează un flag (și de ce nu redenumești questul)
În pachetul verificat, flag-ul se salvează în baza de date, în tabelul quest din baza player, sub numele questului plus numele flag-ului. Concret, pc.setqf("ucisi", 7) în questul vanatoare_lupi devine „vanatoare_lupi, ucisi, 7” pentru acel personaj.
Asta are trei urmări practice:
- Dacă redenumești questul, jucătorii își pierd progresul. Noul nume nu are niciun flag salvat.
- Flag-urile sunt numere întregi. Nu poți salva text. Pentru „da/nu” folosești 1 și 0.
- Valoarea 0 înseamnă „nimic”. În același pachet, un flag cu valoarea 0 este șters din baza de date, iar
pc.getqfpe un flag inexistent întoarce 0. Deci „nesetat” și „0” sunt același lucru.
Păstrează numele scurte și fără spații sau diacritice: ucisi, primit, urmatoarea. În sursa verificată, numele questului are cel mult 32 de caractere.
Condițiile de nivel
Ai două locuri unde poți pune o condiție.
În rândul when, cu with: opțiunea nici nu apare dacă condiția nu e îndeplinită.
when 20011.chat."Misiunea zilnica" with pc.get_level() >= 20 and pc.get_level() <= 60 beginÎn interiorul blocului, cu if: opțiunea apare, dar NPC-ul îi explică jucătorului de ce nu poate.
if pc.get_level() < 20 then
say("Revino cand ai nivelul 20.")
return
endA doua variantă e mai prietenoasă: jucătorul află că misiunea există. Vei vedea în questurile din pachet și forma scurtă pc.level; în questlib.lua ea înseamnă exact pc.get_level().
Capcana levelup: questurile din pachet folosesc des when levelup with pc.level >= 30. Acest eveniment pornește doar în momentul în care jucătorul urcă un nivel. Un jucător care era deja la nivelul 45 când ai adăugat questul nu va declanșa nimic până la următorul nivel. Pentru misiunile noi, o condiție verificată la NPC e mai sigură.
Codul: misiune zilnică, pentru nivelurile 20–60
Jucătorul omoară 20 de Lupi albaștri (monstrul 104 în pachetul verificat), primește 20.000 yang și poate repeta misiunea după 24 de ore.
quest zilnica_lupi begin
state start begin
when 20011.chat."Misiunea zilnica" with pc.get_level() >= 20 and pc.get_level() <= 60 begin
say_title("Misiunea zilnica")
local ramas = pc.getqf("urmatoarea") - get_time()
if ramas > 0 then
say(string.format("Revino peste %d minute.", math.ceil(ramas / 60)))
return
end
if pc.getqf("activa") == 0 then
say("Omoara 20 de Lupi albastri si revino.")
pc.setqf("ucisi", 0)
pc.setqf("activa", 1)
return
end
if pc.getqf("ucisi") < 20 then
say(string.format("Ai omorat %d din 20.", pc.getqf("ucisi")))
return
end
pc.setqf("activa", 0)
pc.setqf("urmatoarea", get_time() + 86400)
pc.change_money(20000)
say("Bravo! Iata 20.000 yang. Revino maine.")
end
when 104.kill with pc.getqf("activa") == 1 begin
local n = pc.getqf("ucisi")
if n < 20 then
pc.setqf("ucisi", n + 1)
end
end
end
endExplicat rând cu rând
| Rând | Ce înseamnă |
|---|---|
with pc.get_level() >= 20 and pc.get_level() <= 60 | Opțiunea apare doar între nivelurile 20 și 60. and înseamnă „și”. |
local ramas = pc.getqf("urmatoarea") - get_time() | urmatoarea ține momentul de la care se poate repeta. Scădem momentul de acum: rezultatul e câte secunde mai sunt. |
if ramas > 0 then | Dacă încă n-a trecut timpul, îi spunem cât mai are și ne oprim. La prima vizită flag-ul e 0, deci ramas e negativ și trecem mai departe. |
math.ceil(ramas / 60) | Transformă secundele în minute, rotunjind în sus. |
if pc.getqf("activa") == 0 then | N-a pornit încă misiunea azi: o pornim. |
pc.setqf("ucisi", 0) și pc.setqf("activa", 1) | Resetăm numărătoarea și marcăm misiunea ca activă. |
if pc.getqf("ucisi") < 20 then | Încă n-a terminat: îi arătăm progresul. |
pc.setqf("activa", 0) | Închidem misiunea înainte de recompensă. |
pc.setqf("urmatoarea", get_time() + 86400) | Următoarea dată posibilă: acum plus 86.400 de secunde (24 de ore). |
pc.change_money(20000) | Recompensa. |
when 104.kill with pc.getqf("activa") == 1 | Lupii albaștri se numără doar cât timp misiunea e activă. |
Aici n-am folosit etape (state), ci doar flag-uri: activa face aceeași treabă. Ambele variante sunt corecte. Etapele sunt mai clare pentru misiuni cu mulți pași; flag-urile sunt mai simple pentru misiuni repetabile.
Pachetul de referință folosește exact același model de „pauză” în misiunile de colectare ale biologului: un flag duration cu get_time() plus un număr de secunde.
Regula de aur: flag-urile nu se scriu la logare
Nu pune niciodată pc.setqf (și nici pc.setf) în when login. Există o problemă cunoscută în motorul Metin2: scrierea de quest flag-uri în timpul intrării în joc poate strica flag-urile jucătorului sau tabelul quest din baza de date. Vei vedea în pachet questuri care fac lucruri la login, de exemplu afișează scrisori. Afișarea e în regulă. Scrierea de flag-uri o faci doar din acțiuni în joc: dialog cu un NPC, un monstru omorât, un item folosit.
Dacă vrei „cadou la prima logare”, pune-l la un NPC din sat, cu o condiție pc.getqf("primit") == 0, ca în lecția despre recompense în inventar.
Testează
- Cu un personaj de nivel 19: opțiunea nu apare. La nivel 61, la fel.
- Pornește misiunea, omoară 5 lupi, ieși din joc, revino: trebuie să scrie 5 din 20.
- Termină misiunea și vorbește din nou cu NPC-ul: trebuie să-ți spună câte minute mai ai.
- Pe serverul de test, ca să nu aștepți 24 de ore, poți schimba temporar
86400în120(2 minute). Nu uita să-l pui la loc înainte de a publica.
Greșeli des întâlnite
- Flag scris în
when login. Risc de date de quest stricate. - Questul redenumit după lansare. Toți jucătorii pierd progresul.
- Condiție de nivel doar în
with, nu și la recompensă, într-o misiune lungă. Pentru limite superioare (de exemplu „doar până la 60”), un jucător poate accepta la 59 și preda la 65. Decide dacă te deranjează și verifică din nou la predare. - Testul de 2 minute rămas pe serverul live. Misiunea zilnică devine „la fiecare 2 minute”.
Întrebări frecvente
Cum resetez misiunea pentru un singur jucător?
Pe serverul de test, cel mai sigur e din quest: o opțiune vizibilă doar pentru GM care pune flag-ul la 0. Nu edita tabelul quest pe serverul live cât timp jucătorul e conectat, pentru că serverul ține flag-urile și în memorie.
Pot citi flag-ul altui quest?
Da: pc.getf("gheare_lup", "nume_flag") citește un flag din questul gheare_lup. Util pentru „misiunea asta apare doar dacă ai terminat-o pe cealaltă”.
Ce e pc.delqf?
Șterge un flag din questul curent. În practică, pc.setqf("nume", 0) are același efect și e mai ușor de citit.
Ce urmează
Până acum am ținut minte lucruri pentru fiecare jucător. Următorul pas e memoria pentru tot serverul: un NPC care pornește un eveniment.
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ă.