mirror of
https://github.com/minetest-mods/global_exchange.git
synced 2025-06-29 22:31:03 +02:00
Compare commits
11 Commits
master
...
nalc-1.2.0
Author | SHA1 | Date | |
---|---|---|---|
c1a527eeea | |||
57deb8582e | |||
81517a5b3d | |||
0de7a34fcf | |||
d49a7fdc12 | |||
73407cd6fa | |||
b52e813d45 | |||
5cfb580545 | |||
141de27c97 | |||
808b3cbf04 | |||
2a5a726cc0 |
127
README.md
127
README.md
@ -15,87 +15,86 @@ Nodes
|
|||||||
|
|
||||||
Using the Exchange
|
Using the Exchange
|
||||||
==================
|
==================
|
||||||
Main Screen
|
Overview
|
||||||
-----------
|
-----------
|
||||||
The first screen you see is where you can search and post new buy/sell orders.
|
At the top of the exchange form there are four tabs: Market Summary, Buy, Sell,
|
||||||
Here is an overview of each element:
|
and Your Orders. Pressing each tab will take you to the indicated screen as
|
||||||
- Market Summary - Pressing this will take you to the market summary screen.
|
described below.
|
||||||
- Your Orders - This will take you to a screen where you can view and cancel
|
|
||||||
your existing orders.
|
|
||||||
- Item - This field is for entering the item name (e.g. default:cobble) of the
|
|
||||||
item you want to search or post an order for.
|
|
||||||
- Amount - This field is for entering how many of the item you want to buy/sell
|
|
||||||
when posting an order. It has no purpose in searches.
|
|
||||||
- Select Item - This button takes you to a screen for choosing your item
|
|
||||||
graphically, instead of manually typing an item name.
|
|
||||||
- Rate - This field is for entering the desired price per item when posting an
|
|
||||||
order. For buy orders, this is the maximum price - your order will also accept
|
|
||||||
items that are cheaper. For sell orders, this is the minimum price - your
|
|
||||||
order will also accept buyers that are willing to pay more. The Rate field has
|
|
||||||
no effect on searches
|
|
||||||
- Search - This button searches existing orders for the selected item. If you
|
|
||||||
have the "Sell" box checked, it will only display buy orders, and will display
|
|
||||||
them in descending rate. If you have the box unchecked, it will show sell
|
|
||||||
orders in order of ascending rate.
|
|
||||||
- Post Order - This posts a new order for the item with the given amount and
|
|
||||||
rate. If the "Sell" box is checked, this is a sell order, so the exchange will
|
|
||||||
remove the items from your inventory. If it's unchecked, you are making a buy
|
|
||||||
order, so it will deduct credits from your account. If there are already
|
|
||||||
matching orders, it will immediately fill your order up to the amount possible,
|
|
||||||
and the remainder will stay as a new order.
|
|
||||||
- Sell - This checkbox determines what kind of orders to search for, and also
|
|
||||||
what kind of order you are posting.
|
|
||||||
- Search Results - This will display the results of your search. Clicking on an
|
|
||||||
element here will automatically fill the "Amount" and "Rate" fields, so that if
|
|
||||||
you click "Post Order", it will match the order you clicked.
|
|
||||||
|
|
||||||
Market Summary
|
Market Summary
|
||||||
--------------
|
--------------
|
||||||
This summarizes the various items available on the exchange. From left to right,
|
This summarizes the various items available on the exchange. From left to right,
|
||||||
the columns display the item name, the description (what is shown in inventory),
|
the columns display the item name, the description (what is shown in inventory),
|
||||||
the amount requested by buyers, the maximum rate offered by buyers, the amount
|
the tool wear if applicable, the amount requested by buyers, the maximum rate
|
||||||
offered by sellers, and the minimum rate offered by sellers. It is updated
|
offered by buyers, the amount offered by sellers, and the minimum rate offered
|
||||||
periodically.
|
by sellers. It is updated periodically.
|
||||||
|
|
||||||
|
Buy
|
||||||
|
-----------
|
||||||
|
The upper-left corner shows the open order book for the selected item,
|
||||||
|
consisting of the three best sell offers (lowest asking price and least tool
|
||||||
|
wear) followed by the three best buy offers (highest offer price and highest
|
||||||
|
acceptable tool wear). To the right is an image of the selected item, entry
|
||||||
|
fields for the quantity and offer price, and a drop-down field for the desired
|
||||||
|
tool wear: "New" (no wear), "Good" (up to 10% wear), "Worn" (up to 50% wear),
|
||||||
|
and "Junk" (any amount of wear). To qualify, a seller must offer an item with
|
||||||
|
wear equal to or less than the indicated amount (e.g. if you select "Good" you
|
||||||
|
may receive an item with only 5% wear, but not one 15% worn). Similarly, the
|
||||||
|
offer price is the highest price you are willing to pay; in practice you may
|
||||||
|
pay less depending on the open sell orders. Orders are always fulfilled at the
|
||||||
|
price listed in the open order book.
|
||||||
|
|
||||||
|
At the bottom of the form is a grid similar to the creative inventory. You can
|
||||||
|
page through the available items using the "<<" and ">>" buttons and select the
|
||||||
|
item you wish to buy simply by clicking on it.
|
||||||
|
|
||||||
|
To finalize the order, press the "Place Bid" button. Note that it is permitted
|
||||||
|
to enter an order which exceeds your available funds at the time the order is
|
||||||
|
placed. As matching sell orders are located, the order will be fulfulled until
|
||||||
|
there are insufficient funds to cover the next item, at which point the
|
||||||
|
remainder of the order will be cancelled.
|
||||||
|
|
||||||
|
Sell
|
||||||
|
-----------
|
||||||
|
As with the Buy screen, the upper-left corner shows the open order book for
|
||||||
|
the selected item. Instead of a static image, the selected item appears as a
|
||||||
|
1x1 inventory. At the bottom of the screen is the standard 8x4 player
|
||||||
|
inventory. To choose the type and quantity of items to sell, move the items
|
||||||
|
from your player inventory to the exchange inventory. Below the exchange
|
||||||
|
inventory is an entry field for the desired asking price. To finalize the
|
||||||
|
order, press the "Sell" button. As with buy orders, the asking price is the
|
||||||
|
lowest price you are willing to accept, and you may receive a higher price
|
||||||
|
depending on the open buy orders.
|
||||||
|
|
||||||
|
Unsold items in the exchange inventory are returned to the player inventory
|
||||||
|
when the form is closed, or to the player's Inbox if the inventory is full.
|
||||||
|
(However, items in the exchange inventory at the time of a server crash, or
|
||||||
|
other abnormal condition, may be lost.)
|
||||||
|
|
||||||
Your Orders
|
Your Orders
|
||||||
-----------
|
-----------
|
||||||
This screen lets you see and cancel your orders. To cancel an order, click the
|
This screen lets you see and cancel your orders. To cancel an order, click the
|
||||||
order and press the "Cancel" button.
|
order and press the "Cancel" button. If the order was sell order, the items
|
||||||
|
held in "escrow" are returned to your player inventory. If any of the items do
|
||||||
Select Item
|
not fit in the inventory they are placed in your Inbox instead to be claimed
|
||||||
-----------
|
later.
|
||||||
This displays a creative-style inventory menu for selecting an item for searches
|
|
||||||
or posting orders. To select an item, drag it from the inventory to the box near
|
|
||||||
the bottom of the form
|
|
||||||
|
|
||||||
Buying/Selling
|
Buying/Selling
|
||||||
==============
|
==============
|
||||||
Once you have opened the exchange, you have a few options. If you don't already
|
Once you have opened the exchange, you have a few options. If you don't already
|
||||||
know what you want to buy or sell, you can look at the Market Summary to get a
|
know what you want to buy or sell, you can look at the Market Summary to get a
|
||||||
glance at what people are offering. After you have decided on what you are
|
glance at what people are offering. After you have decided on what you are
|
||||||
going to do, return to the exchange page.
|
going to do, return to the Buy or Sell page.
|
||||||
|
|
||||||
If you are selling an item, you should check the "Sell" checkbox. Otherwise,
|
When selling, the Ask field is the minimum price you will accept for each
|
||||||
leave it unchecked. Next, you need to select the item you want to deal in. There
|
item. When buying, the Bid field determines the maximum amount you are willing
|
||||||
are two ways: typing the item name (e.g. default:cobble) in manually to the item
|
to pay. If there are matching offers (i.e. there are one or more offers with a
|
||||||
field, or using the "Select Item" menu. If you haven't already decided on a price,
|
price at least as good and a compatible tool wear level), then that part of
|
||||||
or you want to make sure your order is filled quickly, you can conduct a search.
|
your offer will immediately be filled. For example, if you post a buy order
|
||||||
To do this, click the "Search" button. This will give you a list of results. If
|
for 10 cobblestone at 5 credits each, and there is a sell offer for 5
|
||||||
you checked the "Sell" box, then these will be buy orders, and will show the
|
cobblestone at 3 credits each, it will give you 5 cobble immediately at a
|
||||||
maximum price per item each buyer is willing to accept. Otherwise, these will be
|
total cost of 15 credits (the order-book price), and leave an order on the
|
||||||
sell orders, displaying the minimum price each seller will accept. If you click
|
exchange for 5 more cobblestone at 5 credits each.
|
||||||
on a search result, it will automatically fill your Amount and Rate fields to
|
|
||||||
match.
|
|
||||||
|
|
||||||
The Amount and Rate fields are used to decide how much and how expensively you
|
|
||||||
want to make your order. When selling, the Rate field is the minimum price you
|
|
||||||
will accept. When buying, it is the maximum. Once everything is filled out how
|
|
||||||
you want it, press the "Post Order" button. If there are matching offers (when
|
|
||||||
you post a buy/sell offer, there are one or more sell/buy offers with a price
|
|
||||||
at least as good), then that part of your offer will immediately be filled. For
|
|
||||||
example, if you post a buy order for 10 cobblestone at 5 credits each, and there
|
|
||||||
is a sell offer for 5 cobblestone 3 credits each, it will give you 5 cobble
|
|
||||||
immediately, and leave an order on the exchange for 5 more cobblestone.
|
|
||||||
|
|
||||||
Once your offer is on the exchange, you can view or cancel it from the "Your
|
Once your offer is on the exchange, you can view or cancel it from the "Your
|
||||||
Orders" menu.
|
Orders" menu.
|
||||||
|
326
atm.lua
326
atm.lua
@ -1,152 +1,196 @@
|
|||||||
-- A telling machine. Call this file with the exchange argument.
|
-- A telling machine. Call this file with the exchange argument.
|
||||||
local exchange = ...
|
local exchange, formlib = ...
|
||||||
|
|
||||||
local atm_form = "global_exchange:atm_form"
|
local atm_form = "global_exchange:atm_form"
|
||||||
|
local atm_pos = {}
|
||||||
|
|
||||||
local main_menu =[[
|
local unique = (function(unique_num)
|
||||||
size[6,2]
|
return function()
|
||||||
button[2,0;2,1;info;Account Info]
|
unique_num = unique_num + 1
|
||||||
button[4,0;2,1;wire;Wire Monies]
|
return unique_num
|
||||||
button[1,1;4,1;transaction_log;Transaction Log]
|
end
|
||||||
]]
|
end)(0)
|
||||||
|
|
||||||
|
local coins = {
|
||||||
|
[1] = "bitchange:minecoinblock", [2] = "bitchange:minecoin", [3] = "bitchange:mineninth",
|
||||||
|
[4] = "maptools:gold_coin", [5] = "maptools:silver_coin", [6] = "maptools:copper_coin"
|
||||||
|
}
|
||||||
|
|
||||||
local function logout(x,y)
|
local coins_convert = {
|
||||||
return "button[" .. x .. "," .. y .. ";2,1;logout;Log Out]"
|
[coins[6]]=1, [coins[5]]=9, [coins[4]]=81, [coins[3]]=729, [coins[2]]=6561, [coins[1]]=59049,
|
||||||
end
|
["minercantile:copper_coin"]=1, ["minercantile:silver_coin"]=9, ["minercantile:gold_coin"]=81
|
||||||
|
}
|
||||||
|
|
||||||
|
local function withdraw_fs(fs, p_name, amount)
|
||||||
|
local spos = atm_pos[p_name].x..","..atm_pos[p_name].y..","..atm_pos[p_name].z
|
||||||
|
local inv = minetest.get_inventory({ type = "node", pos={x=atm_pos[p_name].x, y=atm_pos[p_name].y, z=atm_pos[p_name].z} })
|
||||||
|
|
||||||
local function label(x,y,text)
|
local msg = ""
|
||||||
return "label[" .. x .. "," .. y .. ";"
|
local w_amount = tonumber(amount)
|
||||||
.. minetest.formspec_escape(text) .. "]"
|
if w_amount and math.floor(w_amount) == w_amount and w_amount > 0 then
|
||||||
end
|
local succ, err = exchange:give_credits(p_name, 0 - w_amount, "Cash withdrawal: (-"..w_amount..")")
|
||||||
|
if succ then
|
||||||
|
local index = 1
|
||||||
|
repeat
|
||||||
|
local m = math.floor(w_amount / coins_convert[coins[index]])
|
||||||
|
if m > 0 then
|
||||||
|
inv:add_item( "main", ItemStack({ name = coins[index], count = m }) )
|
||||||
|
end
|
||||||
|
w_amount = w_amount - (coins_convert[coins[index]] * m)
|
||||||
|
index = index + 1
|
||||||
|
until ( w_amount == 0)
|
||||||
|
else
|
||||||
|
msg = err
|
||||||
|
end
|
||||||
|
elseif w_amount then
|
||||||
|
msg = "Invalid number ! Must be an Integer > 0"
|
||||||
|
end
|
||||||
|
|
||||||
local function field(x,y, w,h, name, label, default)
|
|
||||||
return "field[" .. x .. "," .. y .. ";" .. w .. "," .. h .. ";"
|
|
||||||
.. name .. ";" .. minetest.formspec_escape(label) .. ";"
|
|
||||||
.. minetest.formspec_escape(default) .. "]"
|
|
||||||
end
|
|
||||||
|
|
||||||
local unique_num = 1
|
|
||||||
|
|
||||||
local function unique()
|
|
||||||
local ret = unique_num
|
|
||||||
unique_num = unique_num + 1
|
|
||||||
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function info_fs(p_name)
|
|
||||||
local balance = exchange:get_balance(p_name)
|
local balance = exchange:get_balance(p_name)
|
||||||
|
|
||||||
local fs
|
fs:size(8,10)
|
||||||
|
|
||||||
if not balance then
|
if not balance then
|
||||||
fs = label(0.5,0.5, "You don't have an account.")
|
fs:label(0.5, 0.5, "You don't have an account.")
|
||||||
else
|
else
|
||||||
fs = label(0.5,0.5, "Balance: " .. balance)
|
fs:label(3,8.9, "Balance: " .. balance)
|
||||||
|
fs:field(0.75, 1.25, 3.25, 1, "w_amount", "Desired amount:")
|
||||||
|
fs:button(4, 1, 3.25, 1, "withdraw", "Get !")
|
||||||
|
fs:label(1, 2.25, "Or deposit your coins to credit your account:")
|
||||||
|
fs:list(1,3,6,1, "nodemeta:"..spos, "main")
|
||||||
|
fs:list(0,4.25, 8,4, "current_player", "main")
|
||||||
|
fs("listring[current_player;main]"..
|
||||||
|
"listring[nodemeta:"..spos..";main]"
|
||||||
|
)
|
||||||
|
fs:label(0,9.75, msg)
|
||||||
end
|
end
|
||||||
|
fs:button(0,8.75, 2,1, "logout", "Log Out")
|
||||||
return "size[4,3]" .. fs .. logout(0.5,2)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function info_fs(fs, p_name)
|
||||||
local function wire_fs(p_name)
|
|
||||||
local balance = exchange:get_balance(p_name)
|
local balance = exchange:get_balance(p_name)
|
||||||
|
|
||||||
local fs = "size[4,5]" .. logout(0,4)
|
fs:size(4,3)
|
||||||
|
|
||||||
if not balance then
|
if balance then
|
||||||
return fs .. label(0.5,0.5, "You don't have an account.")
|
fs:label(0.5,0.5, "Balance: " .. balance)
|
||||||
|
else
|
||||||
|
fs:label(0.5,0.5, "You don't have an account.")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- To prevent duplicates
|
fs:button(1,2, 2,1, "logout", "Log Out")
|
||||||
return fs .. field(-100, -100, 0,0, "trans_id", "", unique()) ..
|
|
||||||
label(0.5,0.5, "Balance: " .. balance) ..
|
|
||||||
field(0.5,1.5, 2,1, "recipient", "Send to:", "") ..
|
|
||||||
field(0.5,2.5, 2,1, "amount", "Amount", "") ..
|
|
||||||
"button[2,4;2,1;send;Send]"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function send_fs(p_name, receiver, amt_str)
|
local function wire_fs(fs, p_name)
|
||||||
local fs = "size[7,3]"
|
local balance = exchange:get_balance(p_name)
|
||||||
|
|
||||||
|
fs:size(4,5)
|
||||||
|
|
||||||
|
if balance then
|
||||||
|
-- To detect duplicate/stale form submission
|
||||||
|
fs:field(-100, -100, 0,0, "trans_id", "", unique())
|
||||||
|
|
||||||
|
fs:label(0.50,0.325, "Balance: " .. balance)
|
||||||
|
fs:field(0.75,1.750, 3,1, "recipient", "Send to:", "")
|
||||||
|
fs:field(0.75,3.000, 3,1, "amount", "Amount", "")
|
||||||
|
|
||||||
|
fs:button(0,4.25, 2,1, "logout", "Log Out")
|
||||||
|
fs:button(2,4.25, 2,1, "send", "Send")
|
||||||
|
else
|
||||||
|
fs:button(0,4, 2,1, "logout", "Back")
|
||||||
|
fs:label(0.5,0.5, "You don't have an account.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function send_fs(fs, p_name, receiver, amt_str)
|
||||||
|
fs:size(10,3)
|
||||||
|
|
||||||
|
fs:button(4,2, 2,1, "wire", "Back")
|
||||||
|
|
||||||
local amt = tonumber(amt_str)
|
local amt = tonumber(amt_str)
|
||||||
|
local msg = nil
|
||||||
|
|
||||||
if not amt or amt <= 0 then
|
if not amt or amt <= 0 then
|
||||||
return fs .. label(0.5,0.5, "Invalid transfer amount.") ..
|
msg = "Invalid transfer amount."
|
||||||
"button[0.5,2;2,1;wire;Back]"
|
else
|
||||||
|
local succ, err = exchange:transfer_credits(p_name, receiver, amt)
|
||||||
|
|
||||||
|
if not succ then
|
||||||
|
msg = "Error: " .. err
|
||||||
|
else
|
||||||
|
msg = "Successfully sent " .. amt ..
|
||||||
|
" credits to " .. receiver .. "."
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local succ, err = exchange:transfer_credits(p_name, receiver, amt)
|
fs:label(0.5,0.5, msg)
|
||||||
|
|
||||||
if not succ then
|
|
||||||
return fs .. label(0.5,0.5, "Error: " .. err) ..
|
|
||||||
"button[0.5,2;2,1;wire;Back]"
|
|
||||||
end
|
|
||||||
return fs.. label(0.5,0.5, "Successfully sent " ..
|
|
||||||
amt .. " credits to " .. receiver) ..
|
|
||||||
"button[0.5,2;2,1;wire;Back]"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function log_fs(p_name)
|
local function log_fs(fs, p_name)
|
||||||
local res = {
|
fs:size(14,8)
|
||||||
"size[8,8]label[0,0;Transaction Log]button[0,7;2,1;logout;Log Out]",
|
|
||||||
"tablecolumns[text;text]",
|
|
||||||
"table[0,1;8,6;log_table;Time,Message",
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, entry in ipairs(exchange:player_log(p_name)) do
|
fs:label(0,0, "Transaction Log")
|
||||||
i = i*4
|
|
||||||
res[i] = ","
|
fs:element("tablecolumns", "text", "text")
|
||||||
res[i+1] = tostring(entry.Time)
|
|
||||||
res[i+2] = ","
|
fs("table[0,0.75;13.75,6.75;log_table;Time,Message")
|
||||||
res[i+3] = entry.Message
|
for _, entry in ipairs(exchange:player_log(p_name)) do
|
||||||
|
fs(","):escape_list(entry.Time, entry.Message)
|
||||||
end
|
end
|
||||||
res[#res+1] ="]"
|
fs("]")
|
||||||
|
|
||||||
return table.concat(res)
|
fs:button(6,7.5, 2,1, "logout", "Log Out")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function main_menu_fs(fs, p_name)
|
||||||
|
fs:size(8,2)
|
||||||
|
fs:button(0,0.125, 4,1, "withdraw", "Cash deposit and withdrawal")
|
||||||
|
fs:button(4,0.125, 2,1, "info", "Account Info")
|
||||||
|
fs:button(6,0.125, 2,1, "wire", "Wire Monies")
|
||||||
|
fs:button(0.50, 1.125, 7, 1, "transaction_log", "Transaction Log")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function show_atm_form(fs_fn, p_name, ...)
|
||||||
|
local fs = formlib.Builder()
|
||||||
|
fs_fn(fs, p_name, ...)
|
||||||
|
minetest.show_formspec(p_name, atm_form, tostring(fs))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local trans_ids = {}
|
local trans_ids = {}
|
||||||
|
|
||||||
|
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if formname ~= atm_form then return end
|
if formname ~= atm_form then return end
|
||||||
if fields.quit then return true end
|
if fields.quit then return true end
|
||||||
|
|
||||||
local p_name = player:get_player_name()
|
local p_name = player:get_player_name()
|
||||||
|
|
||||||
local this_id = fields.trans_id
|
local this_id = tonumber(fields.trans_id)
|
||||||
|
|
||||||
if this_id and this_id == trans_ids[p_name] then
|
if this_id and trans_ids[p_name] and this_id <= trans_ids[p_name] then
|
||||||
|
-- Ignore duplicate/stale form submittal
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
trans_ids[p_name] = this_id
|
trans_ids[p_name] = this_id
|
||||||
|
|
||||||
if fields.logout then
|
if fields.logout then
|
||||||
minetest.show_formspec(p_name, atm_form, main_menu)
|
show_atm_form(main_menu_fs, p_name)
|
||||||
end
|
elseif fields.info then
|
||||||
|
show_atm_form(info_fs, p_name)
|
||||||
if fields.info then
|
elseif fields.wire then
|
||||||
minetest.show_formspec(p_name, atm_form, info_fs(p_name))
|
show_atm_form(wire_fs, p_name)
|
||||||
end
|
elseif fields.withdraw then
|
||||||
|
show_atm_form(withdraw_fs, p_name, fields and fields.w_amount)
|
||||||
if fields.wire then
|
elseif fields.send then
|
||||||
minetest.show_formspec(p_name, atm_form, wire_fs(p_name))
|
show_atm_form(send_fs, p_name, fields.recipient, fields.amount)
|
||||||
end
|
elseif fields.transaction_log then
|
||||||
|
show_atm_form(log_fs, p_name)
|
||||||
if fields.send then
|
|
||||||
minetest.show_formspec(p_name, atm_form,
|
|
||||||
send_fs(p_name, fields.recipient, fields.amount))
|
|
||||||
end
|
|
||||||
|
|
||||||
if fields.transaction_log then
|
|
||||||
minetest.show_formspec(p_name, atm_form, log_fs(p_name))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -180,18 +224,19 @@ minetest.register_node("global_exchange:atm_bottom", {
|
|||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {
|
fixed = {
|
||||||
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
{-0.500, -0.500, -0.5000, 0.500, 0.500, 0.50},
|
||||||
{-0.5, 0.5, -0.5, -0.375, 1.125, -0.25},
|
{-0.500, 0.500, -0.5000, -0.375, 1.125, -0.25},
|
||||||
{0.375, 0.5, -0.5, 0.5, 1.125, -0.25},
|
{ 0.375, 0.500, -0.5000, 0.500, 1.125, -0.25},
|
||||||
{-0.5, 0.5, -0.25, 0.5, 1.5, 0.5},
|
{-0.500, 0.500, -0.2500, 0.500, 1.500, 0.50},
|
||||||
{-0.5, 1.125, -0.4375, -0.375, 1.25, -0.25},
|
{-0.500, 1.125, -0.4375, -0.375, 1.250, -0.25},
|
||||||
{0.375, 1.125, -0.4375, 0.5, 1.25, -0.25},
|
{ 0.375, 1.125, -0.4375, 0.500, 1.250, -0.25},
|
||||||
{-0.5, 1.25, -0.375, -0.375, 1.375, -0.25},
|
{-0.500, 1.250, -0.3750, -0.375, 1.375, -0.25},
|
||||||
{0.375, 1.25, -0.375, 0.5, 1.375, -0.25},
|
{ 0.375, 1.250, -0.3750, 0.500, 1.375, -0.25},
|
||||||
{-0.5, 1.375, -0.3125, -0.375, 1.5, -0.25},
|
{-0.500, 1.375, -0.3125, -0.375, 1.500, -0.25},
|
||||||
{0.375, 1.375, -0.3125, 0.5, 1.5, -0.25},
|
{ 0.375, 1.375, -0.3125, 0.500, 1.500, -0.25},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
groups = {cracky=2, atm = 1},
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
local under = pointed_thing.under
|
local under = pointed_thing.under
|
||||||
local pos
|
local pos
|
||||||
@ -223,6 +268,11 @@ minetest.register_node("global_exchange:atm_bottom", {
|
|||||||
return itemstack
|
return itemstack
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
can_dig = function(pos,player)
|
||||||
|
local meta = minetest.get_meta(pos);
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
return inv:is_empty("main")
|
||||||
|
end,
|
||||||
on_destruct = function(pos)
|
on_destruct = function(pos)
|
||||||
local pos2 = {x = pos.x, y = pos.y + 1, z = pos.z}
|
local pos2 = {x = pos.x, y = pos.y + 1, z = pos.z}
|
||||||
local n2 = minetest.get_node(pos2)
|
local n2 = minetest.get_node(pos2)
|
||||||
@ -230,10 +280,49 @@ minetest.register_node("global_exchange:atm_bottom", {
|
|||||||
minetest.remove_node(pos2)
|
minetest.remove_node(pos2)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
groups = {cracky=2, atm = 1},
|
on_construct = function(pos)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
meta:set_string("infotext", "ATM")
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
inv:set_size("main", 6)
|
||||||
|
end,
|
||||||
|
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||||
|
local itname = stack:get_name()
|
||||||
|
if coins_convert[itname] ~= nil then
|
||||||
|
return stack:get_count()
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
end,
|
||||||
|
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||||
|
return stack:get_count()
|
||||||
|
end,
|
||||||
|
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||||
|
local itname = stack:get_name()
|
||||||
|
if coins_convert[itname] ~= nil then
|
||||||
|
local p_name = player:get_player_name()
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
local nb = stack:get_count()
|
||||||
|
local amount = coins_convert[itname] * nb
|
||||||
|
local succ, msg = exchange:give_credits(p_name, amount, "Cash deposit (+"..amount..")")
|
||||||
|
if succ then
|
||||||
|
inv:set_stack(listname, index, nil)
|
||||||
|
minetest.log("action", p_name.." put "..nb.." "..stack:get_name() .. " to ATM at " .. minetest.pos_to_string(pos))
|
||||||
|
show_atm_form(withdraw_fs, p_name)
|
||||||
|
--minetest.show_formspec(p_name, atm_form, deposit_fs(p_name))
|
||||||
|
else
|
||||||
|
minetest.log("error", p_name.." want to put "..nb.." "..stack:get_name().." to ATM at ".. minetest.pos_to_string(pos).." but: "..msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||||
|
minetest.log("action", player:get_player_name().." take "..stack:get_count().." "..stack:get_name().." from ATM at "..minetest.pos_to_string(pos))
|
||||||
|
end,
|
||||||
on_rightclick = function(pos, _, clicker)
|
on_rightclick = function(pos, _, clicker)
|
||||||
|
local p_name = clicker:get_player_name()
|
||||||
|
atm_pos[p_name] = pos
|
||||||
minetest.sound_play("atm_beep", {pos = pos, gain = 0.3, max_hear_distance = 5})
|
minetest.sound_play("atm_beep", {pos = pos, gain = 0.3, max_hear_distance = 5})
|
||||||
minetest.show_formspec(clicker:get_player_name(), atm_form, main_menu)
|
show_atm_form(main_menu_fs, clicker:get_player_name())
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -254,15 +343,15 @@ minetest.register_node("global_exchange:atm_top", {
|
|||||||
node_box = {
|
node_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {
|
fixed = {
|
||||||
{-0.5, -0.5, -0.5, -0.375, 0.125, -0.25},
|
{-0.500, -0.500, -0.5000, -0.375, 0.125, -0.25},
|
||||||
{0.375, -0.5, -0.5, 0.5, 0.125, -0.25},
|
{ 0.375, -0.500, -0.5000, 0.500, 0.125, -0.25},
|
||||||
{-0.5, -0.5, -0.25, 0.5, 0.5, 0.5},
|
{-0.500, -0.500, -0.2500, 0.500, 0.500, 0.50},
|
||||||
{-0.5, 0.125, -0.4375, -0.375, 0.25, -0.25},
|
{-0.500, 0.125, -0.4375, -0.375, 0.250, -0.25},
|
||||||
{0.375, 0.125, -0.4375, 0.5, 0.25, -0.25},
|
{ 0.375, 0.125, -0.4375, 0.500, 0.250, -0.25},
|
||||||
{-0.5, 0.25, -0.375, -0.375, 0.375, -0.25},
|
{-0.500, 0.250, -0.3750, -0.375, 0.375, -0.25},
|
||||||
{0.375, 0.25, -0.375, 0.5, 0.375, -0.25},
|
{ 0.375, 0.250, -0.3750, 0.500, 0.375, -0.25},
|
||||||
{-0.5, 0.375, -0.3125, -0.375, 0.5, -0.25},
|
{-0.500, 0.375, -0.3125, -0.375, 0.500, -0.25},
|
||||||
{0.375, 0.375, -0.3125, 0.5, 0.5, -0.25},
|
{ 0.375, 0.375, -0.3125, 0.500, 0.500, -0.25},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selection_box = {
|
selection_box = {
|
||||||
@ -278,10 +367,11 @@ minetest.register_node("global_exchange:atm_top", {
|
|||||||
minetest.register_craft( {
|
minetest.register_craft( {
|
||||||
output = "global_exchange:atm",
|
output = "global_exchange:atm",
|
||||||
recipe = {
|
recipe = {
|
||||||
{ "default:stone", "default:stone", "default:stone" },
|
{ "default:stone", "default:stone", "default:stone" },
|
||||||
{ "default:stone", "default:gold_ingot", "default:stone" },
|
{ "default:stone", "default:gold_ingot", "default:stone" },
|
||||||
{ "default:stone", "default:stone", "default:stone" },
|
{ "default:stone", "default:stone", "default:stone" },
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_alias("global_exchange:atm", "global_exchange:atm_bottom")
|
minetest.register_alias("global_exchange:atm", "global_exchange:atm_bottom")
|
||||||
|
-- vim:set ts=4 sw=4 noet:
|
||||||
|
@ -1,60 +1,61 @@
|
|||||||
|
local exchange, formlib = ...
|
||||||
local exchange = ...
|
|
||||||
|
|
||||||
local mailbox_form = "global_exchange:digital_mailbox"
|
local mailbox_form = "global_exchange:digital_mailbox"
|
||||||
|
|
||||||
local mailbox_contents = {}
|
local mailbox_contents = {}
|
||||||
local selected_index = {}
|
local selected_index = {}
|
||||||
-- Map from player names to their most recent search result
|
|
||||||
|
|
||||||
|
-- Map from player names to their most recent search result
|
||||||
local function get_mail(p_name)
|
local function get_mail(p_name)
|
||||||
local mail_maybe = mailbox_contents[p_name]
|
local mail_maybe = mailbox_contents[p_name]
|
||||||
if mail_maybe then
|
|
||||||
return mail_maybe
|
if not mail_maybe then
|
||||||
else
|
local _,res = exchange:view_inbox(p_name)
|
||||||
mailbox_contents[p_name] = {}
|
mail_maybe = res or {}
|
||||||
return mailbox_contents[p_name]
|
mailbox_contents[p_name] = mail_maybe
|
||||||
|
selected_index[p_name] = math.min(selected_index[p_name] or 0, #mail_maybe)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return mail_maybe
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function mk_inbox_list(results, x, y, w, h)
|
local function wear_string(wear)
|
||||||
local res = {
|
return "-" .. math.ceil(100 * wear / 65535) .. "%"
|
||||||
"textlist[",
|
|
||||||
tostring(x),
|
|
||||||
",",
|
|
||||||
tostring(y),
|
|
||||||
";",
|
|
||||||
tostring(w),
|
|
||||||
",",
|
|
||||||
tostring(h),
|
|
||||||
";result_list;"
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, row in ipairs(results) do
|
|
||||||
res[i*2+8] = row.Amount .. " " .. row.Item
|
|
||||||
res[i*2+9] = ","
|
|
||||||
end
|
|
||||||
res[#res+1] = "]"
|
|
||||||
|
|
||||||
return table.concat(res)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function mk_mail_fs(p_name, results, err_str)
|
local function mk_inbox_list(fs, results, x, y, w, h)
|
||||||
fs = "size[6,8]" ..
|
fs:textlist(x,y, w,h, "result_list", function(add_row)
|
||||||
"label[0,0;Inbox]"
|
for i, row in ipairs(results) do
|
||||||
|
local wear_suffix = nil
|
||||||
|
if row.Wear > 0 then
|
||||||
|
wear_suffix = " (" .. wear_string(row.Wear) .. ")"
|
||||||
|
end
|
||||||
|
add_row(row.Amount, " ", row.Item, wear_suffix)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function mk_mail_fs(fs, p_name, results, err_str)
|
||||||
|
fs:size(8,8)
|
||||||
|
fs:label(0,0, "Inbox")
|
||||||
|
|
||||||
if err_str then
|
if err_str then
|
||||||
fs = fs .. "label[3,0;Error: " .. err_str .. "]"
|
fs:label(3,0, "Error: " .. err_str)
|
||||||
end
|
end
|
||||||
|
|
||||||
return fs .. mk_inbox_list(results, 0, 1, 6, 6) ..
|
mk_inbox_list(fs, results, 0, 1, 7.75, 6.25)
|
||||||
"button[0,7;2,1;claim;Claim]"
|
|
||||||
|
fs:button(3,7.35, 2,1, "claim", "Claim")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function show_mail(p_name, results, err_str)
|
local function show_mail(p_name, err_str)
|
||||||
minetest.show_formspec(p_name, mailbox_form, mk_mail_fs(p_name, results, err_str))
|
local fs = formlib.Builder()
|
||||||
|
mk_mail_fs(fs, p_name, get_mail(p_name), err_str)
|
||||||
|
minetest.show_formspec(p_name, mailbox_form, tostring(fs))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -63,35 +64,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||||||
if fields.quit then return true end
|
if fields.quit then return true end
|
||||||
|
|
||||||
local p_name = player:get_player_name()
|
local p_name = player:get_player_name()
|
||||||
local idx = selected_index[p_name]
|
|
||||||
|
|
||||||
if fields.claim
|
|
||||||
and idx then
|
|
||||||
local row = get_mail(p_name)[idx]
|
|
||||||
|
|
||||||
if row then
|
|
||||||
local stack = ItemStack(row.Item)
|
|
||||||
stack:set_count(row.Amount)
|
|
||||||
|
|
||||||
local p_inv = player:get_inventory()
|
|
||||||
if not p_inv:room_for_item("main", stack) then
|
|
||||||
show_mail(p_name, get_mail(p_name), "Not enough room.")
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local succ, res = exchange:take_inbox(row.Id, row.Amount)
|
|
||||||
if not succ then
|
|
||||||
show_mail(p_name, get_mail(p_name), res)
|
|
||||||
end
|
|
||||||
|
|
||||||
stack:set_count(res)
|
|
||||||
|
|
||||||
p_inv:add_item("main", stack)
|
|
||||||
|
|
||||||
table.remove(get_mail(p_name), idx)
|
|
||||||
show_mail(p_name, get_mail(p_name))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if fields.result_list then
|
if fields.result_list then
|
||||||
local event = minetest.explode_textlist_event(fields.result_list)
|
local event = minetest.explode_textlist_event(fields.result_list)
|
||||||
@ -101,22 +73,48 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if fields.claim then
|
||||||
|
local idx = selected_index[p_name]
|
||||||
|
local row = get_mail(p_name)[idx]
|
||||||
|
|
||||||
|
if row then
|
||||||
|
local stack = ItemStack(row.Item)
|
||||||
|
stack:set_count(row.Amount)
|
||||||
|
stack:set_wear(row.Wear)
|
||||||
|
|
||||||
|
local p_inv = player:get_inventory()
|
||||||
|
local leftover = p_inv:add_item("main", stack)
|
||||||
|
local took_amount = row.Amount - leftover:get_count()
|
||||||
|
|
||||||
|
mailbox_contents[p_name] = nil
|
||||||
|
|
||||||
|
local succ, res = exchange:take_inbox(row.Id, took_amount)
|
||||||
|
if succ then
|
||||||
|
show_mail(p_name)
|
||||||
|
else
|
||||||
|
show_mail(p_name, res)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
minetest.register_node("global_exchange:mailbox", {
|
minetest.register_node("global_exchange:mailbox", {
|
||||||
description = "Digital Mailbox",
|
description = "Digital Mailbox",
|
||||||
tiles = {"global_exchange_box.png",
|
tiles = {
|
||||||
|
"global_exchange_box.png",
|
||||||
"global_exchange_box.png",
|
"global_exchange_box.png",
|
||||||
"global_exchange_box.png^global_exchange_mailbox_side.png",
|
"global_exchange_box.png^global_exchange_mailbox_side.png",
|
||||||
},
|
},
|
||||||
|
is_ground_content = false,
|
||||||
|
stack_max = 1,
|
||||||
groups = {cracky=2},
|
groups = {cracky=2},
|
||||||
on_rightclick = function(pos, node, clicker)
|
on_rightclick = function(pos, node, clicker)
|
||||||
local p_name = clicker:get_player_name()
|
local p_name = clicker:get_player_name()
|
||||||
local _,res = exchange:view_inbox(p_name)
|
mailbox_contents[p_name] = nil
|
||||||
mailbox_contents[p_name] = res
|
show_mail(p_name)
|
||||||
minetest.show_formspec(p_name, mailbox_form, mk_mail_fs(p_name, res))
|
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -125,7 +123,8 @@ minetest.register_craft( {
|
|||||||
output = "global_exchange:mailbox",
|
output = "global_exchange:mailbox",
|
||||||
recipe = {
|
recipe = {
|
||||||
{ "default:stone", "default:gold_ingot", "default:stone" },
|
{ "default:stone", "default:gold_ingot", "default:stone" },
|
||||||
{ "default:stone", "default:chest", "default:stone" },
|
{ "default:stone", "default:chest", "default:stone" },
|
||||||
{ "default:stone", "default:stone", "default:stone" },
|
{ "default:stone", "default:stone", "default:stone" },
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
-- vim:set ts=4 sw=4 noet:
|
||||||
|
1018
exchange.lua
1018
exchange.lua
File diff suppressed because it is too large
Load Diff
@ -1,35 +1,63 @@
|
|||||||
|
local exchange, formlib = ...
|
||||||
|
|
||||||
local exchange = ...
|
|
||||||
local search_cooldown = 2
|
local search_cooldown = 2
|
||||||
local summary_interval = 600
|
local summary_interval = 600
|
||||||
|
|
||||||
|
local global_inv = nil
|
||||||
|
|
||||||
|
-- NALC split() function
|
||||||
|
local function split(str, sep)
|
||||||
|
if not str then return nil end
|
||||||
|
local result = {}
|
||||||
|
local regex = ("([^%s]+)"):format(sep)
|
||||||
|
for each in str:gmatch(regex) do
|
||||||
|
table.insert(result, each)
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
local function is_integer(x)
|
||||||
|
return math.floor(x) == x
|
||||||
|
end
|
||||||
|
|
||||||
|
local function wear_string(wear)
|
||||||
|
if wear > 0 then
|
||||||
|
return "-" .. math.ceil(100 * wear / 65535) .. "%"
|
||||||
|
else
|
||||||
|
return "----"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local summary_fs = ""
|
local summary_fs = ""
|
||||||
local function mk_summary_fs()
|
local function mk_summary_fs()
|
||||||
local res = {
|
local fs = formlib.Builder()
|
||||||
"size[8,8]",
|
|
||||||
"label[0,0;Updated Periodically]",
|
|
||||||
"tablecolumns[text;text;text;text;text;text]",
|
|
||||||
"table[0,1;8,6;summary_table;",
|
|
||||||
"Item,Description,Buy Vol,Buy Max,Sell Vol,Sell Min"
|
|
||||||
}
|
|
||||||
|
|
||||||
local all_items = minetest.registered_items
|
fs:tablecolumns("text", "text", "text", "text", "text", "text", "text")
|
||||||
for i, row in ipairs(exchange:market_summary()) do
|
fs:table(0,0, 11.75,9, "summary_table", function(add_row)
|
||||||
local n = #res+1
|
add_row("Item",
|
||||||
res[n] = "," .. row.item_name
|
"Description",
|
||||||
local def = all_items[row.item_name] or {}
|
"Wear",
|
||||||
res[n+1] = "," .. (def.description or "Unknown Item")
|
"Buy Vol",
|
||||||
res[n+2] = "," .. (row.buy_volume or 0)
|
"Buy Max",
|
||||||
res[n+3] = "," .. (row.buy_max or "N/A")
|
"Sell Vol",
|
||||||
res[n+4] = "," .. (row.sell_volume or 0)
|
"Sell Min")
|
||||||
res[n+5] = "," .. (row.sell_min or "N/A")
|
|
||||||
end
|
|
||||||
|
|
||||||
res[#res+1] = "]"
|
local all_items = minetest.registered_items
|
||||||
res[#res+1] = "button[3,7;2,1;back;Back]"
|
for i, row in ipairs(exchange:market_summary()) do
|
||||||
|
local def = all_items[row.Item] or {}
|
||||||
|
add_row(row.Item,
|
||||||
|
split(def.description, "\n")[1] or "Unknown Item",
|
||||||
|
wear_string(row.Wear),
|
||||||
|
row.Buy_Volume or 0,
|
||||||
|
row.Buy_Max or "N/A",
|
||||||
|
row.Sell_Volume or 0,
|
||||||
|
row.Sell_Min or "N/A")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
summary_fs = table.concat(res)
|
summary_fs = tostring(fs)
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.after(0, mk_summary_fs)
|
minetest.after(0, mk_summary_fs)
|
||||||
|
|
||||||
|
|
||||||
@ -42,26 +70,34 @@ minetest.register_globalstep(function(dtime)
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local summary_form = "global_exchange:summary"
|
|
||||||
local function show_summary(p_name)
|
local wear_levels = {
|
||||||
minetest.show_formspec(p_name, summary_form, summary_fs)
|
[1] = { index = 1, text = "New (-0%)", wear = math.floor(0.00*65535) },
|
||||||
|
[2] = { index = 2, text = "Good (-10%)", wear = math.floor(0.10*65535) },
|
||||||
|
[3] = { index = 3, text = "Worn (-50%)", wear = math.floor(0.50*65535) },
|
||||||
|
[4] = { index = 4, text = "Junk (-100%)", wear = math.floor(1.00*65535) },
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Allow lookup by text label as well as index
|
||||||
|
for _,v in ipairs(wear_levels) do
|
||||||
|
wear_levels[tostring(v.text)] = v
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local main_state = {}
|
local main_state = {}
|
||||||
-- ^ A per-player state for the main form. It contains these values:
|
-- ^ A per-player state for the main form.
|
||||||
-- old_fields: Keeps track of the fields before this update, when changing
|
|
||||||
-- things slightly
|
|
||||||
-- search_results: The last search results the player obtained
|
|
||||||
-- last_search_time: The last time the player did a search. Used to implement
|
|
||||||
-- a cooldown on searches
|
|
||||||
-- sell: A boolean whether the player has sell selected
|
|
||||||
|
|
||||||
minetest.register_on_joinplayer(function(player)
|
minetest.register_on_joinplayer(function(player)
|
||||||
exchange:new_account(player:get_player_name()) --just to make sure
|
exchange:new_account(player:get_player_name()) --just to make sure
|
||||||
main_state[player:get_player_name()] = {
|
main_state[player:get_player_name()] = {
|
||||||
old_fields = {},
|
tab = 1,
|
||||||
search_results = {},
|
buy_item = "",
|
||||||
last_search_time = 0,
|
buy_wear = wear_levels[1].text,
|
||||||
|
buy_price = "",
|
||||||
|
buy_amount = "1",
|
||||||
|
sell_price = "",
|
||||||
|
buy_page = 1,
|
||||||
|
selected_index = 0,
|
||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@ -70,268 +106,268 @@ minetest.register_on_leaveplayer(function(player)
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
local main_form = "global_exchange:exchange_main"
|
|
||||||
|
|
||||||
|
|
||||||
local tablecolumns =
|
|
||||||
"tablecolumns[text;text;text;text;text;text]"
|
|
||||||
|
|
||||||
|
|
||||||
local function table_from_results(results, x, y, w, h, selected)
|
|
||||||
local fs_tab
|
|
||||||
|
|
||||||
local function insert(str)
|
|
||||||
fs_tab[#fs_tab+1] = str
|
|
||||||
end
|
|
||||||
|
|
||||||
fs_tab = {
|
|
||||||
tablecolumns,
|
|
||||||
"table[" .. x .. "," .. y .. ";" .. w .. "," .. h .. ";",
|
|
||||||
"result_table;",
|
|
||||||
"Poster,Type,Item,Description,Amount,Rate"
|
|
||||||
}
|
|
||||||
|
|
||||||
local all_items = minetest.registered_items
|
|
||||||
|
|
||||||
for i, row in ipairs(results) do
|
|
||||||
insert(",")
|
|
||||||
insert(tostring(row.Poster))
|
|
||||||
insert(",")
|
|
||||||
insert(tostring(row.Type))
|
|
||||||
insert(",")
|
|
||||||
insert(tostring(row.Item))
|
|
||||||
insert(",")
|
|
||||||
local def = all_items[row.Item] or {}
|
|
||||||
insert(def.description or "Unknown Item")
|
|
||||||
insert(",")
|
|
||||||
insert(tostring(row.Amount))
|
|
||||||
insert(",")
|
|
||||||
insert(tostring(row.Rate))
|
|
||||||
end
|
|
||||||
|
|
||||||
if selected and selected ~= "" then
|
|
||||||
insert(";")
|
|
||||||
insert(selected)
|
|
||||||
end
|
|
||||||
insert("]")
|
|
||||||
|
|
||||||
return table.concat(fs_tab)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function mk_main_fs(p_name, new_item, err_str, success)
|
|
||||||
local state = main_state[p_name]
|
|
||||||
if not state then return end -- Should have been initialized on player join
|
|
||||||
|
|
||||||
local old_fields = state.old_fields
|
|
||||||
local results = state.search_results
|
|
||||||
local item_def = new_item or old_fields.item or ""
|
|
||||||
local amount_def = old_fields.amount or ""
|
|
||||||
local rate_def = old_fields.rate or ""
|
|
||||||
local sell_def = state.sell or false
|
|
||||||
local selected_def = old_fields.selected or ""
|
|
||||||
|
|
||||||
local bal = exchange:get_balance(p_name)
|
|
||||||
|
|
||||||
local fs
|
|
||||||
if bal then
|
|
||||||
fs = "label[0,0;Balance: " .. bal .. "]"
|
|
||||||
else
|
|
||||||
fs = "label[0.2,0.5;Use an ATM to make your account.]"
|
|
||||||
end
|
|
||||||
|
|
||||||
fs = fs .. "button[4,0;2,1;summary;Market Summary]" ..
|
|
||||||
"button[6,0;2,1;your_orders;Your Orders]" ..
|
|
||||||
"field[0.2,1.5;3,1;item;Item: ;" .. item_def .. "]" ..
|
|
||||||
"field[3.2,1.5;3,1;amount;Amount: ;" .. amount_def .. "]" ..
|
|
||||||
"button[6,1;2,1.4;select_item;Select Item]" ..
|
|
||||||
"checkbox[5,3;sell;Sell;" .. tostring(sell_def) .. "]" ..
|
|
||||||
"field[0.2,2.5;2,1;rate;Rate: ;" .. rate_def .. "]" ..
|
|
||||||
"button[2,2;2,1.4;search;Search]" ..
|
|
||||||
"button[4,2;3,1.4;post_order;Post Order]"
|
|
||||||
|
|
||||||
if err_str then
|
|
||||||
fs = fs .. "label[0,3;Error: " .. err_str .. "]"
|
|
||||||
end
|
|
||||||
|
|
||||||
if success then
|
|
||||||
fs = fs .. "label[0,3;Success!]"
|
|
||||||
end
|
|
||||||
|
|
||||||
return "size[8,9]" .. fs .. table_from_results(results, 0, 4, 8, 5, selected_def)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function show_main(p_name, new_item, err_str, success)
|
|
||||||
minetest.show_formspec(p_name, main_form, mk_main_fs(p_name, new_item, err_str, success))
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Something similar to creative inventory
|
-- Something similar to creative inventory
|
||||||
local pagemax = 1
|
local pagemax = 1
|
||||||
|
local pagewidth = 12
|
||||||
|
local pageheight = 4
|
||||||
|
local pageitems = pagewidth * pageheight
|
||||||
|
local selectable_list = {}
|
||||||
|
|
||||||
-- Create detached inventory after loading all mods
|
-- Create inventory list after loading all mods
|
||||||
minetest.after(0, function()
|
minetest.after(0, function()
|
||||||
local inv = minetest.create_detached_inventory("global_exchange", {
|
|
||||||
allow_move = function(inv, from_list, _, to_list, _,_, player)
|
|
||||||
local p_name = player:get_player_name()
|
|
||||||
|
|
||||||
if from_list == "main"
|
|
||||||
and to_list == "p_" .. p_name then
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
allow_put = function()
|
|
||||||
return 0
|
|
||||||
end,
|
|
||||||
allow_take = function()
|
|
||||||
return 0
|
|
||||||
end,
|
|
||||||
on_move = function(inv, _, _, _, _, _, player)
|
|
||||||
local p_name = player:get_player_name()
|
|
||||||
local p_list = "p_" .. p_name
|
|
||||||
|
|
||||||
local item_name = inv:get_list(p_list)[1]:get_name()
|
|
||||||
inv:set_list(p_list, {})
|
|
||||||
inv:add_item("main", item_name)
|
|
||||||
show_main(p_name, item_name)
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
local selectable_list,n = {},1
|
|
||||||
for name, def in pairs(minetest.registered_items) do
|
for name, def in pairs(minetest.registered_items) do
|
||||||
if (not def.groups.not_in_creative_inventory
|
if (def.groups.not_in_creative_inventory or 0) == 0 and
|
||||||
or def.groups.not_in_creative_inventory == 0)
|
(split(def.description, "\n")[1] or "") ~= "" then
|
||||||
and def.description
|
selectable_list[#selectable_list + 1] = name
|
||||||
and def.description ~= "" then
|
|
||||||
selectable_list[n] = name
|
|
||||||
n = n+1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
table.sort(selectable_list)
|
table.sort(selectable_list)
|
||||||
inv:set_size("main", #selectable_list)
|
|
||||||
for _,itemstring in ipairs(selectable_list) do
|
pagemax = math.max(math.ceil(#selectable_list / pageitems), 1)
|
||||||
inv:add_item("main", ItemStack(itemstring))
|
end)
|
||||||
|
|
||||||
|
local main_form = "global_exchange:exchange_main"
|
||||||
|
|
||||||
|
local function table_from_results(fs, results, name, x, y, w, h, selected)
|
||||||
|
fs:tablecolumns("text", "text", "text", "text", "text", "text", "text")
|
||||||
|
fs:table(x,y, w,h, name, function(add_row)
|
||||||
|
add_row("Poster", "Type", "Item",
|
||||||
|
"Description",
|
||||||
|
"Wear", "Amount", "Rate")
|
||||||
|
|
||||||
|
local all_items = minetest.registered_items
|
||||||
|
for i, row in ipairs(results) do
|
||||||
|
local def = all_items[row.Item] or {}
|
||||||
|
add_row(row.Poster, row.Type, row.Item,
|
||||||
|
split(def.description, "\n")[1] or "Unknown Item",
|
||||||
|
wear_string(row.Wear), row.Amount, row.Rate)
|
||||||
|
end
|
||||||
|
end, math.max(0, tonumber(selected) or 0) + 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function mk_main_market_fs(fs, p_name, state)
|
||||||
|
fs(summary_fs)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function mk_main_order_book_fs(fs, p_name, x, y, w, h, item_name)
|
||||||
|
local order_book = exchange:order_book("", item_name)
|
||||||
|
|
||||||
|
fs:tablecolumns("text", "text", "text", "text")
|
||||||
|
fs:table(x,y, w,h, "order_book", function(add_row)
|
||||||
|
add_row("Type", "Rate", "Wear", "Amount")
|
||||||
|
for _,row in ipairs(order_book) do
|
||||||
|
add_row(row.Type, row.Rate, wear_string(row.Wear), row.Amount)
|
||||||
|
end
|
||||||
|
end, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function mk_main_buy_fs(fs, p_name, state)
|
||||||
|
mk_main_order_book_fs(fs, p_name, 0, 0, 8.75, 3.75, state.buy_item)
|
||||||
|
|
||||||
|
fs:item_image_button(9,0, 1,1, "buy_item", state.buy_item)
|
||||||
|
|
||||||
|
fs:field(10.25,0.40, 2,1, "buy_amount", "Quantity", state.buy_amount, false)
|
||||||
|
|
||||||
|
local wear = wear_levels[state.buy_wear] or wear_levels[1]
|
||||||
|
fs:dropdown(9,1, 3, "buy_wear", function(add_item)
|
||||||
|
for _,v in ipairs(wear_levels) do
|
||||||
|
add_item(v.text)
|
||||||
|
end
|
||||||
|
end, wear.index)
|
||||||
|
|
||||||
|
fs:field(9.35,2.40, 2.9,1, "buy_price", "Bid (ea.)", state.buy_price, false)
|
||||||
|
|
||||||
|
fs:button(9,3, 3,1, "buy", "Place Bid")
|
||||||
|
|
||||||
|
fs:container(0,4, function()
|
||||||
|
fs:button( 0,0.25, 1,1, "buy_left", "<<")
|
||||||
|
fs:button( 5,0.25, 2,1, "position", state.buy_page .. "/" .. pagemax)
|
||||||
|
fs:button(11,0.25, 1,1, "buy_right", ">>")
|
||||||
|
|
||||||
|
local firstitem = ((state.buy_page - 1) * pageitems)
|
||||||
|
for y=0,(pageheight-1) do
|
||||||
|
for x=0,(pagewidth-1) do
|
||||||
|
local index = firstitem + (pagewidth * y) + x + 1
|
||||||
|
if selectable_list[index] then
|
||||||
|
fs:item_image_button(x,1.25+y, 1,1, "select_" .. index,
|
||||||
|
selectable_list[index])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function mk_main_sell_fs(fs, p_name, state)
|
||||||
|
local sell_stack = global_inv:get_stack("p_" .. p_name, 1)
|
||||||
|
local sell_item = (not sell_stack:is_empty()
|
||||||
|
and sell_stack:get_name()) or ""
|
||||||
|
|
||||||
|
mk_main_order_book_fs(fs, p_name, 0, 0, 8.75, 3.75, sell_item)
|
||||||
|
|
||||||
|
fs:list(9,0, 1,1, "detached:global_exchange", "p_" .. p_name)
|
||||||
|
|
||||||
|
fs:field(9.35,2.40, 2.9,1, "sell_price", "Ask (ea.)", state.sell_price, false)
|
||||||
|
|
||||||
|
fs:button(9,3, 3,1, "sell", "Sell")
|
||||||
|
|
||||||
|
fs:box(1.9375,5.1875, 7.96875,4.03, "#00000020")
|
||||||
|
|
||||||
|
fs:list(2,5.25, 8,4, "current_player", "main")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function mk_main_own_orders_fs(fs, p_name, state)
|
||||||
|
if not state.own_results then
|
||||||
|
state.own_results = exchange:search_player_orders(p_name) or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
pagemax = math.ceil((#selectable_list - 1) / (8 * 4))
|
state.selected_index = math.min(state.selected_index or 0, #state.own_results)
|
||||||
end)
|
|
||||||
|
table_from_results(fs, state.own_results, "result_table", 0, 0, 11.75, 8.5, state.selected_index)
|
||||||
|
fs:button(4.5,8.5, 3,1, "cancel", "Cancel Order")
|
||||||
|
end
|
||||||
|
|
||||||
|
local main_tabs = {
|
||||||
|
[1] = { text = "Market", mk_fs = mk_main_market_fs },
|
||||||
|
[2] = { text = "Buy", mk_fs = mk_main_buy_fs },
|
||||||
|
[3] = { text = "Sell", mk_fs = mk_main_sell_fs },
|
||||||
|
[4] = { text = "My Orders", mk_fs = mk_main_own_orders_fs },
|
||||||
|
}
|
||||||
|
|
||||||
|
local function mk_main_fs(fs, p_name, err_str, success)
|
||||||
|
local state = main_state[p_name]
|
||||||
|
if not state then return end -- Should have been initialized on player join
|
||||||
|
|
||||||
|
fs:size(12,10)
|
||||||
|
fs:bgcolor("#606060", false)
|
||||||
|
|
||||||
|
fs:tabheader(0,0.65, "tab", function(add_tab)
|
||||||
|
for _,tab in ipairs(main_tabs) do
|
||||||
|
add_tab(tab.text)
|
||||||
|
end
|
||||||
|
end, state.tab or 1, false, true)
|
||||||
|
|
||||||
|
local bal = exchange:get_balance(p_name)
|
||||||
|
fs:label(0,0.37, "Balance: " .. bal)
|
||||||
|
|
||||||
|
if err_str then
|
||||||
|
fs:label(4,0.37, err_str)
|
||||||
|
elseif success then
|
||||||
|
fs:label(4,0.37, "Success!")
|
||||||
|
end
|
||||||
|
|
||||||
|
if main_tabs[state.tab] then
|
||||||
|
fs:container(0,1, main_tabs[state.tab].mk_fs, p_name, state)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function show_main(p_name, err_str, success)
|
||||||
|
local fs = formlib.Builder()
|
||||||
|
mk_main_fs(fs, p_name, err_str, success)
|
||||||
|
minetest.show_formspec(p_name, main_form, tostring(fs))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
minetest.register_on_joinplayer(function(player)
|
minetest.register_on_joinplayer(function(player)
|
||||||
-- the inventory list name is "p_"..player_name
|
-- the inventory list name (for selling) is "p_"..player_name
|
||||||
minetest.get_inventory({
|
global_inv:set_size("p_" .. player:get_player_name(), 1)
|
||||||
type="detached",
|
|
||||||
name="global_exchange"
|
|
||||||
}):set_size("p_" .. player:get_player_name(), 1)
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
local select_form = "global_exchange:select_form"
|
|
||||||
|
|
||||||
|
|
||||||
local function mk_select_formspec(p_name, start_i, pagenum)
|
|
||||||
return "size[9.3,8]" ..
|
|
||||||
"list[detached:global_exchange;main;0.3,0.5;8,4;" .. tostring(start_i) .. "]" ..
|
|
||||||
"button[0.3,4.5;1.6,1;select_prev;<<]"..
|
|
||||||
"button[6.7,4.5;1.6,1;select_next;>>]"..
|
|
||||||
"label[2.0,5.55;"..tostring(math.floor(pagenum)).."/"..tostring(pagemax).."]"..
|
|
||||||
"list[detached:global_exchange;p_" .. p_name .. ";0.3,7;1,1;]"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local player_pages = {}
|
|
||||||
|
|
||||||
|
|
||||||
local function show_select(p_name)
|
|
||||||
local pagenum = player_pages[p_name] or 1
|
|
||||||
local start_i = (pagenum - 1) * 8 * 4
|
|
||||||
|
|
||||||
local fs = mk_select_formspec(p_name, start_i, pagenum)
|
|
||||||
minetest.show_formspec(p_name, select_form, fs)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local own_form = "global_exchange:my_orders"
|
|
||||||
|
|
||||||
local own_state = {}
|
|
||||||
-- ^ Per=player state for the own orders form. Contains these fields:
|
|
||||||
-- selected_index: The selected index
|
|
||||||
-- own_results: Results for own orders.
|
|
||||||
|
|
||||||
local function mk_own_orders_fs(p_name, results, selected)
|
|
||||||
return "size[8,8]" ..
|
|
||||||
"label[0.5,0.2;Your Orders]" ..
|
|
||||||
"button[6,0;2,1;refresh;Refresh]" ..
|
|
||||||
table_from_results(results, 0, 2, 8, 4.5, selected or "") ..
|
|
||||||
"button[0,7;2,1;cancel;Cancel]" ..
|
|
||||||
"button[3,7;2,1;back;Back]"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function show_own_orders(p_name, results, selected)
|
|
||||||
minetest.show_formspec(p_name, own_form, mk_own_orders_fs(p_name, results, selected))
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Returns success, and also returns an error message if failed.
|
-- Returns success, and also returns an error message if failed.
|
||||||
local function post_order(player, ex_name, order_type, item_name, amount_str, rate_str)
|
local function post_buy(player, ex_name, item_name, wear_str, amount_str, rate_str)
|
||||||
local p_name = player:get_player_name()
|
local p_name = player:get_player_name()
|
||||||
|
|
||||||
if item_name == "" then
|
if (item_name or "") == "" then
|
||||||
return false, "You must input an item"
|
return false, "You must input an item"
|
||||||
end
|
elseif not minetest.registered_items[item_name] then
|
||||||
|
|
||||||
if not minetest.registered_items[item_name] then
|
|
||||||
return false, "That item does not exist."
|
return false, "That item does not exist."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local wear_level = wear_levels[wear_str]
|
||||||
|
if not wear_level then
|
||||||
|
return false, "Invalid wear."
|
||||||
|
end
|
||||||
|
|
||||||
local amount = tonumber(amount_str)
|
local amount = tonumber(amount_str)
|
||||||
local rate = tonumber(rate_str)
|
local rate = tonumber(rate_str)
|
||||||
|
|
||||||
if not amount then
|
if not amount or not is_integer(amount) or amount < 1 then
|
||||||
return false, "Invalid amount."
|
return false, "Invalid amount."
|
||||||
end
|
elseif not rate or not is_integer(rate) or rate < 1 then
|
||||||
|
|
||||||
if not rate then
|
|
||||||
return false, "Invalid rate."
|
return false, "Invalid rate."
|
||||||
end
|
end
|
||||||
|
|
||||||
if amount > 1000 then
|
|
||||||
return false, "Max amount is 1000"
|
|
||||||
end
|
|
||||||
|
|
||||||
local p_inv = player:get_inventory()
|
local p_inv = player:get_inventory()
|
||||||
local stack = ItemStack(item_name)
|
local stack = ItemStack(item_name)
|
||||||
stack:set_count(amount)
|
|
||||||
|
|
||||||
if order_type == "buy" then
|
local succ, res = exchange:buy(p_name, ex_name, item_name, wear_level.wear, amount, rate)
|
||||||
if not p_inv:room_for_item("main", stack) then
|
if not succ then
|
||||||
return false, "Not enough space in inventory."
|
return false, res
|
||||||
end
|
|
||||||
|
|
||||||
local succ, res = exchange:buy(p_name, ex_name, item_name, amount, rate)
|
|
||||||
if not succ then
|
|
||||||
return false, res
|
|
||||||
end
|
|
||||||
|
|
||||||
stack:set_count(res)
|
|
||||||
p_inv:add_item("main", stack)
|
|
||||||
else
|
|
||||||
if not p_inv:contains_item("main", stack) then
|
|
||||||
return false, "Items not in inventory."
|
|
||||||
end
|
|
||||||
|
|
||||||
local succ, res = exchange:sell(p_name, ex_name, item_name, amount, rate)
|
|
||||||
if not succ then
|
|
||||||
return false, res
|
|
||||||
end
|
|
||||||
|
|
||||||
p_inv:remove_item("main", stack)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
for _,row in ipairs(res) do
|
||||||
|
stack:set_count(row.amount)
|
||||||
|
stack:set_wear(row.wear)
|
||||||
|
|
||||||
|
local leftover = p_inv:add_item("main", stack)
|
||||||
|
|
||||||
|
-- Put anything that won't fit in the inventory in the player's inbox
|
||||||
|
if not leftover:is_empty() then
|
||||||
|
exchange:put_in_inbox(p_name, item_name, row.wear, leftover:get_count())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Refresh market summary "soonish"
|
||||||
|
elapsed = math.max(elapsed, summary_interval - 5)
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Returns success, and also returns an error message if failed.
|
||||||
|
-- The item to sell is determined by the player's list in global_inv.
|
||||||
|
local function post_sell(player, ex_name, rate_str)
|
||||||
|
local p_name = player:get_player_name()
|
||||||
|
local stack = global_inv:get_stack("p_" .. p_name, 1)
|
||||||
|
|
||||||
|
if not stack or stack:is_empty() then
|
||||||
|
return false, "You must input an item"
|
||||||
|
elseif not minetest.registered_items[stack:get_name()] then
|
||||||
|
return false, "That item does not exist."
|
||||||
|
end
|
||||||
|
|
||||||
|
if stack.get_meta then
|
||||||
|
local meta = stack:get_meta()
|
||||||
|
local def_meta = ItemStack(stack:get_name()):get_meta()
|
||||||
|
|
||||||
|
if not stack:get_meta():equals(def_meta) then
|
||||||
|
return false, "Cannot sell an item with metadata."
|
||||||
|
end
|
||||||
|
elseif (stack:get_metadata() or "") ~= "" then
|
||||||
|
return false, "Cannot sell an item with metadata."
|
||||||
|
end
|
||||||
|
|
||||||
|
local rate = tonumber(rate_str)
|
||||||
|
|
||||||
|
if not rate or not is_integer(rate) or rate < 1 then
|
||||||
|
return false, "Invalid rate."
|
||||||
|
end
|
||||||
|
|
||||||
|
local item_name = stack:get_name()
|
||||||
|
local wear = stack:get_wear()
|
||||||
|
local amount = stack:get_count()
|
||||||
|
|
||||||
|
local succ, res = exchange:sell(p_name, ex_name, item_name, wear, amount, rate)
|
||||||
|
if not succ then
|
||||||
|
return false, res
|
||||||
|
end
|
||||||
|
|
||||||
|
stack:clear()
|
||||||
|
global_inv:set_stack("p_" .. p_name, 1, stack)
|
||||||
|
|
||||||
|
-- Refresh market summary "soonish"
|
||||||
|
elapsed = math.max(elapsed, summary_interval - 5)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -339,185 +375,113 @@ end
|
|||||||
local function handle_main(player, fields)
|
local function handle_main(player, fields)
|
||||||
local p_name = player:get_player_name()
|
local p_name = player:get_player_name()
|
||||||
local state = main_state[p_name]
|
local state = main_state[p_name]
|
||||||
local old_fields = state.old_fields
|
|
||||||
|
|
||||||
for k, v in pairs(fields) do
|
local copy_fields = {
|
||||||
old_fields[k] = v
|
"buy_wear",
|
||||||
|
"buy_amount",
|
||||||
|
"buy_price",
|
||||||
|
"sell_price"
|
||||||
|
}
|
||||||
|
for _,k in ipairs(copy_fields) do
|
||||||
|
if fields[k] then
|
||||||
|
state[k] = fields[k]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if fields.select_item then
|
if fields.tab then
|
||||||
show_select(p_name)
|
state.tab = tonumber(fields.tab) or 1
|
||||||
end
|
|
||||||
|
|
||||||
if fields.search then
|
|
||||||
local now = os.time()
|
|
||||||
local last_search = state.last_search_time
|
|
||||||
|
|
||||||
if now - last_search < search_cooldown then
|
|
||||||
show_main(p_name, nil, "Please wait before searching again.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- If the player is selling, she wants "buy" type offers.
|
|
||||||
local order_type
|
|
||||||
if state.sell then
|
|
||||||
order_type = "buy"
|
|
||||||
else
|
|
||||||
order_type = "sell"
|
|
||||||
end
|
|
||||||
local item_name = fields["item"]
|
|
||||||
|
|
||||||
local results = exchange:search_orders("", order_type, item_name)
|
|
||||||
state.search_results = results
|
|
||||||
state.last_search_time = now
|
|
||||||
|
|
||||||
show_main(p_name)
|
show_main(p_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if fields.buy_left then
|
||||||
|
state.buy_page = (((state.buy_page or 1) + ((2*pagemax-1) - 1)) % pagemax) + 1
|
||||||
|
show_main(p_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
if fields.buy_right then
|
||||||
|
state.buy_page = (((state.buy_page or 1) + ((2*pagemax-1) + 1)) % pagemax) + 1
|
||||||
|
show_main(p_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
for name in pairs(fields) do
|
||||||
|
local index = tonumber(string.match(name, "select_([0-9]+)"))
|
||||||
|
if index and index >= 1 and index < #selectable_list then
|
||||||
|
state.buy_item = selectable_list[index]
|
||||||
|
show_main(p_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if fields.buy then
|
||||||
|
local succ, err =
|
||||||
|
post_buy(player, "", state.buy_item, fields.buy_wear,
|
||||||
|
fields.buy_amount, fields.buy_price)
|
||||||
|
if succ then
|
||||||
|
state.buy_amount = "1"
|
||||||
|
state.buy_price = ""
|
||||||
|
state.own_results = nil
|
||||||
|
show_main(p_name, nil, true)
|
||||||
|
else
|
||||||
|
show_main(p_name, err)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if fields.sell then
|
if fields.sell then
|
||||||
state.sell = fields.sell == "true"
|
local succ, err = post_sell(player, "", fields.sell_price)
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
if fields.post_order then
|
|
||||||
local now = os.time()
|
|
||||||
local last_search = state.last_search_time
|
|
||||||
|
|
||||||
if now - last_search < search_cooldown then
|
|
||||||
show_main(p_name, nil, "Please wait before posting.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local order_type
|
|
||||||
if state.sell then
|
|
||||||
order_type = "sell"
|
|
||||||
else
|
|
||||||
order_type = "buy"
|
|
||||||
end
|
|
||||||
|
|
||||||
local succ, err =
|
|
||||||
post_order(player, "", order_type, fields.item, fields.amount, fields.rate)
|
|
||||||
|
|
||||||
if succ then
|
if succ then
|
||||||
state.search_results = {}
|
state.sell_price = ""
|
||||||
show_main(p_name, nil, nil, true)
|
state.own_results = nil
|
||||||
|
show_main(p_name, nil, true)
|
||||||
else
|
else
|
||||||
show_main(p_name, nil, err)
|
show_main(p_name, err)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if fields.result_table then
|
|
||||||
local results = state.search_results
|
|
||||||
local event = minetest.explode_table_event(fields.result_table)
|
|
||||||
|
|
||||||
if event.type ~= "CHG" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local index = event.row - 1
|
|
||||||
result = results[index]
|
|
||||||
|
|
||||||
if result then
|
|
||||||
old_fields.amount = tostring(result.Amount)
|
|
||||||
old_fields.rate = tostring(result.Rate)
|
|
||||||
end
|
|
||||||
|
|
||||||
show_main(p_name)
|
|
||||||
end
|
|
||||||
|
|
||||||
if fields.summary then
|
|
||||||
show_summary(p_name)
|
|
||||||
end
|
|
||||||
|
|
||||||
if fields.your_orders then
|
|
||||||
if not own_state[p_name] then
|
|
||||||
own_state[p_name] = {}
|
|
||||||
end
|
|
||||||
local o_state = own_state[p_name]
|
|
||||||
|
|
||||||
o_state.own_results = exchange:search_player_orders(p_name) or {}
|
|
||||||
|
|
||||||
show_own_orders(p_name, o_state.own_results)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function handle_select(player, fields)
|
|
||||||
local p_name = player:get_player_name()
|
|
||||||
|
|
||||||
local pagenum = player_pages[p_name] or 1
|
|
||||||
|
|
||||||
if fields.select_prev then
|
|
||||||
player_pages[p_name] = math.max(1, pagenum - 1)
|
|
||||||
show_select(p_name)
|
|
||||||
elseif fields.select_next then
|
|
||||||
player_pages[p_name] = math.min(pagemax, pagenum + 1)
|
|
||||||
show_select(p_name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function handle_own_orders(player, fields)
|
|
||||||
local p_name = player:get_player_name()
|
|
||||||
|
|
||||||
local state = own_state[p_name] or {}
|
|
||||||
local results = state.own_results or {}
|
|
||||||
local idx = state.selected_index
|
local idx = state.selected_index
|
||||||
|
local own_results = state.own_results or {}
|
||||||
|
|
||||||
if fields.refresh then
|
if fields.cancel and own_results[idx] then
|
||||||
state.own_results = exchange:search_player_orders(p_name) or {}
|
local succ, res = exchange:cancel_order(p_name, own_results[idx].Id)
|
||||||
show_own_orders(p_name, state.own_results)
|
|
||||||
end
|
|
||||||
|
|
||||||
if fields.cancel and idx then
|
|
||||||
local row = results[idx]
|
|
||||||
if not row then return true end
|
|
||||||
local p_inv = player:get_inventory()
|
|
||||||
|
|
||||||
local amount = row.Amount
|
|
||||||
local item = row.Item
|
|
||||||
local stack = ItemStack(item)
|
|
||||||
stack:set_count(amount)
|
|
||||||
if row.Type == "sell" then
|
|
||||||
if not p_inv:room_for_item("main", stack) then
|
|
||||||
show_own_orders(p_name, state.own_results, "Not enough room.")
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local succ, err =
|
|
||||||
exchange:cancel_order(p_name, row.Id, row.Type, row.Item, row.Amount, row.Rate)
|
|
||||||
if succ then
|
if succ then
|
||||||
table.remove(results, idx)
|
if res.Type == "sell" then
|
||||||
if row.Type == "sell" then
|
local p_inv = player:get_inventory()
|
||||||
p_inv:add_item("main", stack)
|
local stack = ItemStack(res.Item)
|
||||||
|
stack:set_count(res.Amount)
|
||||||
|
stack:set_wear(res.Wear)
|
||||||
|
local leftover = p_inv:add_item("main", stack)
|
||||||
|
|
||||||
|
-- Put anything that won't fit in the inventory in the player's inbox
|
||||||
|
if not leftover:is_empty() then
|
||||||
|
exchange:put_in_inbox(p_name, res.Item, res.Wear, leftover:get_count())
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
|
||||||
-- Refresh the results, since there might have been a problem.
|
-- Refresh market summary "soonish"
|
||||||
state.own_results = exchange:search_player_orders(p_name) or {}
|
elapsed = math.max(elapsed, summary_interval - 5)
|
||||||
end
|
end
|
||||||
|
|
||||||
show_own_orders(p_name, state.own_results)
|
state.own_results = nil
|
||||||
|
show_main(p_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
if fields.result_table then
|
if fields.result_table then
|
||||||
local event = minetest.explode_table_event(fields.result_table)
|
local event = minetest.explode_table_event(fields.result_table)
|
||||||
if event.type == "CHG" then
|
if event.type == "CHG" then
|
||||||
state.selected_index = event.row - 1
|
state.selected_index = event.row - 1
|
||||||
show_own_orders(p_name, results, event.row)
|
show_main(p_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if fields.back then
|
if fields.quit then
|
||||||
show_main(p_name)
|
-- Return the player's unsold inventory, if any
|
||||||
end
|
local stack = global_inv:get_stack("p_" .. p_name, 1)
|
||||||
end
|
local p_inv = player:get_inventory()
|
||||||
|
local leftover = p_inv:add_item("main", stack)
|
||||||
|
|
||||||
|
-- Whatever doesn't fit in the player's inventory stays in the form.
|
||||||
|
-- Note that any items in the form when the server exits are lost.
|
||||||
|
global_inv:set_stack("p_" .. p_name, 1, leftover)
|
||||||
|
|
||||||
local function handle_summary(player, fields)
|
state.own_results = nil
|
||||||
if fields.back then
|
|
||||||
show_main(player:get_player_name())
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -525,12 +489,6 @@ end
|
|||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if formname == main_form then
|
if formname == main_form then
|
||||||
handle_main(player, fields)
|
handle_main(player, fields)
|
||||||
elseif formname == select_form then
|
|
||||||
handle_select(player, fields)
|
|
||||||
elseif formname == own_form then
|
|
||||||
handle_own_orders(player, fields)
|
|
||||||
elseif formname == summary_form then
|
|
||||||
handle_summary(player, fields)
|
|
||||||
else
|
else
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -538,6 +496,37 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
global_inv = minetest.create_detached_inventory("global_exchange", {
|
||||||
|
allow_move = function(inv,from_list,from_index,to_list,to_index,count,player)
|
||||||
|
return 0
|
||||||
|
end,
|
||||||
|
allow_put = function(inv,to_list,to_index,stack,player)
|
||||||
|
local p_name = player:get_player_name()
|
||||||
|
|
||||||
|
if to_list == "p_" .. p_name then
|
||||||
|
return stack:get_count()
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
allow_take = function(inv,from_list,from_index,stack,player)
|
||||||
|
local p_name = player:get_player_name()
|
||||||
|
|
||||||
|
if from_list == "p_" .. p_name then
|
||||||
|
return stack:get_count()
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_put = function(inv,to_list,to_index,stack,player)
|
||||||
|
show_main(player:get_player_name())
|
||||||
|
end,
|
||||||
|
on_take = function(inv,from_list,from_index,stack,player)
|
||||||
|
show_main(player:get_player_name())
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
minetest.register_node("global_exchange:exchange", {
|
minetest.register_node("global_exchange:exchange", {
|
||||||
description = "Exchange Terminal",
|
description = "Exchange Terminal",
|
||||||
drawtype = "nodebox",
|
drawtype = "nodebox",
|
||||||
@ -552,18 +541,19 @@ minetest.register_node("global_exchange:exchange", {
|
|||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
groups = {cracky=2},
|
groups = {cracky=2},
|
||||||
|
is_ground_content = false,
|
||||||
stack_max = 1,
|
stack_max = 1,
|
||||||
light_source = 3,
|
light_source = 3,
|
||||||
node_box = {
|
node_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {
|
fixed = {
|
||||||
{-8/16, -4/16, 3/16, 0.5, 0.5, 5/16},--screens
|
{-8/16, -4/16, 3/16, 8/16, 8/16, 5/16},--screens
|
||||||
{-1/16, -7/16, 5/16, 1/16, 5/16, 7/16},--screen leg
|
{-1/16, -7/16, 5/16, 1/16, 5/16, 7/16},--screen leg
|
||||||
{-3/16, -8/16, 4/16, 3/16, -7/16, 8/16},--leg platform
|
{-3/16, -8/16, 4/16, 3/16, -7/16, 8/16},--leg platform
|
||||||
{-7/16, -8/16, -8/16, 2/16, -6/16, -3/16},--keyboard
|
{-7/16, -8/16, -8/16, 2/16, -6/16, -3/16},--keyboard
|
||||||
{3/16, -8/16, -3/16, 7/16, -7/16, 3/16},--phone low
|
{ 3/16, -8/16, -3/16, 7/16, -7/16, 3/16},--phone low
|
||||||
{4/16, -7/16, -1/16, 6/16, -6/16, 3/16},--phone hi
|
{ 4/16, -7/16, -1/16, 6/16, -6/16, 3/16},--phone hi
|
||||||
{2/16, -7/16, 0, 8/16, -5/16, 2/16},--phone speaker
|
{ 2/16, -7/16, 0/16, 8/16, -5/16, 2/16},--phone speaker
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
on_rightclick = function(_, _, clicker)
|
on_rightclick = function(_, _, clicker)
|
||||||
@ -581,8 +571,9 @@ minetest.register_node("global_exchange:exchange", {
|
|||||||
minetest.register_craft( {
|
minetest.register_craft( {
|
||||||
output = "global_exchange:exchange",
|
output = "global_exchange:exchange",
|
||||||
recipe = {
|
recipe = {
|
||||||
{ "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" },
|
{ "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" },
|
||||||
{ "default:mese_crystal", "default:steel_ingot", "default:diamond" },
|
{ "default:mese_crystal", "default:steel_ingot", "default:diamond" },
|
||||||
{ "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" },
|
{ "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" },
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
-- vim:set ts=4 sw=4 noet:
|
||||||
|
172
formlib.lua
Normal file
172
formlib.lua
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
local formlib = {}
|
||||||
|
local builder_methods = {}
|
||||||
|
|
||||||
|
function formlib.escape(x)
|
||||||
|
if x == nil then return "" end
|
||||||
|
return minetest.formspec_escape(tostring(x))
|
||||||
|
end
|
||||||
|
|
||||||
|
function formlib.bool(x)
|
||||||
|
-- nil and false are returned as-is, everything else maps to true
|
||||||
|
return x and true
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.append(fs, ...)
|
||||||
|
for i=1,select("#", ...) do
|
||||||
|
local x = select(i, ...)
|
||||||
|
if x ~= nil then table.insert(fs, tostring(x)) end
|
||||||
|
end
|
||||||
|
return fs
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.escape(fs, ...)
|
||||||
|
for i=1,select("#", ...) do
|
||||||
|
local x = select(i, ...)
|
||||||
|
if x ~= nil then table.insert(fs, formlib.escape(x)) end
|
||||||
|
end
|
||||||
|
return fs
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.escape_list(fs, ...)
|
||||||
|
for i=1,select("#", ...) do
|
||||||
|
local x = select(i, ...)
|
||||||
|
if i > 1 then fs(",") end
|
||||||
|
fs:escape(x)
|
||||||
|
end
|
||||||
|
return fs
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.escape_groups(fs, ...)
|
||||||
|
for i=1,select("#", ...) do
|
||||||
|
local group = select(i, ...)
|
||||||
|
if i > 1 then fs(";") end
|
||||||
|
if type(group) == "table" then
|
||||||
|
fs:escape_list(unpack(group))
|
||||||
|
else
|
||||||
|
fs:escape(group)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return fs
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.element(fs, name, ...)
|
||||||
|
return fs(name, "["):escape_groups(...):append("]")
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.size(fs, w,h, fixed)
|
||||||
|
if fixed == nil then
|
||||||
|
return fs:element("size", {w,h})
|
||||||
|
else
|
||||||
|
return fs:element("size", {w,h, formlib.bool(fixed)})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.bgcolor(fs, color, fullscreen)
|
||||||
|
if fullscreen == nil then
|
||||||
|
return fs:element("bgcolor", {color})
|
||||||
|
else
|
||||||
|
return fs:element("bgcolor", {color}, {formlib.bool(fullscreen)})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.list(fs, x,y, w,h, inv_loc, inv_list, start_idx)
|
||||||
|
return fs:element("list", {inv_loc}, {inv_list}, {x,y}, {w,h}, {start_idx})
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.button(fs, x,y, w,h, name, text)
|
||||||
|
return fs:element("button", {x,y}, {w,h}, {name}, {text})
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.item_image_button(fs, x,y, w,h, name, item, text)
|
||||||
|
return fs:element("item_image_button", {x,y}, {w,h}, {item}, {name}, {text})
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.label(fs, x,y, text)
|
||||||
|
return fs:element("label", {x,y}, {text})
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.field(fs, x,y, w,h, name, label, default, close_on_enter)
|
||||||
|
fs:element("field", {x,y}, {w,h}, {name}, {label}, {default})
|
||||||
|
if close_on_enter ~= nil then
|
||||||
|
fs:element("field_close_on_enter", {name}, {formlib.bool(close_on_enter)})
|
||||||
|
end
|
||||||
|
return fs
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.box(fs, x,y, w,h, color)
|
||||||
|
return fs:element("box", {x,y}, {w,h}, {color})
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.dropdown(fs, x,y, w, name, body_fn, selected_idx)
|
||||||
|
fs("dropdown["):escape_groups({x,y}, {w}, {name}):append(";")
|
||||||
|
local first = true
|
||||||
|
local results = { body_fn(function(...)
|
||||||
|
if first then first = false else fs(",") end
|
||||||
|
fs:escape(...)
|
||||||
|
end) }
|
||||||
|
if selected_idx ~= nil then fs(";"):escape(selected_idx) end
|
||||||
|
return fs("]"), unpack(results)
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.tabheader(fs, x,y, name, body_fn, current_tab, transparent, draw_border)
|
||||||
|
fs("tabheader["):escape_groups({x,y}, {name}):append(";")
|
||||||
|
local first = true
|
||||||
|
local results = { body_fn(function(...)
|
||||||
|
if first then first = false else fs(",") end
|
||||||
|
fs:escape(...)
|
||||||
|
end) }
|
||||||
|
fs(";"):escape_groups({current_tab}, {formlib.bool(transparent)}, {formlib.bool(draw_border)})
|
||||||
|
return fs("]"), unpack(results)
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.textlist(fs, x,y, w,h, name, body_fn, selected_idx, transparent)
|
||||||
|
fs("textlist["):escape_groups({x,y}, {w,h}, {name}):append(";")
|
||||||
|
local first = true
|
||||||
|
local results = { body_fn(function(...)
|
||||||
|
if first then first = false else fs(",") end
|
||||||
|
fs:escape(...)
|
||||||
|
end) }
|
||||||
|
fs(";"):escape_groups({selected_idx}, {formlib.bool(transparent)})
|
||||||
|
return fs("]"), unpack(results)
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.tableoptions(fs, ...)
|
||||||
|
return fs:element("tableoptions", ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.tablecolumns(fs, ...)
|
||||||
|
return fs:element("tablecolumns", ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.table(fs, x,y, w,h, name, body_fn, selected_idx)
|
||||||
|
fs("table["):escape_groups({x,y}, {w,h}, {name}):append(";")
|
||||||
|
local first = true
|
||||||
|
local results = { body_fn(function(...)
|
||||||
|
if first then first = false else fs(",") end
|
||||||
|
fs:escape_list(...)
|
||||||
|
end) }
|
||||||
|
if selected_idx ~= nil then fs(";"):escape(selected_idx) end
|
||||||
|
return fs("]"), unpack(results)
|
||||||
|
end
|
||||||
|
|
||||||
|
function builder_methods.container(fs, x,y, sub_fn, ...)
|
||||||
|
fs:element("container", {x,y})
|
||||||
|
local results = { sub_fn(fs, ...) }
|
||||||
|
return fs("container_end[]"), unpack(results)
|
||||||
|
end
|
||||||
|
|
||||||
|
local builder_meta = {
|
||||||
|
__metatable = "protected",
|
||||||
|
__index = builder_methods,
|
||||||
|
__call = builder_methods.append,
|
||||||
|
__tostring = table.concat,
|
||||||
|
}
|
||||||
|
|
||||||
|
function formlib.Builder()
|
||||||
|
local fs = {}
|
||||||
|
setmetatable(fs, builder_meta)
|
||||||
|
return fs
|
||||||
|
end
|
||||||
|
|
||||||
|
return formlib
|
||||||
|
-- vim:set ts=4 sw=4 noet:
|
70
init.lua
70
init.lua
@ -1,53 +1,45 @@
|
|||||||
|
|
||||||
local insecure_env = minetest.request_insecure_environment()
|
local insecure_env = minetest.request_insecure_environment()
|
||||||
assert(insecure_env,
|
assert(insecure_env, "global_exchange needs to be trusted to run under mod security.")
|
||||||
"global_exchange needs to be trusted to run under mod security.")
|
|
||||||
|
|
||||||
local modpath = minetest.get_modpath(minetest.get_current_modname()) .. "/"
|
local modpath = minetest.get_modpath(minetest.get_current_modname()) .. "/"
|
||||||
|
|
||||||
local income = tonumber(minetest.setting_get("citizens_income")) or 10
|
local exchange = assert(loadfile(modpath .. "exchange.lua"))(insecure_env).
|
||||||
local income_interval = 1200
|
open_exchange(minetest.get_worldpath() .. "/global_exchange.db")
|
||||||
local income_msg = "You receive your citizen's income (+" .. income .. ")"
|
|
||||||
|
|
||||||
local next_payout = os.time() + income_interval
|
|
||||||
|
|
||||||
local exchange =
|
|
||||||
assert(loadfile(modpath .. "exchange.lua"))(insecure_env).open_exchange(
|
|
||||||
minetest.get_worldpath() .. "/global_exchange.db"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
local formlib = assert(loadfile(modpath .. "formlib.lua"))()
|
||||||
|
|
||||||
minetest.register_on_shutdown(function()
|
minetest.register_on_shutdown(function()
|
||||||
exchange:close()
|
exchange:close()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
local function handle_setbalance_command(caller, name, newbalance)
|
||||||
local function check_giving()
|
return exchange:set_balance(name, newbalance)
|
||||||
local now = os.time()
|
|
||||||
if now < next_payout then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
next_payout = now + income_interval
|
|
||||||
|
|
||||||
for _, player in ipairs(minetest.get_connected_players()) do
|
|
||||||
local p_name = player:get_player_name()
|
|
||||||
|
|
||||||
local succ = exchange:give_credits(p_name, income,
|
|
||||||
"Citizen's Income (+" .. income .. ")")
|
|
||||||
|
|
||||||
if succ then
|
|
||||||
minetest.chat_send_player(p_name, income_msg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.after(5, check_giving)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.after(5, check_giving)
|
minetest.register_privilege("balance", {
|
||||||
|
description = "Can use /setbalance",
|
||||||
|
give_to_singleplayer = false
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("setbalance", {
|
||||||
|
params = "[<name>] <balance>",
|
||||||
|
description = "set a player's trading balance",
|
||||||
|
privs = {balance=true},
|
||||||
|
func = function(caller, param)
|
||||||
|
local name, balancestr = string.match(param, "([^ ]+) ([0-9]+)")
|
||||||
|
if not name or not balancestr then
|
||||||
|
name = caller
|
||||||
|
balancestr = string.match(param, "([0-9]+)")
|
||||||
|
if not balancestr then
|
||||||
|
return false, "Invalid parameters (see /help setbalance)"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return handle_setbalance_command(caller, name, tonumber(balancestr))
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
assert(loadfile(modpath .. "atm.lua"))(exchange, formlib)
|
||||||
|
assert(loadfile(modpath .. "exchange_machine.lua"))(exchange, formlib)
|
||||||
|
assert(loadfile(modpath .. "digital_mailbox.lua"))(exchange, formlib)
|
||||||
|
|
||||||
assert(loadfile(modpath .. "atm.lua"))(exchange)
|
minetest.log("action", "[global_exchange] loaded.")
|
||||||
assert(loadfile(modpath .. "exchange_machine.lua"))(exchange)
|
|
||||||
assert(loadfile(modpath .. "digital_mailbox.lua"))(exchange)
|
|
||||||
|
Reference in New Issue
Block a user