Skip to content

Market and Player Trading

This guide shows how to change the player market (the “trade” window where players sell gear to each other for peso). It covers the fees, the level limits, the listing time, the minimum price, and the rule that decides which gear may be listed. Read it with Gear Upgrade and Compound Rates and Gacha Boxes, because the gear boxes decide whether a gear can be sold.

All file names below come from the source code that loads them. Anything marked not confirmed yet was not verified in code or config. The market sells gear only (PRESENT_EXTRAITEM). User::OnTradeCreate returns an error for any other type.

Part File Read by
Fees, levels, listing time ls_gamesvr\config\sp2_trade_info.ini, section [common] TradeInfoManager.cpp (ls_gamesvr\NodeInfo\)
Same values for the window, plus the minimum price config\sp2_trade_info.ini in the client TradeInfoManager.cpp (LSClient\)
Who may sell which gear sp2_extraitem_info.ini (item<n>_trade, tradetype*) ioExtraItemInfoManager.cpp
Unlock item etc item type 1000046 ioEtcItemTradeStateChange::_OnUse (ioEtcItem.cpp)
Mail texts for sold, cancelled and expired offers sp2_present_helper.ini, section [TradePresent] ioPresentHelper::LoadTradePresent
List storage table userTradeDB and procedures game_trade_* DB scripts in the testbed db\ folders

The server owns the money. The client file gives the window the same numbers for display and holds one rule the server does not check (the minimum price). After every change, compare the server and client files.

[common]
Change = 1
register_period = 30
register_limit_level = 20
item_buy_limit_level = 15
register_tex = 0.05f
buy_tex = 0.1f
pc_room_register_tex = 0.025f
pc_room_buy_tex = 0.05f
Key Used for Server Client
register_period How long an offer stays listed (days is the likely unit; the unit is not stated in code) yes yes (window text)
register_limit_level Level needed to list gear yes no use found in the client windows
item_buy_limit_level Level needed to buy yes yes
register_tex Listing fee, a fraction of the price. 0.05 means 5 percent yes yes
buy_tex Extra charge for the buyer, a fraction of the price yes yes
pc_room_register_tex, pc_room_buy_tex Same fees for internet cafe players yes yes
Change Reload flag read by CheckNeedReload yes no
register_limit_peso Minimum price of an offer not read yes
trade_state_change_item_level Level needed to use the unlock item not read yes
trade_list_request_time Milliseconds between list refreshes (default 60000) not read yes

Notes from the code:

  • The server uses the key register_tex, the file spells it “tex” for tax. Keep the spelling.
  • Listing: User::OnTradeCreate checks the grade level against register_limit_level, then charges price * register_tex as peso. If the player has less, the error is TRADE_CREATE_PESO. The gear is deleted from the inventory and the row goes to userTradeDB with the listing time.
  • Buying: the buyer needs price + price * buy_tex (ServerNode::OnTradeGetInfoOK). The server takes that amount. The seller is paid through the postbox (mail text id from TradeSellMent, TRADE_S_SELL_COMPLETE in ServerNode.cpp). The exact seller amount was not traced to the end. Not confirmed yet.
  • Minimum price: only the client enforces register_limit_peso (TradeItemRegisterWnd.cpp). The player types the price in units of 10000 peso. The server code of OnTradeCreate has no price check, so a changed client could list below the minimum. A maximum price: not confirmed yet.
  • The shipped client file has register_limit_peso = 50000 and trade_state_change_item_level = 20.
  1. Edit sp2_trade_info.ini on the server. Keep Change = 1. The line that would reset the flag is commented out, so the file is reloaded at each check while the flag is 1. How often the check runs: not confirmed yet.
  2. Edit the client file with the same values for register_period, register_limit_level, item_buy_limit_level, register_tex, buy_tex and the two internet cafe values. The window shows the fee from the client copy, but the server charges its own.
  3. Set register_limit_peso and trade_state_change_item_level in the client file only.
  4. If the two files differ, the window shows one fee and the server takes another. This is the most common market mistake.

