Update server_shop mod to Git commit 06f6691...
https://github.com/AntumMT/mod-server_shop/tree/06f6691
This commit is contained in:
parent
f2b9cf9073
commit
62821f6acb
@ -35,7 +35,7 @@ The game includes the mods from the default [minetest_game](https://github.com/m
|
||||
* commerce/
|
||||
* [atm][] ([GPL][lic.gpl3.0]) -- version: [1.0.4][ver.atm] *2021-04-21* ([patched][patch.atm])
|
||||
* [currency][] ([LGPL][lic.lgpl3.0] / [CC BY-SA][lic.ccbysa4.0]) -- version: [2021-01-30][ver.currency]
|
||||
* [server_shop][] ([MIT][lic.server_shop]) -- version: [f2ca797 Git][ver.server_shop] *2021-05-13*
|
||||
* [server_shop][] ([MIT][lic.server_shop]) -- version: [06f6691 Git][ver.server_shop] *2021-05-14*
|
||||
* core/
|
||||
* [antum][] ([MIT][lic.antum]) -- version: [69b39a4 Git][ver.antum] *2017-08-30*
|
||||
* [minetest_game][] ([LGPL][lic.lgpl2.1] / [CC BY-SA][lic.ccbysa3.0]) -- version: [5.4.1][ver.minetest_game] *2021-04-10*
|
||||
@ -551,7 +551,7 @@ The game includes the mods from the default [minetest_game](https://github.com/m
|
||||
[ver.pvp_areas]: https://github.com/everamzah/pvp_areas/tree/6e4d66d
|
||||
[ver.quartz]: https://github.com/minetest-mods/quartz/tree/72ec06f
|
||||
[ver.rainbow_ore]: https://github.com/FsxShader2012/rainbow_ore/tree/6e77693
|
||||
[ver.server_shop]: https://github.com/AntumMT/mod-server_shop/tree/f2ca797
|
||||
[ver.server_shop]: https://github.com/AntumMT/mod-server_shop/tree/06f6691
|
||||
[ver.sfinv_buttons]: http://repo.or.cz/minetest_sfinv_buttons.git/tree/ebb1f7c
|
||||
[ver.shark]: https://github.com/AntumMT/mod-shark/tree/ef2507b
|
||||
[ver.sheep]: https://github.com/AntumMT/mod-cmer/tree/ff39b4a
|
||||
|
@ -1,5 +1,10 @@
|
||||
|
||||
pre
|
||||
1.3
|
||||
- added buyer shops
|
||||
- changed json product list type to indexed array
|
||||
|
||||
|
||||
1.2
|
||||
- custom currencies can be registered
|
||||
- changed format of world "server_shops.json":
|
||||
- "sells" keyword changed to "products"
|
||||
|
@ -7,52 +7,54 @@ Shops intended to be set up by [Minetest](https://www.minetest.net/) server admi
|
||||
|
||||
No craft recipe is given as this for administrators, currently a machine can only be set up with `/giveme server_shop:shop` command.
|
||||
|
||||
***WARNING:** this mod is in early development, see [TODO](TODO.txt) list*
|
||||
|
||||
![screenshot](screenshot.png)
|
||||
|
||||
---
|
||||
### Usage:
|
||||
|
||||
#### Registering Shops & Currencies:
|
||||
#### Registering Shops:
|
||||
|
||||
Shop lists are registered with the `server_shop.register_shop(id, name, def)` function. `id` is a string identifier associated with the shop list. `name` is a human-readable string that will be displayed as the shop's title. `def` is the shop list definition. Shop lists are defined in a table of tuples in `{itemname, price}` format.
|
||||
There are two types of shops, seller & buyer. A seller shop can be registered with `server_shop.register_seller(id, name, def)`. A buyer with `server_shop.register_buyer(id, name, def)`. `id` is a string identifier associated with the shop list. `name` is a human-readable string that will be displayed as the shop's title. `def` is the shop list definition. Shop lists are defined in a table of tuples in `{itemname, value}` format. `itemname` is the technical string name of an item (e.g. `default:wood`). `value` is the number representation of what the item is worth.
|
||||
|
||||
Registration example:
|
||||
*Example:*
|
||||
```lua
|
||||
server_shop.register_shop("basic", "Basic Shop", {
|
||||
{
|
||||
{"default:wood", 2},
|
||||
{"default:obsidian", 7},
|
||||
}
|
||||
-- register seller
|
||||
server_shop.register_seller("frank", "Frank's Shop", {{"default:wood", 2}})
|
||||
|
||||
-- register buyer
|
||||
server_shop.register_buyer("julie", "Julie's Shop", {
|
||||
{"default:copper_lump", 5},
|
||||
{"default:iron_lump", 6},
|
||||
})
|
||||
```
|
||||
|
||||
Shops can optionally be configured in `<world_path>/server_shops.json` file. To register a seller shop (buyers currently not supported), set `type` to "sell". `id` is a string identifier for the shop. `name` is the string displayed in the formspec & when a player points at the node. `products` is a list of products sold at the shop in format "name:value".
|
||||
Shops can optionally be configured in `<world_path>/server_shops.json` file. To register a shop, set `type` to "sell" or "buy". `id` is a string identifier for the shop. `name` is the string displayed in the formspec & when a player points at the node. `products` is an array of products sold at the shop in format "name,value".
|
||||
|
||||
Example:
|
||||
*Example:*
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type":"sell",
|
||||
"id":"frank",
|
||||
"name":"Frank's Shop",
|
||||
"products":{"default:wood":1}
|
||||
"products":[["default:wood",2]]
|
||||
},
|
||||
{
|
||||
"type":"sell",
|
||||
"type":"buy",
|
||||
"id":"julie",
|
||||
"name":"Julie's Shop",
|
||||
"products":
|
||||
{
|
||||
"default:iron_lump":5,
|
||||
"default:copper_lump":5,
|
||||
}
|
||||
[
|
||||
["default:copper_lump",5],
|
||||
["default:iron_lump",6],
|
||||
]
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
Currencies can be registered with `server_shop.register_currency` (***Note:** Only currency values of 1, 5, 10, 50, & 100 are currently supported*):
|
||||
#### Registering Currencies:
|
||||
|
||||
Currencies can be registered with `server_shop.register_currency`:
|
||||
```lua
|
||||
server_shop.register_currency("currency:minegeld", 1)
|
||||
server_shop.register_currency("currency:minegeld_5", 5)
|
||||
@ -72,7 +74,12 @@ When registering a new currency in `server_shops.json`, set `type` to "currency"
|
||||
},
|
||||
```
|
||||
|
||||
You can also register a currency suffix to be displayed in the formspec. Simply set the value of `server_shop.currency_suffix`:
|
||||
***Notes:***
|
||||
- *Only currency values of 1, 5, 10, 50, & 100 are currently supported*
|
||||
- *Buyer shops currently do not work with custom currencies, only minegeld notes from currency mod supported*
|
||||
|
||||
You can also register a currency suffix to be displayed in the formspec. Simply set the string value of `server_shop.currency_suffix`:
|
||||
|
||||
```lua
|
||||
server_shop.currency_suffix = "MG"
|
||||
```
|
||||
@ -85,13 +92,19 @@ In `server_shops.json`, set `type` to "suffix" & `value` to the string to be dis
|
||||
},
|
||||
```
|
||||
|
||||
By default, if the [currency][mod.currency] mod is installed, the minegeld notes will be registered as currency. This can be disabled by setting `server_shop.use_currency_defaults` to `false` in `minetest.conf`.
|
||||
|
||||
#### Setting up Shops in Game:
|
||||
|
||||
Server admins use the chat command `/giveme server_shop:shop` to receive a shop node. After placing the node, the ID can be set with the "Set ID" button & text input field (only players with the "server" privilege can set ID). Set the ID to the shop ID you want associated with this shop node ("basic" for the example above) & the list will be populated with the registered products & prices.
|
||||
Server admins use the chat command `/giveme server_shop:sell` or `/giveme server_shop:buy` to receive a shop node. After placing the node, the ID can be set with the "Set ID" button & text input field (only players with the "server" privilege can set ID). Set the ID to the registered shop ID you want associated with this node ("frank" or "julie" for the examples above) & the list will be populated with the registered products & prices.
|
||||
|
||||
To make purchases, players deposit currency items into the deposit slot. Select an item to purchase & press the "Buy" button. If there is adequate money deposited, player will receive the item & the price will be deducted from the deposited amount. Press the "Refund" button to retrieve any money not spent.
|
||||
#### Using Seller Shops:
|
||||
|
||||
***SECURITY WARNING:*** As stated, this mod is in early development. Currently, it is possible to interfere in another player's transactions. So this mod is *not* recommended for use with public servers at this time.
|
||||
To make purchases, player first deposits registered currency items into the deposit slot. Select an item in the products list & press the "Buy" button. If there is adequate money deposited, player will receive the item & the cost will be deducted from the deposited amount. To retrieve any money not spent, press the "Refund" button. If the formspec is closed while there is still a deposit balance, the remaining money will be refunded back to the player. If there is not room in the player's inventory, the remaining balance will be dropped on the ground.
|
||||
|
||||
#### Using Buyer Shops:
|
||||
|
||||
For buyer shops, the product list shows what items can be sold to this shop & how much money a player will receive for each item. To sell to the shop, drop an item in the deposit slot. If the shop accepts the item, the value will be added to the deposited amount. Press the "Refund" button to retrieve the value of the items sold.
|
||||
|
||||
---
|
||||
### Licensing:
|
||||
@ -107,8 +120,6 @@ To make purchases, players deposit currency items into the deposit slot. Select
|
||||
- Optional:
|
||||
- [currency][mod.currency]
|
||||
|
||||
Compatible with:
|
||||
|
||||
---
|
||||
### Links:
|
||||
|
||||
|
@ -7,6 +7,7 @@ TODO:
|
||||
- optimize how refunds are given (e.g. if there is no room for 50s, but room for 1s, then give out 1s instead)
|
||||
- add shop for players to receive money for selling items
|
||||
- allow any currency value, not just 1, 5, 10, 50, & 100
|
||||
- allow custom currency types for buyer shops
|
||||
- Visuals:
|
||||
- touch up textures
|
||||
- fix texture tiling
|
||||
@ -16,3 +17,5 @@ TODO:
|
||||
- add localization support
|
||||
- add chat command to reload shops file in world directory
|
||||
- set shop name from formspec instead of registration so shops with different names can use same content
|
||||
- fix so unknown items don't mess up shop
|
||||
- don't set node meta data "id" if not a registered shop ID
|
||||
|
@ -6,11 +6,9 @@
|
||||
|
||||
local ss = server_shop
|
||||
|
||||
--- Registered shops.
|
||||
--
|
||||
-- @local
|
||||
-- @table shops
|
||||
local shops = {}
|
||||
local sellers = {}
|
||||
local buyers = {}
|
||||
local shops = sellers -- backward compat
|
||||
|
||||
--- Currencies registered for trade.
|
||||
--
|
||||
@ -23,7 +21,8 @@ ss.currency_suffix = nil
|
||||
--- Registers an item that can be used as currency.
|
||||
--
|
||||
-- TODO:
|
||||
-- - after registering currency, should re-organize table from highest value to lowest
|
||||
--
|
||||
-- - after registering currency, should re-organize table from highest value to lowest
|
||||
--
|
||||
-- @function server_shop.register_currency
|
||||
-- @tparam string item Item name.
|
||||
@ -67,34 +66,112 @@ if ss.use_currency_defaults then
|
||||
ss.currency_suffix = "MG"
|
||||
end
|
||||
|
||||
--- Registers a shop list to be accessed via a shop node.
|
||||
--- Checks ID string for invalid characters.
|
||||
--
|
||||
-- TODO:
|
||||
-- - log warning if `def` name or value missing or wrong type or
|
||||
-- if name is empty string
|
||||
-- @function server_shop.format_id
|
||||
-- @tparam string id Shop identifier string.
|
||||
-- @treturn string Formatted string.
|
||||
function ss.format_id(id)
|
||||
return id:trim():gsub("%s", "_")
|
||||
end
|
||||
|
||||
--- Registers a seller shop.
|
||||
--
|
||||
-- @function server_shop.register_shop
|
||||
-- @param id String ID associated with shop list.
|
||||
-- @param name Human readable name to be displayed.
|
||||
-- @param def Shop definition (e.g. items & prices)
|
||||
function ss.register_shop(id, name, def)
|
||||
if shops[id] then
|
||||
-- @function server_shop.register_seller
|
||||
-- @tparam string id Shop string identifier.
|
||||
-- @tparam string name Human readable name.
|
||||
-- @tparam table[string,int] def List of products & prices in format `{item_name, price}`.
|
||||
function ss.register_seller(id, name, def)
|
||||
if type(id) ~= "string" then
|
||||
ss.log("error", ss.modname .. ".register_seller: invalid \"id\" parameter")
|
||||
return
|
||||
elseif type(name) ~= "string" then
|
||||
ss.log("error", ss.modname .. ".register_seller: invalid \"name\" parameter")
|
||||
return
|
||||
elseif type(def) ~= "table" then
|
||||
ss.log("error", ss.modname .. ".register_seller: invalid \"def\" parameter")
|
||||
return
|
||||
end
|
||||
|
||||
id = ss.format_id(id)
|
||||
|
||||
if sellers[id] then
|
||||
ss.log("warning", "Overwriting shop with id: " .. id)
|
||||
end
|
||||
|
||||
local new_shop = {name=name, def=def,}
|
||||
shops[id] = new_shop
|
||||
sellers[id] = {name=name:trim(), def=def,}
|
||||
|
||||
ss.log("action", "Registered shop: " .. id)
|
||||
ss.log("action", "Registered seller shop: " .. id)
|
||||
end
|
||||
|
||||
--- Retrieves shop by ID.
|
||||
--- Registers a buyer shop.
|
||||
--
|
||||
-- @function server_shop.register_buyer
|
||||
-- @tparam string id Shop string identifier.
|
||||
-- @tparam string name Human readable name.
|
||||
-- @tparam table[string,int] def List of products & prices in format `{item_name, price}`.
|
||||
function ss.register_buyer(id, name, def)
|
||||
if type(id) ~= "string" then
|
||||
ss.log("error", ss.modname .. ".register_buyer: invalid \"id\" parameter")
|
||||
return
|
||||
elseif type(name) ~= "string" then
|
||||
ss.log("error", ss.modname .. ".register_buyer: invalid \"name\" parameter")
|
||||
return
|
||||
elseif type(def) ~= "table" then
|
||||
ss.log("error", ss.modname .. ".register_buyer: invalid \"def\" parameter")
|
||||
return
|
||||
end
|
||||
|
||||
id = ss.format_id(id)
|
||||
|
||||
if buyers[id] then
|
||||
ss.log("warning", "Overwriting buyer shop with id: " .. id)
|
||||
end
|
||||
|
||||
buyers[id] = {name=name:trim(), def=def,}
|
||||
|
||||
ss.log("action", "Registered buyer shop: " .. id)
|
||||
end
|
||||
|
||||
--- Registers a shop.
|
||||
--
|
||||
-- Added for backwards compatibility.
|
||||
--
|
||||
-- @function server_shop.register_shop
|
||||
-- @tparam string id Shop string identifier.
|
||||
-- @tparam string name Human readable name.
|
||||
-- @tparam table[string,int] def List of products & prices in format `{item_name, price}`.
|
||||
-- @tparam bool buyer Denotes whether to register seller or buyer shop (default: `false` (seller)).
|
||||
function ss.register_shop(id, name, def, buyer)
|
||||
if buyer then
|
||||
ss.register_buyer(id, name, def)
|
||||
else
|
||||
ss.register_seller(id, name, def)
|
||||
end
|
||||
end
|
||||
|
||||
--- Retrieves shop product list.
|
||||
--
|
||||
-- @function server_shop.get_shop
|
||||
-- @param id String identifier of shop.
|
||||
-- @return Table of shop contents.
|
||||
function ss.get_shop(id)
|
||||
return shops[id]
|
||||
-- @tparam string id String identifier of shop.
|
||||
-- @tparam bool buyer Denotes whether seller or buyer shops will be parsed (default: false).
|
||||
-- @treturn table Table of shop contents.
|
||||
function ss.get_shop(id, buyer)
|
||||
if buyer then
|
||||
return buyers[id]
|
||||
end
|
||||
|
||||
return sellers[id]
|
||||
end
|
||||
|
||||
--- Checks if a shop is registered.
|
||||
--
|
||||
-- @function server_shop.is_registered
|
||||
-- @tparam string id Shop string identifier.
|
||||
-- @tparam bool buyer Denotes whether to check seller or buyer shops (default: false).
|
||||
-- @tparam bool `true` if the shop ID is found.
|
||||
function ss.is_registered(id, buyer)
|
||||
return ss.get_shop(id, buyer) ~= nil
|
||||
end
|
||||
|
||||
--- Checks if a player has admin rights to for managing shop.
|
||||
|
@ -3,12 +3,13 @@ local ss = server_shop
|
||||
local transaction = dofile(ss.modpath .. "/transaction.lua")
|
||||
|
||||
|
||||
--- Calculates the value of an item stack.
|
||||
--- Calculates value of an item stack against registered currencies.
|
||||
--
|
||||
-- @local
|
||||
-- @function server_shop.calculate_value
|
||||
-- @function calculate_currency_value
|
||||
-- @tparam ItemStack stack Item stack.
|
||||
local function calculate_value(stack)
|
||||
-- @treturn int Total value of item stack.
|
||||
local function calculate_currency_value(stack)
|
||||
local value = 0
|
||||
|
||||
for c, v in pairs(ss.registered_currencies) do
|
||||
@ -21,19 +22,40 @@ local function calculate_value(stack)
|
||||
return value
|
||||
end
|
||||
|
||||
--- Calculates value of an item stack against a registered shop's product list.
|
||||
--
|
||||
-- @local
|
||||
-- @function calculate_product_value
|
||||
-- @tparam ItemStack stack Item stack.
|
||||
-- @tparam string id Shop id.
|
||||
-- @tparam bool buyer Determines whether to parse buyer shops or seller shops.
|
||||
-- @treturn int Total value of item stack.
|
||||
local function calculate_product_value(stack, id, buyer)
|
||||
local shop = ss.get_shop(id, buyer)
|
||||
if not shop then return 0 end
|
||||
|
||||
local callbacks = {
|
||||
local item_name = stack:get_name()
|
||||
local value_per = 0
|
||||
for _, product in ipairs(shop.def) do
|
||||
if item_name == product[1] then
|
||||
value_per = product[2]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return value_per * stack:get_count()
|
||||
end
|
||||
|
||||
|
||||
local seller_callbacks = {
|
||||
allow_put = function(inv, listname, index, stack, player)
|
||||
-- TODO: move this to `on_put`
|
||||
|
||||
local pmeta = player:get_meta()
|
||||
|
||||
local to_deposit = calculate_value(stack)
|
||||
if to_deposit <= 0 then return 0 end
|
||||
|
||||
local id = pmeta:get_string(ss.modname .. ":id")
|
||||
if id:trim() == "" then return 0 end
|
||||
|
||||
local to_deposit = calculate_currency_value(stack)
|
||||
if to_deposit <= 0 then return 0 end
|
||||
|
||||
local pos = core.deserialize(pmeta:get_string(ss.modname .. ":pos"))
|
||||
if not pos then return 0 end
|
||||
|
||||
@ -46,5 +68,29 @@ local callbacks = {
|
||||
end,
|
||||
}
|
||||
|
||||
local inv = core.create_detached_inventory(ss.modname, callbacks)
|
||||
inv:set_size("deposit", 1)
|
||||
local buyer_callbacks = {
|
||||
allow_put = function(inv, listname, index, stack, player)
|
||||
local pmeta = player:get_meta()
|
||||
local id = pmeta:get_string(ss.modname .. ":id")
|
||||
if id:trim() == "" then return 0 end
|
||||
|
||||
local to_deposit = calculate_product_value(stack, id, true)
|
||||
if to_deposit <= 0 then return 0 end
|
||||
|
||||
local pos = core.deserialize(pmeta:get_string(ss.modname .. ":pos"))
|
||||
if not pos then return 0 end
|
||||
|
||||
transaction.set_deposit(id, player, transaction.get_deposit(id, player, true) + to_deposit, true)
|
||||
|
||||
-- refresh formspec dialog
|
||||
ss.show_formspec(pos, player, true)
|
||||
|
||||
return -1
|
||||
end,
|
||||
}
|
||||
|
||||
local sinv = core.create_detached_inventory(ss.modname .. ":sell", seller_callbacks)
|
||||
sinv:set_size("deposit", 1)
|
||||
|
||||
local binv = core.create_detached_inventory(ss.modname .. ":buy", buyer_callbacks)
|
||||
binv:set_size("deposit", 1)
|
||||
|
@ -7,14 +7,18 @@ local fs_height = 11
|
||||
local btn_w = 1.75
|
||||
local btn_y = 4.6
|
||||
|
||||
local transaction = dofile(ss.modpath .. "/transaction.lua")
|
||||
|
||||
|
||||
--- Retrieves shop name by ID.
|
||||
--
|
||||
-- @local
|
||||
-- @function get_shop_name
|
||||
-- @tparam string id String identifier of shop.
|
||||
-- @tparam bool buyer
|
||||
-- @treturn string Shop's name representation.
|
||||
local function get_shop_name(id)
|
||||
local shop = ss.get_shop(id)
|
||||
local function get_shop_name(id, buyer)
|
||||
local shop = ss.get_shop(id, buyer)
|
||||
if shop then
|
||||
return shop.name
|
||||
end
|
||||
@ -26,9 +30,10 @@ end
|
||||
-- @function get_shop_index
|
||||
-- @param shop_id String identifier of shop.
|
||||
-- @param idx Index of the item to retrieve.
|
||||
-- @tparam bool buyer
|
||||
-- @return String item identifier or `nil` if shop does not contain item.
|
||||
local function get_shop_index(shop_id, idx)
|
||||
local shop = ss.get_shop(shop_id)
|
||||
local function get_shop_index(shop_id, idx, buyer)
|
||||
local shop = ss.get_shop(shop_id, buyer)
|
||||
if shop then
|
||||
local product = shop.def[idx]
|
||||
if product then
|
||||
@ -42,10 +47,11 @@ end
|
||||
-- @local
|
||||
-- @function get_product_list
|
||||
-- @param id String identifier of shop.
|
||||
-- @tparam bool buyer
|
||||
-- @return String of shop contents.
|
||||
local function get_product_list(id)
|
||||
function get_product_list(id, buyer)
|
||||
local products = ""
|
||||
local shop = ss.get_shop(id)
|
||||
local shop = ss.get_shop(id, buyer)
|
||||
|
||||
if shop and shop.def then
|
||||
for _, p in ipairs(shop.def) do
|
||||
@ -53,51 +59,71 @@ local function get_product_list(id)
|
||||
|
||||
if not item then
|
||||
core.log("warning", "Unknown item \"" .. p[1] .. "\" for shop ID \"" .. id .. "\"")
|
||||
goto continue
|
||||
end
|
||||
|
||||
local item_name = item.short_description
|
||||
if not item_name then
|
||||
item_name = item.description
|
||||
else
|
||||
local item_name = item.short_description
|
||||
if not item_name then
|
||||
item_name = p[1]
|
||||
item_name = item.description
|
||||
if not item_name then
|
||||
item_name = p[1]
|
||||
end
|
||||
end
|
||||
|
||||
local item_price = p[2]
|
||||
if not item_price then
|
||||
core.log("warning", "Price not set for item \"" .. p[1] .. "\" for shop ID \"" .. id .. "\"")
|
||||
elseif products == "" then
|
||||
products = item_name .. " : " .. tostring(item_price) .. " MG"
|
||||
else
|
||||
products = products .. "," .. item_name .. " : " .. tostring(item_price) .. " MG"
|
||||
end
|
||||
end
|
||||
|
||||
local item_price = p[2]
|
||||
if not item_price then
|
||||
core.log("warning", "Price not set for item \"" .. p[1] .. "\" for shop ID \"" .. id .. "\"")
|
||||
goto continue
|
||||
end
|
||||
|
||||
if products == "" then
|
||||
products = item_name .. " : " .. tostring(item_price) .. " MG"
|
||||
else
|
||||
products = products .. "," .. item_name .. " : " .. tostring(item_price) .. " MG"
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
return products
|
||||
end
|
||||
|
||||
--- Gets string formatted for use with form names.
|
||||
--
|
||||
-- @local
|
||||
-- @function format_formname
|
||||
-- @tparam bool buyer Denotes buyer or seller (default: `false` (seller)).
|
||||
local function format_formname(buyer)
|
||||
if buyer then
|
||||
return ss.modname .. ":buy"
|
||||
end
|
||||
|
||||
return ss.modname .. ":sell"
|
||||
end
|
||||
|
||||
--- Retrieves formspec layout.
|
||||
--
|
||||
-- @function server_shop.get_formspec
|
||||
-- @param pos
|
||||
-- @param player
|
||||
function ss.get_formspec(pos, player)
|
||||
-- @tparam bool buyer
|
||||
-- @treturn string Formspec formatted string.
|
||||
function ss.get_formspec(pos, player, buyer)
|
||||
buyer = buyer == true
|
||||
|
||||
local smeta = core.get_meta(pos)
|
||||
local pmeta = player:get_meta()
|
||||
local id = smeta:get_string("id")
|
||||
local deposited = pmeta:get_int(ss.modname .. ":" .. id .. ":deposited")
|
||||
local deposited = transaction.get_deposit(id, player, buyer)
|
||||
|
||||
-- store ID in player meta for retrieval during transactions
|
||||
pmeta:set_string(ss.modname .. ":id", id)
|
||||
|
||||
local formspec = "formspec_version[4]size[" .. tostring(fs_width) .. "," .. tostring(fs_height) .."]"
|
||||
local is_registered = ss.is_registered(id, buyer)
|
||||
local margin_r = fs_width-(btn_w+0.2)
|
||||
local btn_refund = "button[0.2," .. tostring(btn_y) .. ";"
|
||||
.. tostring(btn_w) .. ",0.75;btn_refund;Refund]"
|
||||
local btn_buy = "button[" .. tostring(margin_r) .. ","
|
||||
.. tostring(btn_y) .. ";" .. tostring(btn_w)
|
||||
.. ",0.75;btn_buy;Buy]"
|
||||
|
||||
local formspec = "formspec_version[4]"
|
||||
.. "size[" .. tostring(fs_width) .. "," .. tostring(fs_height) .."]"
|
||||
|
||||
local shop_name = smeta:get_string("name"):trim()
|
||||
if shop_name ~= "" then
|
||||
@ -121,8 +147,7 @@ function ss.get_formspec(pos, player)
|
||||
|
||||
-- get item name for displaying image
|
||||
local selected_item = nil
|
||||
local shop = ss.get_shop(id)
|
||||
|
||||
local shop = ss.get_shop(id, buyer)
|
||||
if shop then
|
||||
-- make sure we're not out of range of the shop list
|
||||
if selected_idx > #shop.def then
|
||||
@ -135,8 +160,6 @@ function ss.get_formspec(pos, player)
|
||||
end
|
||||
end
|
||||
|
||||
local margin_r = fs_width-(btn_w+0.2)
|
||||
|
||||
formspec = formspec
|
||||
.. "label[0.2,1;Deposited: " .. tostring(deposited)
|
||||
if ss.currency_suffix and ss.currency_suffix ~= "" then
|
||||
@ -144,11 +167,15 @@ function ss.get_formspec(pos, player)
|
||||
end
|
||||
formspec = formspec .. "]"
|
||||
|
||||
if id ~= "" then -- don't allow deposits to unregistered stores
|
||||
formspec = formspec .. "list[detached:" .. ss.modname .. ";deposit;0.2,1.5;1,1;0]"
|
||||
if is_registered then -- don't allow deposits to unregistered stores
|
||||
local inv_type = format_formname(false)
|
||||
if buyer then inv_type = format_formname(true) end
|
||||
|
||||
formspec = formspec .. "list[detached:" .. inv_type .. ";deposit;0.2,1.5;1,1;0]"
|
||||
end
|
||||
|
||||
formspec = formspec .. "textlist[2.15,1.5;9.75,3;products;" .. get_product_list(id) .. ";"
|
||||
formspec = formspec .. "textlist[2.15,1.5;9.75,3;products;"
|
||||
.. get_product_list(id, buyer) .. ";"
|
||||
.. tostring(selected_idx) .. ";false]"
|
||||
|
||||
if selected_item and selected_item ~= "" then
|
||||
@ -156,16 +183,20 @@ function ss.get_formspec(pos, player)
|
||||
.. "item_image[" .. tostring(fs_width-1.2) .. ",1.5;1,1;" .. selected_item .. "]"
|
||||
end
|
||||
|
||||
formspec = formspec
|
||||
.. "button[0.2," .. tostring(btn_y) .. ";" .. tostring(btn_w) .. ",0.75;btn_refund;Refund]"
|
||||
.. "button[" .. tostring(margin_r) .. "," .. tostring(btn_y) .. ";" .. tostring(btn_w) .. ",0.75;btn_buy;Buy]"
|
||||
.. "list[current_player;main;2.15,5.5;8,4;0]"
|
||||
.. "button_exit[" .. tostring(margin_r) .. ",10;" .. tostring(btn_w) .. ",0.75;btn_close;Close]"
|
||||
local formname = "server_shop"
|
||||
if id and id ~= "" then
|
||||
formname = formname .. "_" .. id
|
||||
if is_registered then
|
||||
formspec = formspec .. btn_refund
|
||||
|
||||
-- buyers don't need a "Buy" button
|
||||
if not buyer then formspec = formspec .. btn_buy end
|
||||
end
|
||||
|
||||
formspec = formspec .. "list[current_player;main;2.15,5.5;8,4;0]"
|
||||
.. "button_exit[" .. tostring(margin_r) .. ",10;" .. tostring(btn_w) .. ",0.75;btn_close;Close]"
|
||||
|
||||
local formname = format_formname(false)
|
||||
if buyer then formname = format_formname(true) end
|
||||
if id and id ~= "" then formname = formname .. ":" .. id end
|
||||
|
||||
return formspec .. formname
|
||||
end
|
||||
|
||||
@ -174,15 +205,17 @@ end
|
||||
-- @function server_shop.show_formspec
|
||||
-- @param pos
|
||||
-- @param player
|
||||
function ss.show_formspec(pos, player)
|
||||
core.show_formspec(player:get_player_name(), ss.modname .. ":shop", ss.get_formspec(pos, player))
|
||||
-- @tparam bool buyer
|
||||
function ss.show_formspec(pos, player, buyer)
|
||||
core.show_formspec(player:get_player_name(), format_formname(buyer),
|
||||
ss.get_formspec(pos, player, buyer))
|
||||
end
|
||||
|
||||
|
||||
local transaction = dofile(ss.modpath .. "/transaction.lua")
|
||||
|
||||
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if formname == ss.modname .. ":shop" then
|
||||
if formname == format_formname(false) or formname == format_formname(true) then
|
||||
local buyer = formname == format_formname(true)
|
||||
|
||||
local pmeta = player:get_meta()
|
||||
local pos = core.deserialize(pmeta:get_string(ss.modname .. ":pos"))
|
||||
if not pos then
|
||||
@ -213,11 +246,11 @@ core.register_on_player_receive_fields(function(player, formname, fields)
|
||||
return false
|
||||
end
|
||||
|
||||
fields.input_id = fields.input_id:trim()
|
||||
fields.input_id = ss.format_id(fields.input_id)
|
||||
smeta:set_string("id", fields.input_id)
|
||||
|
||||
-- set or remove displayed text when pointed at
|
||||
local shop_name = get_shop_name(fields.input_id)
|
||||
local shop_name = get_shop_name(fields.input_id, buyer)
|
||||
if shop_name then
|
||||
smeta:set_string("infotext", shop_name)
|
||||
smeta:set_string("name", shop_name)
|
||||
@ -226,7 +259,7 @@ core.register_on_player_receive_fields(function(player, formname, fields)
|
||||
smeta:set_string("name", nil)
|
||||
end
|
||||
|
||||
ss.log("action", "server admin " .. player:get_player_name()
|
||||
ss.log("action", "admin " .. player:get_player_name()
|
||||
.. " set shop ID at ("
|
||||
.. tostring(pos.x) .. "," .. tostring(pos.y) .. "," .. tostring(pos.z)
|
||||
.. ") to \"" .. id .. "\"")
|
||||
@ -236,7 +269,7 @@ core.register_on_player_receive_fields(function(player, formname, fields)
|
||||
pmeta:set_int(ss.modname .. ":selected", idx)
|
||||
end
|
||||
elseif fields.btn_refund then
|
||||
transaction.give_refund(id, player)
|
||||
transaction.give_refund(id, player, buyer)
|
||||
elseif fields.btn_buy then
|
||||
local idx = pmeta:get_int(ss.modname .. ":selected")
|
||||
local product = get_shop_index(id, idx)
|
||||
@ -261,7 +294,7 @@ core.register_on_player_receive_fields(function(player, formname, fields)
|
||||
product:set_count(product_count)
|
||||
|
||||
-- subtract total from deposited money
|
||||
transaction.set_deposit(id, player, deposited - total)
|
||||
transaction.set_deposit(id, player, deposited - total, buyer)
|
||||
|
||||
-- execute transaction
|
||||
core.chat_send_player(player:get_player_name(), "You purchased " .. tostring(product:get_count())
|
||||
@ -270,7 +303,7 @@ core.register_on_player_receive_fields(function(player, formname, fields)
|
||||
end
|
||||
|
||||
-- refresh formspec view
|
||||
ss.show_formspec(pos, player)
|
||||
ss.show_formspec(pos, player, buyer)
|
||||
|
||||
return false
|
||||
end
|
||||
|
@ -43,52 +43,44 @@ if fopen ~= nil then
|
||||
io.close(fopen)
|
||||
|
||||
local json = core.parse_json(content)
|
||||
for _, shop in ipairs(json) do
|
||||
if shop.type == "currency" then
|
||||
if type(shop.value) ~= "number" or shop.value <= 0 then
|
||||
shop_file_error("invalid or undeclared currency \"value\"; must be a number greater than 0")
|
||||
end
|
||||
if json then
|
||||
for _, shop in ipairs(json) do
|
||||
if shop.type == "currency" then
|
||||
if type(shop.value) ~= "number" or shop.value <= 0 then
|
||||
shop_file_error("invalid or undeclared currency \"value\"; must be a number greater than 0")
|
||||
end
|
||||
|
||||
ss.register_currency(shop.name, shop.value)
|
||||
elseif shop.type == "suffix" then
|
||||
if type(shop.value) ~= "string" or shop.value:trim() == "" then
|
||||
shop_file_error("invalid or undeclared suffix \"value\"; must be non-empty string")
|
||||
else
|
||||
ss.currency_suffix = shop.value
|
||||
end
|
||||
elseif shop.type == "sell" then
|
||||
if type(shop.id) ~= "string" or shop.id:trim() == "" then
|
||||
shop_file_error("invalid or undeclared \"id\"; must be non-empty string")
|
||||
elseif type(shop.name) ~= "string" or shop.name:trim() == "" then
|
||||
shop_file_error("invalid or undeclared \"name\"; must be non-empty string")
|
||||
elseif type(shop.products) ~= "table" then
|
||||
shop_file_error("invalid or undeclared \"products\" list; must be non-empty table")
|
||||
else
|
||||
shop.id = shop.id:trim()
|
||||
shop.name = shop.name:trim()
|
||||
local products = {}
|
||||
ss.register_currency(shop.name, shop.value)
|
||||
elseif shop.type == "suffix" then
|
||||
if type(shop.value) ~= "string" or shop.value:trim() == "" then
|
||||
shop_file_error("invalid or undeclared suffix \"value\"; must be non-empty string")
|
||||
else
|
||||
ss.currency_suffix = shop.value
|
||||
end
|
||||
elseif shop.type == "sell" or shop.type == "buy" then
|
||||
if type(shop.id) ~= "string" or shop.id:trim() == "" then
|
||||
shop_file_error("invalid or undeclared \"id\"; must be non-empty string")
|
||||
elseif type(shop.name) ~= "string" or shop.name:trim() == "" then
|
||||
shop_file_error("invalid or undeclared \"name\"; must be non-empty string")
|
||||
elseif type(shop.products) ~= "table" then
|
||||
shop_file_error("invalid or undeclared \"products\" list; must be non-empty table")
|
||||
else
|
||||
if not shop.products then shop.products = {} end
|
||||
if #shop.products == 0 then
|
||||
ss.log("warning", shops_file .. ": empty shop list for shop id \"" .. shop.id .. "\"")
|
||||
end
|
||||
|
||||
for k, v in pairs(shop.products) do
|
||||
if type(k) ~= "string" or k == "" then
|
||||
shop_file_error("shop " .. shop.id .. ": invalid or undeclared product name, must be string")
|
||||
elseif type(v) ~= "number" or v <= 0 then
|
||||
shop_file_error("shop " .. shop.id .. ": invalid or undeclared product value ("
|
||||
.. k .. "), must be number greater than 0")
|
||||
if shop.type == "sell" then
|
||||
server_shop.register_seller(shop.id, shop.name, shop.products)
|
||||
else
|
||||
table.insert(products, {k, v})
|
||||
server_shop.register_buyer(shop.id, shop.name, shop.products)
|
||||
end
|
||||
end
|
||||
|
||||
if #products == 0 then
|
||||
ss.log("warning", shop_file .. ": empty shop list for shop id \"" .. shop.id .. "\"")
|
||||
end
|
||||
|
||||
server_shop.register_shop(shop.id, shop.name, products)
|
||||
elseif not shop.type then
|
||||
error(shops_file .. ": mandatory \"type\" parameter not set")
|
||||
else
|
||||
error(shops_file .. ": Unrecognized type: " .. shop.type)
|
||||
end
|
||||
elseif not shop.type then
|
||||
error(shops_file .. ": mandatory \"type\" parameter not set")
|
||||
else
|
||||
error(shops_file .. ": Unrecognized type: " .. shop.type)
|
||||
end
|
||||
end
|
||||
else
|
||||
|
@ -1,6 +1,6 @@
|
||||
name = server_shop
|
||||
title = Server Shop
|
||||
description = Shops intended to be set up by server administrators.
|
||||
version = 1.1
|
||||
version = 1.2
|
||||
author = Jordan Irwin (AntumDeluge)
|
||||
optional_depends = currency
|
||||
optional_depends = currency, default
|
||||
|
@ -2,8 +2,8 @@
|
||||
local ss = server_shop
|
||||
|
||||
|
||||
core.register_node(ss.modname .. ":shop", {
|
||||
description = "Shop",
|
||||
core.register_node(ss.modname .. ":sell", {
|
||||
description = "Seller Shop",
|
||||
--drawtype = "nodebox",
|
||||
drawtype = "normal",
|
||||
tiles = {
|
||||
@ -52,3 +52,41 @@ core.register_node(ss.modname .. ":shop", {
|
||||
return ss.is_shop_owner(pos, player) or ss.is_shop_admin(player)
|
||||
end,
|
||||
})
|
||||
core.register_alias(ss.modname .. ":shop", ss.modname .. ":sell") -- backward compat
|
||||
|
||||
|
||||
if core.registered_items["currency:minegeld_50"] and core.registered_items["default:gold_ingot"] then
|
||||
core.register_node(ss.modname .. ":buy", {
|
||||
description = "Buyer Shop",
|
||||
drawtype = "normal",
|
||||
tiles = {
|
||||
"server_shop_side.png",
|
||||
"server_shop_side.png",
|
||||
"server_shop_side.png",
|
||||
"server_shop_side.png",
|
||||
"server_shop_side.png",
|
||||
"server_shop_front.png",
|
||||
"server_shop_side.png",
|
||||
},
|
||||
groups = {oddly_breakable_by_hand=1,},
|
||||
paramtype2 = "facedir",
|
||||
after_place_node = function(pos, placer)
|
||||
-- set node owner
|
||||
core.get_meta(pos):set_string("owner", placer:get_player_name())
|
||||
end,
|
||||
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
|
||||
local pmeta = player:get_meta()
|
||||
|
||||
-- store node pos in player meta for retrieval in callbacks
|
||||
pmeta:set_string(ss.modname .. ":pos", core.serialize(pos))
|
||||
-- store selected index in player meta for retrieval in callbacks
|
||||
-- FIXME: may not be necessary for buyers
|
||||
pmeta:set_int(ss.modname .. ":selected", 1)
|
||||
|
||||
ss.show_formspec(pos, player, true)
|
||||
end,
|
||||
can_dig = function(pos, player)
|
||||
return ss.is_shop_owner(pos, player) or ss.is_shop_admin(player)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 133 KiB |
@ -2,6 +2,21 @@
|
||||
local ss = server_shop
|
||||
|
||||
|
||||
--- Formats a string from deposit identification.
|
||||
--
|
||||
-- @local
|
||||
-- @function format_deposit_id
|
||||
-- @tparam string id Shop identifier.
|
||||
-- @tparam bool buyer Denotes whether shop type is seller or buyer (default: false).
|
||||
-- @treturn string String formatted as "<modname>:<buy/sell>:<id>:deposited".
|
||||
local function format_deposit_id(id, buyer)
|
||||
local deposit_id = ss.modname .. ":sell:"
|
||||
if buyer then
|
||||
deposit_id = ss.modname .. ":buy:"
|
||||
end
|
||||
return deposit_id .. id .. ":deposited"
|
||||
end
|
||||
|
||||
--- Sets deposited amount for shop.
|
||||
--
|
||||
-- @local
|
||||
@ -9,9 +24,10 @@ local ss = server_shop
|
||||
-- @tparam string id Shop id.
|
||||
-- @param player Player for whom deposit is being set.
|
||||
-- @tparam int amount The amount deposit should be set to.
|
||||
local function set_deposit(id, player, amount)
|
||||
-- @tparam bool buyer Denotes whether shop is a seller or buyer
|
||||
local function set_deposit(id, player, amount, buyer)
|
||||
local pmeta = player:get_meta()
|
||||
local deposit_id = ss.modname .. ":" .. id .. ":deposited"
|
||||
local deposit_id = format_deposit_id(id, buyer)
|
||||
|
||||
pmeta:set_int(deposit_id, amount)
|
||||
end
|
||||
@ -23,8 +39,8 @@ end
|
||||
-- @tparam string id Shop id.
|
||||
-- @param player Player to check.
|
||||
-- @treturn int Total amount currently deposited.
|
||||
local function get_deposit(id, player)
|
||||
return player:get_meta():get_int(ss.modname .. ":" .. id .. ":deposited")
|
||||
local function get_deposit(id, player, buyer)
|
||||
return player:get_meta():get_int(format_deposit_id(id, buyer))
|
||||
end
|
||||
|
||||
--- Add item(s) to player inventory or drops on ground.
|
||||
@ -121,9 +137,9 @@ end
|
||||
-- @function give_refund
|
||||
-- @tparam string id Shop id.
|
||||
-- @param player Player to whom refund is given.
|
||||
local function give_refund(id, player)
|
||||
local function give_refund(id, player, buyer)
|
||||
local pmeta = player:get_meta()
|
||||
local deposit_id = ss.modname .. ":" .. id .. ":deposited"
|
||||
local deposit_id = format_deposit_id(id, buyer)
|
||||
|
||||
local refund = calculate_refund(pmeta:get_int(deposit_id))
|
||||
for _, istack in ipairs(refund) do
|
||||
@ -136,8 +152,6 @@ end
|
||||
|
||||
--- Calculates the price of item being purchased.
|
||||
--
|
||||
-- FIXME: might be broken after shop def change
|
||||
--
|
||||
-- @local
|
||||
-- @function calculate_price
|
||||
-- @param shop_id String identifier of shop.
|
||||
|
Loading…
x
Reference in New Issue
Block a user