Primul lucru pe care îl cere orice jucător nou e „pune și X la magazin”. Pare o schimbare mică, dar mulți administratori caută degeaba un fișier text cu marfa negustorului. În majoritatea pachetelor clasice, magazinele NPC nu stau într-un fișier, ci în **baza de date**. În lecția asta afli unde sunt, cum adaugi un item și cum verifici că totul a mers.
player: shop (ce magazine există și ce NPC le deschide) și shop_item (ce se vinde în fiecare). Prețul nu e în magazin, ci vine din item_proto. După modificare repornești serverul și verifici în joc.Cuvinte pe care le vei întâlni
| Cuvânt | Ce înseamnă |
|---|---|
| Tabel | O listă din baza de date, ca o foaie Excel cu rânduri și coloane. |
| shop | Tabelul cu magazinele: numărul magazinului, un nume intern și NPC-ul care îl deschide. |
| shop_item | Tabelul cu marfa: în ce magazin, ce item, câte bucăți într-un pachet. |
| NPC VNUM | Numărul negustorului, de exemplu 9003 pentru „General Store Saleswoman”. Vezi lecția despre VNUM. |
| SELECT / INSERT | Comenzi SQL: SELECT doar citește, INSERT adaugă un rând nou. |
Cum arată magazinele în baza de date
În pachetul pe care l-am verificat (un serverfiles clasic, în engleză), tabelul shop are trei coloane:
| Coloană | Ce înseamnă |
|---|---|
vnum | Numărul magazinului (nu al NPC-ului!). De exemplu 3. |
name | Un nume intern, nu apare în joc. De exemplu General Store Saleswoman. |
npc_vnum | NPC-ul la care se deschide magazinul. De exemplu 9003. |
Tabelul shop_item are tot trei coloane:
| Coloană | Ce înseamnă |
|---|---|
shop_vnum | În ce magazin apare itemul (legătura cu shop.vnum). |
item_vnum | Ce item se vinde. |
count | Câte bucăți primește jucătorul la o cumpărare. |
Deci magazinul 3 aparține NPC-ului 9003, iar rândul 3, 27001, 20 înseamnă „la magazinul 3 se vinde un pachet de 20 de Red Potion(S)”.
Atenție: la tine pot exista și alte coloane, alte nume sau chiar un fișier text în loc de tabel. Unele surse citesc în plus un fișier opțional shop_table_ex.txt din folderul locale (magazine cu tab-uri). În pachetul verificat, acest fișier nu exista. Mereu te uiți întâi la structura reală.
Pasul 1: Găsește magazinul NPC-ului
Lucrează pe serverul de test. Intră în MySQL (vezi lecția despre MySQL) și rulează doar comenzi de citire:
USE player;
DESCRIBE shop;
DESCRIBE shop_item;
SELECT * FROM shop WHERE npc_vnum = 9003;
SELECT * FROM shop_item WHERE shop_vnum = 3;Bucată cu bucată:
USE player;alege baza de date a jocului. La tine se poate numi altfel.DESCRIBEîți arată coloanele reale ale tabelului. Compară-le cu cele de mai sus.- Primul
SELECTîți spune ce număr de magazin are NPC-ul 9003. - Al doilea
SELECTîți arată marfa acelui magazin.
Ce ar trebui să vezi: un rând în shop (de exemplu 3, General Store Saleswoman, 9003) și mai multe rânduri în shop_item cu poțiunile și itemele pe care le vezi și în joc.
Pasul 2: Fă backup la cele două tabele
Înainte de orice schimbare, salvezi tabelele într-un fișier. Din consola serverului (nu din MySQL):
mysqldump -u root -p player shop shop_item > /root/backup_shop_2026-11-02.sqlÎți cere parola (o scrii, nu se vede pe ecran). Dacă ceva iese prost, cu acest fișier aduci tabelele înapoi exact cum erau. Detalii în lecția despre backup.
Pasul 3: Adaugă itemul
Exemplu: vrei ca magazinul 3 să vândă și un pachet mare de 100 de Red Potion(M) (VNUM 27002):
INSERT INTO shop_item (shop_vnum, item_vnum, count) VALUES (3, 27002, 100);
SELECT * FROM shop_item WHERE shop_vnum = 3 AND item_vnum = 27002;Al doilea rând verifică imediat că inserarea a reușit. Dacă primești o eroare de tip „Duplicate entry”, combinația magazin + item + cantitate există deja: în pachetul verificat, tabelul nu permite de două ori același trio.
Pasul 4: Repornește și verifică
Magazinele sunt citite de procesul db la pornire și trimise canalelor. În pachetul verificat, comanda /reload nu reîncarcă magazinele. Așa că oprești și pornești serverul de test.
Apoi, în joc:
- Mergi la NPC-ul 9003 și deschide magazinul.
- Caută pachetul nou și citește prețul.
- Cumpără-l și verifică yang-ul: a scăzut exact cu prețul afișat?
- Verifică în inventar că ai primit 100 de bucăți.
Ce ar trebui să vezi: itemul nou în magazin, cu prețul 96 × 100 = 9.600 yang (în pachetul verificat, Red Potion(M) are prețul 96 pe bucată în item_proto).
De unde vine prețul
Nu ai pus niciun preț în shop_item, și totuși itemul are unul. În sursa verificată, prețul unui item de la NPC se calculează așa: prețul pe bucată din item_proto × numărul de bucăți din pachet. Deci dacă vrei alt preț, schimbi item_proto, nu magazinul. Despre asta, pe larg, în lecția despre prețuri și restricții la magazine.
Limite de știut
| Limită | De ce contează |
|---|---|
| Maximum 40 de căsuțe pe magazin | Fereastra are 40 de locuri. Un item mare (sabie, armură) ocupă 2–3 căsuțe. Dacă nu mai e loc, itemul nu apare. |
| Ordinea e după VNUM | În pachetul verificat, itemele sunt așezate automat după număr. Nu alegi tu poziția. |
count maxim 255 | Coloana e mică (un număr de la 0 la 255). Un pachet de 500 nu merge. |
npc_vnum maxim 32767 | Coloana e de tip „număr mic”. Un NPC cu VNUM mai mare nu poate fi legat direct aici. |
Când nu apare itemul
| Ce vezi | Ce înseamnă | Ce faci |
|---|---|---|
| Itemul lipsește din magazin | Nu ai repornit sau ai pus alt shop_vnum. | Repornește; verifică cu SELECT. |
În syserr scrie „Shop: no item table by item vnum” | VNUM-ul itemului nu există în item_proto. | Corectează numărul. |
În syserr scrie „not enough shop window” | Magazinul e plin (40 de căsuțe). | Scoate ceva sau folosește alt magazin. |
| NPC-ul arată un meniu de dialog în loc de magazin | Ai un quest pe acel NPC. | Vezi secțiunea de mai jos. |
Capcana questurilor pe negustori
În sursa verificată, când dai click pe un NPC, serverul verifică întâi questurile. Dacă NPC-ul are măcar o opțiune de quest, apare meniul de dialog, iar magazinul nu se mai deschide singur. Exact așa face pachetul la pescar: questul lui are o opțiune care deschide magazinul cu npc.open_shop().
Deci, dacă pui un quest pe un negustor, adaugă-i și o opțiune „Magazin”:
quest magazin_negustor begin
state start begin
when 9003.chat."Magazin" begin
npc.open_shop()
setskin(NOWINDOW)
end
end
endnpc.open_shop() deschide magazinul NPC-ului, iar setskin(NOWINDOW) închide fereastra de dialog. Despre questuri, de la zero, în primul tău quest Lua.
Greșeli des întâlnite
- Cauți marfa într-un fișier text. În pachetele clasice e în baza de date. Verifică întâi tabelele.
- Confunzi numărul magazinului cu numărul NPC-ului.
shop_vnume magazinul (3), nu negustorul (9003). - Modifici direct pe serverul cu jucători. Un
DELETEgreșit golește toate magazinele. Lucrează pe test, cu backup. - Uiți de restart. Fără repornire, schimbarea nu se vede.
- Pui un item fără să te gândești la economie. Un item rar vândut la NPC își pierde valoarea pentru totdeauna.
Întrebări frecvente
Pot scoate un item din magazin?
Da, cu DELETE FROM shop_item WHERE shop_vnum = 3 AND item_vnum = 27002 AND count = 100;. Pune toate trei condițiile, ca să nu ștergi mai mult decât vrei. Rulează întâi același rând cu SELECT * FROM în loc de DELETE FROM, ca să vezi ce va fi șters.
Trebuie să modific și clientul?
Pentru un item care există deja, de obicei nu: lista și prețul vin de la server. Dacă itemul e nou, clientul trebuie să-l cunoască (vezi lecția despre itemul nou pe server și client).
Pot face un magazin nou pentru alt NPC?
Da: adaugi un rând în shop cu un număr liber de magazin și VNUM-ul NPC-ului, apoi marfa în shop_item. NPC-ul trebuie să existe pe hartă. Cum creezi unul afli în lecția următoare.
Ce urmează
Mai departe: cum creezi un NPC nou cu dialog și recompensă. 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ă.