Shop System
The Shop system controls what items NPCs sell in their shops. It uses a two-file pattern: a central registry (ShopManager.xml) that maps NPCs to shop files, and individual shop files (Shop/*.xml) that define item inventories.
See also: Data overview for where this fits in the shared game content.
File Locations#
- Registry:
Data/ShopManager.xml - Shop Files:
Data/Shop/NNN - ShopName.xml
Where NNN is a 3-digit shop index (000-999).
Configuration Pattern#
Step 1: Register Shop in ShopManager.xml#
Define which NPC uses which shop file.
<ShopList>
<Shop Index="0" Npc="251" Map="*" X="*" Y="*"/>
</ShopList>
| Attribute | Type | Description |
|---|---|---|
Index | int | Shop index. Must match the shop file name prefix (e.g., 000, 001). Index values are stored in a map keyed by Index, so each Index must be unique in ShopManager.xml. Filenames are limited to 3 digits (000-999) |
Npc | int/string | NPC class ID that opens this shop. Use "*" to match any NPC (converted to -1 internally) |
Map | int/string | Map number where this shop is available. Use "*" to match any map (converted to -1 internally) |
X | int/string | X coordinate where this shop is available. Use "*" to match any X (converted to -1 internally) |
Y | int/string | Y coordinate where this shop is available. Use "*" to match any Y (converted to -1 internally) |
Step 2: Create Shop File#
Create Data/Shop/NNN - Description.xml where NNN matches the Index from ShopManager.xml.
Shop File Structure#
Individual shop files define the items available for purchase. Items can be listed directly under <Shop>, or grouped into <Page> elements for multi-page shops.
Flat Layout (Single Page)#
<?xml version="1.0"?>
<Shop>
<Item Cat="0" Index="4" Level="7" Durability="0" Duration="0" Skill="1" Luck="0" Option="0"
Excellent="48" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
<!-- More items... -->
</Shop>
Multi-Page Layout#
Use <Page> elements to organize items across multiple pages. Each <Page> starts a new shop page. Up to 8 pages are supported.
<?xml version="1.0"?>
<Shop>
<Page>
<!-- Page 1: Weapons -->
<Item Cat="0" Index="4" Level="7" Durability="0" Duration="0" Skill="1" Luck="0" Option="0"
Excellent="48" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
</Page>
<Page>
<!-- Page 2: Armor -->
<Item Cat="7" Index="0" Level="5" Durability="0" Duration="0" Skill="0" Luck="0" Option="0"
Excellent="0" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
</Page>
</Shop>
Item Attributes#
| Attribute | Type | Default | Description |
|---|---|---|---|
Cat | int | - | Item category (0-15). See Item.xml for categories |
Index | int | - | Item index within category. Together with Cat, identifies the item |
Level | int | 0 | Item level (0-15). Adds stats and level requirement |
Durability | int | 0 | For regular items: durability (0 = use default). For stackable items: stack count (0 = 1) |
Duration | int | 0 | Temporary item duration in seconds (0 = permanent). See Temporary Items |
Skill | int | 0 | Has skill (1 = yes, 0 = no). Adds +skill option and enables special attacks |
Luck | int | 0 | Has Luck (1 = yes, 0 = no). Adds critical damage chance |
Option | int | 0 | Additional option level (0-7). Each level adds 4 to primary stat |
Excellent | int | 0 | Excellent option flags (bitwise). See Excellent Options section |
Ancient | int | 0 | Ancient item ID (0 = none). See Ancient item configuration |
JOH | int | 0 | Jewel of Harmony option index (0 = none) |
OpEx | int | 0 | 380 item option index (0 = none) |
Socket1 | int | 255 | Socket 1 option index (255 = empty socket) |
Socket2 | int | 255 | Socket 2 option index (255 = empty socket) |
Socket3 | int | 255 | Socket 3 option index (255 = empty socket) |
Socket4 | int | 255 | Socket 4 option index (255 = empty socket) |
Socket5 | int | 255 | Socket 5 option index (255 = empty socket) |
Excellent Options (Bitwise Flags)#
The Excellent attribute uses bitwise flags (0-63). Add values together for multiple options:
| Bit | Value | Description |
|---|---|---|
| 0 | 1 | Excellent option 1 |
| 1 | 2 | Excellent option 2 |
| 2 | 4 | Excellent option 3 |
| 3 | 8 | Excellent option 4 |
| 4 | 16 | Excellent option 5 |
| 5 | 32 | Excellent option 6 |
Example: Excellent="48" (32 + 16) = Options 5 and 6 enabled
Actual option effects are defined in ItemOption.xml and vary by item type:
- Weapons: Typically include Mana/HP per kill, attack speed, damage bonuses
- Armor/Shields: Typically include HP/Mana boosts, defense, damage reduction
- Wings: May include max HP%, attack speed, or other special effects
Temporary Items#
The Duration attribute creates time-limited items that expire after a set number of seconds. When a player purchases a temporary item, the server tracks its remaining lifetime.
| Duration Value | Meaning |
|---|---|
0 | Permanent item (default) |
3600 | 1 hour |
86400 | 1 day (24 hours) |
604800 | 1 week (7 days) |
2592000 | 30 days |
Example: A 7-day temporary weapon:
<Item Cat="0" Index="4" Level="9" Durability="0" Duration="604800" Skill="1" Luck="1" Option="4"
Excellent="63" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
Shop Matching Algorithm#
When a player clicks an NPC, the server uses a two-pass algorithm to find the correct shop:
Pass 1: Exact Match#
Finds the first shop where ALL four fields match exactly:
Npc== NPC class IDMap== map numberX== X coordinateY== Y coordinate
Wildcards ("*") are converted to -1 during loading, so a shop with Map="*" will only match if the actual map number is -1 (invalid), not "any map".
Pass 2: NPC-Only Match#
If Pass 1 fails, finds the first shop where:
Npc== NPC class IDNpcis NOT-1(not a wildcard)Map,X,Yare completely ignored
No Match#
If neither pass succeeds, the NPC has no shop and the interaction fails.
Item Pricing#
Shop items use pricing defined in ItemValue.xml. The currency system works as follows:
Currency Selection (priority order, highest first):
- GoblinPoints - If
Coin3toggle is set in ItemValue.xml - WCoinP (Premium coins) - If
Coin2toggle is set - WCoinC (Cash shop coins) - If
Coin1toggle is set - Zen (default) - If no coin toggles are set
Price Multipliers:
- Stackable items: Buy/sell prices multiply by stack count automatically
- Non-stackable items: Use base prices from ItemValue.xml
- Items without ItemValue.xml entries use calculated prices from item properties
See ItemValue documentation for details on configuring custom prices and currency types.
Dependencies#
| File | Purpose |
|---|---|
| Item.xml | Defines all available items, categories, and base stats |
| ItemValue.xml | Defines custom buy/sell prices and currency types (Zen/WCoinC/WCoinP/GP) |
| ItemStack.xml | Defines which items are stackable and their maximum stack sizes |
| SocketItemType.xml | Defines which items can have sockets and maximum socket count |
| SocketItemOption.xml | Defines socket option effects |
| SetItemOption.xml | Defines ancient set bonuses |
Examples#
<?xml version="1.0"?>
<Shop>
<!-- Basic sword with skill, no options -->
<Item Cat="0" Index="4" Level="0" Durability="0" Duration="0" Skill="1" Luck="0" Option="0"
Excellent="0" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
<!-- Enhanced sword: +7, +Luck, +2 option, Excellent (Mana/kill + Attack speed) -->
<Item Cat="0" Index="4" Level="7" Durability="0" Duration="0" Skill="1" Luck="1" Option="2"
Excellent="7" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
</Shop>
<?xml version="1.0"?>
<Shop>
<!-- Stackable potions: Durability = stack count -->
<Item Cat="14" Index="0" Level="0" Durability="10" Duration="0" Skill="0" Luck="0" Option="0"
Excellent="0" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
<Item Cat="14" Index="1" Level="0" Durability="10" Duration="0" Skill="0" Luck="0" Option="0"
Excellent="0" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
<!-- Mana potions -->
<Item Cat="14" Index="4" Level="0" Durability="10" Duration="0" Skill="0" Luck="0" Option="0"
Excellent="0" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
</Shop>
<!-- ShopManager.xml -->
<ShopList>
<!-- Event vendor only appears at specific location -->
<Shop Index="25" Npc="620" Map="0" X="124" Y="143"/>
<!-- Same NPC at different location has different shop -->
<Shop Index="26" Npc="620" Map="0" X="130" Y="150"/>
</ShopList>
Each shop index (25, 26) has its own shop file with different items.
<?xml version="1.0"?>
<Shop>
<!-- Ancient item (full set bonus when equipped) -->
<Item Cat="0" Index="19" Level="9" Durability="0" Duration="0" Skill="1" Luck="1" Option="4"
Excellent="0" Ancient="5" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
</Shop>
Ancient="5" refers to an ancient set defined in SetItemOption.xml.
<?xml version="1.0"?>
<Shop>
<Page>
<!-- Page 1: Swords -->
<Item Cat="0" Index="0" Level="3" Durability="0" Duration="0" Skill="1" Luck="0" Option="0"
Excellent="0" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
<Item Cat="0" Index="4" Level="5" Durability="0" Duration="0" Skill="1" Luck="0" Option="2"
Excellent="0" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
</Page>
<Page>
<!-- Page 2: Armor -->
<Item Cat="7" Index="0" Level="3" Durability="0" Duration="0" Skill="0" Luck="0" Option="0"
Excellent="0" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
<Item Cat="8" Index="0" Level="3" Durability="0" Duration="0" Skill="0" Luck="0" Option="0"
Excellent="0" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
</Page>
<Page>
<!-- Page 3: Consumables -->
<Item Cat="14" Index="0" Level="0" Durability="20" Duration="0" Skill="0" Luck="0" Option="0"
Excellent="0" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
</Page>
</Shop>
Each <Page> creates a separate page in the shop UI. The client displays page navigation (1/3, 2/3, 3/3). Up to 8 pages supported.
<?xml version="1.0"?>
<Shop>
<!-- 7-day trial weapon: full options, temporary -->
<Item Cat="0" Index="19" Level="11" Durability="0" Duration="604800" Skill="1" Luck="1" Option="4"
Excellent="63" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
<!-- 30-day wings -->
<Item Cat="12" Index="0" Level="0" Durability="0" Duration="2592000" Skill="0" Luck="0" Option="0"
Excellent="0" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
<!-- Permanent item (Duration=0) for comparison -->
<Item Cat="14" Index="0" Level="0" Durability="20" Duration="0" Skill="0" Luck="0" Option="0"
Excellent="0" Ancient="0" JOH="0" OpEx="0"
Socket1="255" Socket2="255" Socket3="255" Socket4="255" Socket5="255"/>
</Shop>
Duration="604800" = 7 days in seconds. Duration="2592000" = 30 days. Duration="0" = permanent (default).
Important Behavior#
Filename Parsing#
The server only loads shop files matching the pattern NNN - Name.xml:
- First 3 characters MUST be digits (000-999)
- Must have space-dash-space (
-) separator after digits (character positions [3] = space, [4] = dash, [5] = space) - Filename must contain
.xml
Files like 1 - Shop.xml, 01 - Shop.xml, or Shop001.xml will NOT load.
Shop Capacity and Layout#
Each shop page has 120 slots arranged in a grid. A shop can have up to 8 pages, for a maximum of 960 total slots.
Per-Page Grid:
- 8 columns (X: 0-7)
- 15 rows (Y: 0-14)
- Total per page: 120 slots
Item Placement:
- Items auto-arrange left-to-right, top-to-bottom during loading
- Items occupy multiple slots based on their size (width × height from Item.xml)
- Example: A 2×3 item occupies 6 adjacent slots in the grid
- The server validates that items fit within grid boundaries (8 columns wide, 15 rows tall)
- If a page fills up, items automatically overflow to the next page
- When using
<Page>elements, each<Page>explicitly starts a new page
Slot Calculation: Slot = (Y × 8) + X
- Slot 0 = position (0, 0) - top-left
- Slot 7 = position (7, 0) - top-right
- Slot 119 = position (7, 14) - bottom-right
Stackable Items#
For stackable items (potions, jewels, etc.), the Durability attribute controls the stack count:
Durability="0"= 1 item (default)Durability="10"= stack of 10 itemsDurability="255"= stack of 255 items (maximum)
Price behavior:
- Buy price:
ItemValue.xml price × stack count - Sell price:
ItemValue.xml sell price × stack count - Prices automatically scale when buying/selling stacked items from shops
Socket Slots#
Set Socket1-Socket5 to 255 for empty sockets.
Important behavior:
- The server validates socket support using
SocketItemType.xmlbefore assigning sockets - Only items that support sockets (defined in SocketItemType.xml) will have socket slots allocated
- Socket slots are only assigned up to the maximum socket count for that item type
- Example: If an item supports 3 sockets, only
Socket1-Socket3are used;Socket4andSocket5are ignored
If an item doesn't support sockets, all socket attributes are ignored regardless of configuration values.
NPC Matching Priority#
Always use specific Map/X/Y when possible. Wildcard shops (Map="*") can cause unexpected behavior if multiple NPCs share the same class ID.
Common Issues#
Adding a New Shop#
- Choose Shop Index: Pick an unused index. The filename prefix supports 000-999
- Register in ShopManager.xml:
Use
<Shop Index="50" Npc="999" Map="0" X="100" Y="100"/>Map="*" X="*" Y="*"for global shops (any location). - Create Shop File:
Data/Shop/050 - My Custom Shop.xml- Filename MUST be exactly 3 digits, space-dash-space, description
- Shop index (50) must match filename prefix (050)
- Add Items: Use examples above as templates
- Configure Pricing (optional): Add entries to ItemValue.xml for custom prices/currencies
- Configure Stackables (optional): Ensure stackable items are defined in ItemStack.xml
- Reload shops: run
/reload shop(orreload.shopin the Server Manager), or restart the GameServer - Test: Click NPC to verify shop opens with correct items and prices