To close the market for a version, the simplest way found in the code is the gear rule below (no gear can be listed). A switch that hides the trade window: not confirmed yet.

A gear carries a trade state (m_iTradeState in ioUserExtraItem.h):

Value Name Meaning
0 EET_DISABLE cannot be traded
1 EET_NORMAL tradable after it is unlocked
2 EET_ENABLE can be listed now
3 EET_REGISTER is listed

OnTradeCreate only accepts state 2. A gear gets its state in one of three ways:

  1. From the gear box. In sp2_extraitem_info.ini each [random_machineN] has tradetype_cnt and groups tradetypeN_rateK and tradetypeN_valueK (K from 1 to 3, TRADE_TYPE_MAX). Each item line item<n>_trade picks the group (default 1). The roll uses the rates as weights and the value as the state.

    tradetype_cnt = 1
    tradetype1_rate1 = 100
    tradetype1_value1 = 0
    tradetype1_rate2 = 0
    tradetype1_value2 = 1

    In the 2021 testbed file, 144 rate rows are above 0, and the values used are 0 (no trade), 1 and 2. The first group above gives state 0 with 100 percent, so those gears can never be sold.

  2. By the unlock item. Etc item 1000046 (EIT_ETC_TRADE_STATE_CHANGE) turns a gear with state 1 into state 2. It refuses a gear in another state and a gear that a hero wears (TRADE_STATE_CHANGE_EQUIP_ITEM). The item is used up. The client requires trade_state_change_item_level.

  3. After a failed or expired offer. When an offer is cancelled or expires, the gear returns as a postbox present and gets state 2 again (User.cpp, PRESENT_TRADE_CANCEL_MENT and PRESENT_TRADE_TIMEOUT_MENT). Only permanent gear (period 0) gets this.

Power-up sets the state back to 0 (ioPowerUpManager.cpp). Gear received as a present is created with state 0, except returned market gear (User.cpp).

To make a gear box give sellable gear, set a group with valueK = 2 for state 2, or valueK = 1 and let players buy the unlock item.

sp2_present_helper.ini section [TradePresent] holds the postbox text ids for buy, sell, cancel and time out (TradeBuyMent, TradeSellMent, TradeCancelMent, TradeTimeOutMent). The shipped values are 37 to 40 in all three versions. The texts themselves are in the client text table. See Client Text and Translation. The keys PresentAlarm, SellPresentAlarm and PresentPeriod are read too. Their values in the shipped file were not checked. Not confirmed yet.

The list lives in userTradeDB (columns idx, accountIDX, itemType, value1, value2, price, mcustom, fcustom, userIP, periodDate, regDate). The procedures are game_trade_add, game_trade_delete, game_trade_get_list and game_trade_get_self_index. The 2019 and 2021 scripts also have game_trade_get_list_original, and a log table log_data_trade. value1 and value2 hold the gear code and the level. The list page is read newest first (idx descending). How the expiry is triggered: not confirmed yet.

2014 2019 2021
Server code of TradeInfoManager and OnTradeCreate same keys same keys same keys
Fees in the shipped server file register_tex 0.01, buy_tex 0.01 0.05, 0.1 (testbed) 0.05, 0.1
Client sp2_trade_info.ini packed, not read packed, not read register_limit_peso = 50000
tradetype value 2 rows in the testbed gear file 48 52 52
game_trade_get_list_original procedure no yes yes
Log table log_data_trade stub only yes yes

The 2014 testbed file also has a commented alternate register_limit_level of 99. The 2014 server fees are low (1 percent). Whether the 2014 client shows the same fees: not confirmed yet, its file is packed.

  1. Reload or restart the game server. A client file change needs a client restart.
  2. List a gear with a test account that has the level and state 2. Check the peso drop equals the price times register_tex.
  3. Buy it with a second test account. Check the peso drop equals the price times 1 + buy_tex.
  4. Wait for or shorten the listing time to test the return mail. Check that the gear comes back with state 2.

Not confirmed yet: the exact reload interval, the seller payout amount, the maximum price, and the 2014 and 2019 client file contents.