This commit is contained in:
raymoo 2016-03-12 01:15:48 -08:00
commit cc70c125a9
5 changed files with 277 additions and 337 deletions

112
atm.lua
View File

@ -14,8 +14,7 @@ button[1,1;4,1;transaction_log;Transaction Log]
local function logout(x,y) local function logout(x,y)
return "button[" .. x .. "," .. y .. return "button[" .. x .. "," .. y .. ";2,1;logout;Log Out]"
";2,1;logout;Log Out]"
end end
@ -41,58 +40,48 @@ end
local function new_account_fs(p_name) local function new_account_fs(p_name)
local fs = "size[4,3]"
local act_suc, err = exchange:new_account(p_name) local act_suc, err = exchange:new_account(p_name)
local fs
if not act_suc then if not act_suc then
fs = fs .. label(0.5,0.5, "Error: " .. err) fs = label(0.5,0.5, "Error: " .. err)
else else
fs = fs .. label(0.5,0.5, "Congratulations on \nyour new account.") fs = label(0.5,0.5, "Congratulations on \nyour new account.")
end end
fs = fs .. logout(0.5,2) return "size[4,3]" .. fs .. logout(0.5,2)
return fs
end end
local function info_fs(p_name) local function info_fs(p_name)
local balance = exchange:get_balance(p_name) local balance = exchange:get_balance(p_name)
local fs = "size[4,3]" local fs
if not balance then if not balance then
fs = 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 = fs .. label(0.5,0.5, "Balance: " .. balance) fs = label(0.5,0.5, "Balance: " .. balance)
end end
fs = fs .. logout(0.5,2) return "size[4,3]" .. fs .. logout(0.5,2)
return fs
end end
local function wire_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]" local fs = "size[4,5]" .. logout(0,4)
fs = fs .. logout(0,4)
if not balance then if not balance then
fs = fs .. label(0.5,0.5, "You don't have an account.") return fs .. label(0.5,0.5, "You don't have an account.")
return fs
end end
-- To prevent duplicates -- To prevent duplicates
fs = fs .. field(-100, -100, 0,0, "trans_id", "", unique()) return fs .. field(-100, -100, 0,0, "trans_id", "", unique()) ..
fs = fs .. label(0.5,0.5, "Balance: " .. balance) label(0.5,0.5, "Balance: " .. balance) ..
fs = fs .. field(0.5,1.5, 2,1, "recipient", "Send to:", "") field(0.5,1.5, 2,1, "recipient", "Send to:", "") ..
fs = fs .. field(0.5,2.5, 2,1, "amount", "Amount", "") field(0.5,2.5, 2,1, "amount", "Amount", "") ..
fs = fs .. "button[2,4;2,1;send;Send]" "button[2,4;2,1;send;Send]"
return fs
end end
@ -102,41 +91,37 @@ local function send_fs(p_name, receiver, amt_str)
local amt = tonumber(amt_str) local amt = tonumber(amt_str)
if not amt or amt <= 0 then if not amt or amt <= 0 then
fs = fs .. label(0.5,0.5, "Invalid transfer amount.") return fs .. label(0.5,0.5, "Invalid transfer amount.") ..
fs = fs .. "button[0.5,2;2,1;wire;Back]" "button[0.5,2;2,1;wire;Back]"
return fs
end end
local succ, err = exchange:transfer_credits(p_name, receiver, amt) local succ, err = exchange:transfer_credits(p_name, receiver, amt)
if not succ then if not succ then
fs = fs .. label(0.5,0.5, "Error: " .. err) return fs .. label(0.5,0.5, "Error: " .. err) ..
fs = fs .. "button[0.5,2;2,1;wire;Back]" "button[0.5,2;2,1;wire;Back]"
else
fs = fs.. label(0.5,0.5, "Successfully sent "
.. amt .. " credits to " .. receiver)
fs = fs .. "button[0.5,2;2,1;wire;Back]"
end end
return fs.. label(0.5,0.5, "Successfully sent " ..
return fs amt .. " credits to " .. receiver) ..
"button[0.5,2;2,1;wire;Back]"
end end
local function log_fs(p_name) local function log_fs(p_name)
local res = { "size[8,8]label[0,0;Transaction Log]button[0,7;2,1;logout;Log Out]", local res = {
"tablecolumns[text;text]", "size[8,8]label[0,0;Transaction Log]button[0,7;2,1;logout;Log Out]",
"table[0,1;8,6;log_table;Time,Message", "tablecolumns[text;text]",
"table[0,1;8,6;log_table;Time,Message",
} }
local log = exchange:player_log(p_name) for i, entry in ipairs(exchange:player_log(p_name)) do
for i, entry in ipairs(log) do i = i*4
table.insert(res, ",") res[i] = ","
table.insert(res, tostring(entry.Time)) res[i+1] = tostring(entry.Time)
table.insert(res, ",") res[i+2] = ","
table.insert(res, entry.Message) res[i+3] = entry.Message
end end
table.insert(res, "]") res[#res+1] ="]"
return table.concat(res) return table.concat(res)
end end
@ -145,9 +130,9 @@ end
local trans_ids = {} local trans_ids = {}
local function handle_fields(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()
@ -159,36 +144,33 @@ local function handle_fields(player, formname, fields)
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) minetest.show_formspec(p_name, atm_form, main_menu)
end end
if fields["new_account"] then if fields.new_account then
minetest.show_formspec(p_name, atm_form, new_account_fs(p_name)) minetest.show_formspec(p_name, atm_form, new_account_fs(p_name))
end end
if fields["info"] then if fields.info then
minetest.show_formspec(p_name, atm_form, info_fs(p_name)) minetest.show_formspec(p_name, atm_form, info_fs(p_name))
end end
if fields["wire"] then if fields.wire then
minetest.show_formspec(p_name, atm_form, wire_fs(p_name)) minetest.show_formspec(p_name, atm_form, wire_fs(p_name))
end end
if fields["send"] then if fields.send then
minetest.show_formspec(p_name, atm_form, minetest.show_formspec(p_name, atm_form,
send_fs(p_name, fields.recipient, fields.amount)) send_fs(p_name, fields.recipient, fields.amount))
end end
if fields["transaction_log"] then if fields.transaction_log then
minetest.show_formspec(p_name, atm_form, log_fs(p_name)) minetest.show_formspec(p_name, atm_form, log_fs(p_name))
end end
return true return true
end end)
minetest.register_on_player_receive_fields(handle_fields)
minetest.register_node("global_exchange:atm", { minetest.register_node("global_exchange:atm", {
@ -198,10 +180,8 @@ minetest.register_node("global_exchange:atm", {
"global_exchange_atm_side.png", "global_exchange_atm_side.png",
}, },
groups = {cracky=2}, groups = {cracky=2},
on_rightclick = function(pos, node, clicker) on_rightclick = function(pos, _, clicker)
local p_name = clicker:get_player_name() minetest.show_formspec(clicker:get_player_name(), atm_form, main_menu)
minetest.show_formspec(p_name, atm_form, main_menu)
end, end,
}) })

View File

@ -19,37 +19,37 @@ end
local function mk_inbox_list(results, x, y, w, h) local function mk_inbox_list(results, x, y, w, h)
local res = {} local res = {
table.insert(res, "textlist[") "textlist[",
table.insert(res, tostring(x)) tostring(x),
table.insert(res, ",") ",",
table.insert(res, tostring(y)) tostring(y),
table.insert(res, ";") ";",
table.insert(res, tostring(w)) tostring(w),
table.insert(res, ",") ",",
table.insert(res, tostring(h)) tostring(h),
table.insert(res, ";result_list;") ";result_list;"
}
for i, row in ipairs(results) do for i, row in ipairs(results) do
table.insert(res, row.Amount .. " " .. row.Item) res[i*2+8] = row.Amount .. " " .. row.Item
table.insert(res, ",") res[i*2+9] = ","
end end
table.insert(res, "]") res[#res+1] = "]"
return table.concat(res) return table.concat(res)
end end
local function mk_mail_fs(p_name, results, err_str) local function mk_mail_fs(p_name, results, err_str)
fs = "size[6,8]" fs = "size[6,8]" ..
fs = fs .. "label[0,0;Inbox]" "label[0,0;Inbox]"
if err_str then if err_str then
fs = fs .. "label[3,0;Error: " .. err_str .. "]" fs = fs .. "label[3,0;Error: " .. err_str .. "]"
end end
fs = fs .. mk_inbox_list(results, 0, 1, 6, 6)
fs = fs .. "button[0,7;2,1;claim;Claim]"
return fs return fs .. mk_inbox_list(results, 0, 1, 6, 6) ..
"button[0,7;2,1;claim;Claim]"
end end
@ -58,14 +58,15 @@ local function show_mail(p_name, results, err_str)
end end
local function handle_fields(player, formname, fields) minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= mailbox_form then return end if formname ~= mailbox_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 idx = selected_index[p_name] local idx = selected_index[p_name]
if fields["claim"] and idx then if fields.claim
and idx then
local row = get_mail(p_name)[idx] local row = get_mail(p_name)[idx]
if row then if row then
@ -77,7 +78,7 @@ local function handle_fields(player, formname, fields)
show_mail(p_name, get_mail(p_name), "Not enough room.") show_mail(p_name, get_mail(p_name), "Not enough room.")
return true return true
end end
local succ, res = exchange:take_inbox(row.Id, row.Amount) local succ, res = exchange:take_inbox(row.Id, row.Amount)
if not succ then if not succ then
show_mail(p_name, get_mail(p_name), res) show_mail(p_name, get_mail(p_name), res)
@ -92,8 +93,8 @@ local function handle_fields(player, formname, fields)
end end
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)
if event.type == "CHG" then if event.type == "CHG" then
selected_index[p_name] = event.index selected_index[p_name] = event.index
@ -101,10 +102,7 @@ local function handle_fields(player, formname, fields)
end end
return true return true
end end)
minetest.register_on_player_receive_fields(handle_fields)
minetest.register_node("global_exchange:mailbox", { minetest.register_node("global_exchange:mailbox", {
@ -116,7 +114,7 @@ minetest.register_node("global_exchange:mailbox", {
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 succ, res = exchange:view_inbox(p_name) local _,res = exchange:view_inbox(p_name)
mailbox_contents[p_name] = res mailbox_contents[p_name] = res
minetest.show_formspec(p_name, mailbox_form, mk_mail_fs(p_name, res)) minetest.show_formspec(p_name, mailbox_form, mk_mail_fs(p_name, res))
end, end,

View File

@ -77,7 +77,7 @@ SELECT
AND Orders.Type = "sell" AND Orders.Type = "sell"
) )
FROM distinct_items; FROM distinct_items;
END TRANSACTION; END TRANSACTION;
]=] ]=]
@ -239,7 +239,7 @@ end
local function is_integer(num) local function is_integer(num)
return math.floor(num) == num return num%1 == 0
end end
@ -248,7 +248,7 @@ local function exec_stmt(db, stmt, names)
local res = stmt:step() local res = stmt:step()
stmt:reset() stmt:reset()
if res == sqlite3.BUSY then if res == sqlite3.BUSY then
return false, "Database Busy." return false, "Database Busy."
elseif res ~= sqlite3.DONE then elseif res ~= sqlite3.DONE then
@ -292,7 +292,7 @@ function exports.open_exchange(path)
transaction_log_stmt = assert(db:prepare(transaction_log_query)), transaction_log_stmt = assert(db:prepare(transaction_log_query)),
} }
local ret = { db = db, local ret = { db = db,
stmts = stmts, stmts = stmts,
} }
@ -332,7 +332,7 @@ function ex_methods.log(self, message, recipient)
return true return true
end end
end end
-- Returns success boolean and error. -- Returns success boolean and error.
function ex_methods.new_account(self, p_name, amt) function ex_methods.new_account(self, p_name, amt)
@ -346,7 +346,7 @@ function ex_methods.new_account(self, p_name, amt)
end end
db:exec("BEGIN TRANSACTION;") db:exec("BEGIN TRANSACTION;")
local stmt = self.stmts.new_act_stmt local stmt = self.stmts.new_act_stmt
stmt:bind_names({ stmt:bind_names({
@ -385,7 +385,7 @@ function ex_methods.new_account(self, p_name, amt)
end end
db:exec("COMMIT;") db:exec("COMMIT;")
return true return true
end end
@ -394,7 +394,7 @@ end
function ex_methods.get_balance(self, p_name) function ex_methods.get_balance(self, p_name)
local db = self.db local db = self.db
local stmt = self.stmts.get_balance_stmt local stmt = self.stmts.get_balance_stmt
stmt:bind_values(p_name) stmt:bind_values(p_name)
local res = stmt:step() local res = stmt:step()
@ -534,11 +534,6 @@ end
-- Returns a list of orders, sorted by price. -- Returns a list of orders, sorted by price.
function ex_methods.search_orders(self, ex_name, order_type, item_name) function ex_methods.search_orders(self, ex_name, order_type, item_name)
local params = { ex_name = ex_name,
order_type = order_type,
item_name = item_name,
}
local stmt local stmt
if order_type == "buy" then if order_type == "buy" then
stmt = self.stmts.search_asc_stmt stmt = self.stmts.search_asc_stmt
@ -546,12 +541,17 @@ function ex_methods.search_orders(self, ex_name, order_type, item_name)
stmt = self.stmts.search_desc_stmt stmt = self.stmts.search_desc_stmt
end end
stmt:bind_names(params) stmt:bind_names({
ex_name = ex_name,
order_type = order_type,
item_name = item_name,
})
local orders = {} local orders,n = {},1
for tab in stmt:nrows() do for tab in stmt:nrows() do
table.insert(orders, tab) orders[n] = tab
n = n+1
end end
stmt:reset() stmt:reset()
@ -561,17 +561,15 @@ end
-- Same as above, except not sorted in any particular order. -- Same as above, except not sorted in any particular order.
function ex_methods.search_player_orders(self, p_name) function ex_methods.search_player_orders(self, p_name)
local params = { p_name = p_name,
}
local stmt = self.stmts.search_own_stmt local stmt = self.stmts.search_own_stmt
stmt:bind_names(params) stmt:bind_names({p_name = p_name})
local orders = {} local orders,n = {},1
for tab in stmt:nrows() do for tab in stmt:nrows() do
table.insert(orders, tab) orders[n] = tab
n = n+1
end end
stmt:reset() stmt:reset()
@ -692,31 +690,31 @@ end
-- remaining desired amount. Returns success. If succeeded, also returns amount -- remaining desired amount. Returns success. If succeeded, also returns amount
-- bought. If failed, returns an error message -- bought. If failed, returns an error message
function ex_methods.buy(self, p_name, ex_name, item_name, amount, rate) function ex_methods.buy(self, p_name, ex_name, item_name, amount, rate)
if math.floor(amount) ~= amount then if not is_integer(amount) then
return false, "Noninteger quantity" return false, "Noninteger quantity"
elseif amount <= 0 then elseif amount <= 0 then
return false, "Nonpositive quantity" return false, "Nonpositive quantity"
elseif math.floor(rate) ~= rate then elseif not is_integer(rate) then
return false, "Noninteger rate" return false, "Noninteger rate"
elseif rate <= 0 then elseif rate <= 0 then
return false, "Nonpositive rate" return false, "Nonpositive rate"
end end
local db = self.db local db = self.db
local bal = self:get_balance(p_name) local bal = self:get_balance(p_name)
if not bal then if not bal then
return false, "Nonexistent account." return false, "Nonexistent account."
end end
if bal < amount * rate then if bal < amount * rate then
return false, "Not enough money." return false, "Not enough money."
end end
db:exec("BEGIN TRANSACTION"); db:exec("BEGIN TRANSACTION");
local remaining = amount local remaining = amount
local del_stmt = self.stmts.del_order_stmt local del_stmt = self.stmts.del_order_stmt
@ -748,7 +746,7 @@ function ex_methods.buy(self, p_name, ex_name, item_name, amount, rate)
end end
del_stmt:reset() del_stmt:reset()
local ch_succ, ch_err = local ch_succ, ch_err =
self:change_balance(poster, rate * row_amount) self:change_balance(poster, rate * row_amount)
if not ch_succ then if not ch_succ then
search_stmt:reset() search_stmt:reset()
@ -756,7 +754,7 @@ function ex_methods.buy(self, p_name, ex_name, item_name, amount, rate)
return false, ch_err return false, ch_err
end end
local log_succ, log_err = local log_succ, log_err =
self:log(p_name .. " bought " .. row_amount .. " " self:log(p_name .. " bought " .. row_amount .. " "
.. item_name .. " from you. (+" .. item_name .. " from you. (+"
.. rate * row_amount .. ")", poster) .. rate * row_amount .. ")", poster)
@ -793,7 +791,7 @@ function ex_methods.buy(self, p_name, ex_name, item_name, amount, rate)
end end
red_stmt:reset() red_stmt:reset()
local ch_succ, ch_err = local ch_succ, ch_err =
self:change_balance(poster, rate * remaining) self:change_balance(poster, rate * remaining)
if not ch_succ then if not ch_succ then
search_stmt:reset() search_stmt:reset()
@ -801,7 +799,7 @@ function ex_methods.buy(self, p_name, ex_name, item_name, amount, rate)
return false, ch_err return false, ch_err
end end
local log_succ, log_err = local log_succ, log_err =
self:log(p_name .. " bought " .. remaining .. " " self:log(p_name .. " bought " .. remaining .. " "
.. item_name .. " from you. (+" .. item_name .. " from you. (+"
.. rate * remaining .. ")", poster) .. rate * remaining .. ")", poster)
@ -867,20 +865,20 @@ end
-- Tries to sell to orders at the provided rate, and posts an offer with any -- Tries to sell to orders at the provided rate, and posts an offer with any
-- remaining desired amount. Returns success. If failed, returns an error message. -- remaining desired amount. Returns success. If failed, returns an error message.
function ex_methods.sell(self, p_name, ex_name, item_name, amount, rate) function ex_methods.sell(self, p_name, ex_name, item_name, amount, rate)
if math.floor(amount) ~= amount then if not is_integer(amount) then
return false, "Noninteger quantity" return false, "Noninteger quantity"
elseif amount <= 0 then elseif amount <= 0 then
return false, "Nonpositive quantity" return false, "Nonpositive quantity"
elseif math.floor(rate) ~= rate then elseif not is_integer(rate) then
return false, "Noninteger rate" return false, "Noninteger rate"
elseif rate <= 0 then elseif rate <= 0 then
return false, "Nonpositive rate" return false, "Nonpositive rate"
end end
local db = self.db local db = self.db
db:exec("BEGIN TRANSACTION"); db:exec("BEGIN TRANSACTION");
local remaining = amount local remaining = amount
local revenue = 0 local revenue = 0
@ -913,7 +911,7 @@ function ex_methods.sell(self, p_name, ex_name, item_name, amount, rate)
end end
del_stmt:reset() del_stmt:reset()
local in_succ, in_err = local in_succ, in_err =
self:put_in_inbox(poster, item_name, row_amount) self:put_in_inbox(poster, item_name, row_amount)
if not in_succ then if not in_succ then
search_stmt:reset() search_stmt:reset()
@ -921,7 +919,7 @@ function ex_methods.sell(self, p_name, ex_name, item_name, amount, rate)
return false, in_err return false, in_err
end end
local log_succ, log_err = local log_succ, log_err =
self:log(p_name .. " sold " .. row_amount .. " " self:log(p_name .. " sold " .. row_amount .. " "
.. item_name .. " to you." , poster) .. item_name .. " to you." , poster)
if not log_succ then if not log_succ then
@ -958,7 +956,7 @@ function ex_methods.sell(self, p_name, ex_name, item_name, amount, rate)
end end
red_stmt:reset() red_stmt:reset()
local in_succ, in_err = local in_succ, in_err =
self:put_in_inbox(poster, item_name, remaining) self:put_in_inbox(poster, item_name, remaining)
if not in_succ then if not in_succ then
search_stmt:reset() search_stmt:reset()
@ -966,7 +964,7 @@ function ex_methods.sell(self, p_name, ex_name, item_name, amount, rate)
return false, in_err return false, in_err
end end
local log_succ, log_err = local log_succ, log_err =
self:log(p_name .. " sold " .. remaining .. " " self:log(p_name .. " sold " .. remaining .. " "
.. item_name .. " to you.", poster) .. item_name .. " to you.", poster)
if not log_succ then if not log_succ then
@ -986,7 +984,6 @@ function ex_methods.sell(self, p_name, ex_name, item_name, amount, rate)
end end
remaining = 0 remaining = 0
revenue = revenue + remaining * row.Rate
end end
if remaining == 0 then break end if remaining == 0 then break end
@ -1018,17 +1015,17 @@ end
-- On success, returns true and a list of inbox entries. -- On success, returns true and a list of inbox entries.
-- On failure, returns false and an error message. -- TODO: On failure, return false and an error message.
function ex_methods.view_inbox(self, p_name) function ex_methods.view_inbox(self, p_name)
local db = self.db
local stmt = self.stmts.view_inbox_stmt local stmt = self.stmts.view_inbox_stmt
stmt:bind_values(p_name) stmt:bind_values(p_name)
local res = {} local res,n = {},1
for row in stmt:nrows() do for row in stmt:nrows() do
table.insert(res, row) res[n] = row
n = n+1
end end
stmt:reset() stmt:reset()
@ -1049,7 +1046,7 @@ function ex_methods.take_inbox(self, id, amount)
id = id, id = id,
change = amount change = amount
}) })
local res = get_stmt:step() local res = get_stmt:step()
if res == sqlite3.BUSY then if res == sqlite3.BUSY then
@ -1066,7 +1063,7 @@ function ex_methods.take_inbox(self, id, amount)
get_stmt:reset() get_stmt:reset()
db:exec("BEGIN TRANSACTION;") db:exec("BEGIN TRANSACTION;")
if available > amount then if available > amount then
red_stmt:bind_names({ red_stmt:bind_names({
id = id, id = id,
@ -1115,18 +1112,18 @@ end
-- sell_volume: Number of items for sale -- sell_volume: Number of items for sale
-- sell_min: Minimum sell rate -- sell_min: Minimum sell rate
function ex_methods.market_summary(self) function ex_methods.market_summary(self)
local db = self.db
local stmt = self.stmts.summary_stmt local stmt = self.stmts.summary_stmt
local res = {} local res,n = {},1
for a in stmt:rows() do for a in stmt:rows() do
table.insert(res, { res[n] = {
item_name = a[1], item_name = a[1],
buy_volume = a[2], buy_volume = a[2],
buy_max = a[3], buy_max = a[3],
sell_volume = a[4], sell_volume = a[4],
sell_min = a[5], sell_min = a[5],
}) }
n = n+1
end end
stmt:reset() stmt:reset()
@ -1138,11 +1135,12 @@ end
function ex_methods.player_log(self, p_name) function ex_methods.player_log(self, p_name)
local stmt = self.stmts.transaction_log_stmt local stmt = self.stmts.transaction_log_stmt
stmt:bind_names({ p_name = p_name }) stmt:bind_names({ p_name = p_name })
local res = {} local res,n = {},1
for row in stmt:nrows() do for row in stmt:nrows() do
table.insert(res, row) res[n] = row
n = n+1
end end
stmt:reset() stmt:reset()
@ -1162,7 +1160,7 @@ function exports.test()
print("Bob: ", ex:get_balance("Bob")) print("Bob: ", ex:get_balance("Bob"))
end end
-- Initialize balances -- Initialize balances
if alice_bal then if alice_bal then
ex:set_balance("Alice", 420) ex:set_balance("Alice", 420)
@ -1178,7 +1176,7 @@ function exports.test()
print_balances() print_balances()
-- Transfer a valid amount -- Transfer a valid amount
print("Transfering 1000 credits from Bob to Alice") print("Transfering 1000 credits from Bob to Alice")
@ -1207,7 +1205,7 @@ function exports.test()
local succ, err = ex:sell("Bob", "", "default:cobble", 20, 1) local succ, err = ex:sell("Bob", "", "default:cobble", 20, 1)
print("Success: ", succ, " ", err) print("Success: ", succ, " ", err)
print_balances() print_balances()
ex:close() ex:close()
end end

View File

@ -3,46 +3,41 @@ local exchange = ...
local search_cooldown = 2 local search_cooldown = 2
local summary_interval = 600 local summary_interval = 600
local summary_fs = ""
local function mk_summary_fs() local function mk_summary_fs()
local summary = exchange:market_summary() local res = {
local res = {} "size[8,8]",
table.insert(res, "size[8,8]") "label[0,0;Updated Periodically]",
table.insert(res, "label[0,0;Updated Periodically]") "tablecolumns[text;text;text;text;text;text]",
table.insert(res, "tablecolumns[text;text;text;text;text;text]") "table[0,1;8,6;summary_table;",
table.insert(res, "table[0,1;8,6;summary_table;") "Item,Description,Buy Vol,Buy Max,Sell Vol,Sell Min"
table.insert(res, "Item,Description,Buy Vol,Buy Max,Sell Vol,Sell Min") }
local all_items = minetest.registered_items local all_items = minetest.registered_items
for i, row in ipairs(summary) do for i, row in ipairs(exchange:market_summary()) do
table.insert(res, "," .. row.item_name) local n = #res+1
local def = all_items[row.item_name] res[n] = "," .. row.item_name
if def then local def = all_items[row.item_name] or {}
table.insert(res, "," .. def.description) res[n+1] = "," .. (def.description or "Unknown Item")
else res[n+2] = "," .. (row.buy_volume or 0)
table.insert(res, "," .. "Unknown Item") res[n+3] = "," .. (row.buy_max or "N/A")
end res[n+4] = "," .. (row.sell_volume or 0)
table.insert(res, "," .. (row.buy_volume or 0)) res[n+5] = "," .. (row.sell_min or "N/A")
table.insert(res, "," .. (row.buy_max or "N/A"))
table.insert(res, "," .. (row.sell_volume or 0))
table.insert(res, "," .. (row.sell_min or "N/A"))
end end
table.insert(res, "]") res[#res+1] = "]"
table.insert(res, "button[3,7;2,1;back;Back]") res[#res+1] = "button[3,7;2,1;back;Back]"
return table.concat(res) summary_fs = table.concat(res)
end end
local summary_fs = "" minetest.after(0, mk_summary_fs)
minetest.after(0, function()
summary_fs = mk_summary_fs()
end)
local elapsed = 0 local elapsed = 0
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
elapsed = elapsed + dtime elapsed = elapsed + dtime
if elapsed >= summary_interval then if elapsed >= summary_interval then
summary_fs = mk_summary_fs() mk_summary_fs()
elapsed = 0 elapsed = 0
end end
end) end)
@ -61,17 +56,12 @@ local main_state = {}
-- a cooldown on searches -- a cooldown on searches
-- sell: A boolean whether the player has sell selected -- sell: A boolean whether the player has sell selected
local function default_main_state()
return { old_fields = {},
search_results = {},
last_search_time = 0,
}
end
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
main_state[player:get_player_name()] = default_main_state() main_state[player:get_player_name()] = {
old_fields = {},
search_results = {},
last_search_time = 0,
}
end) end)
minetest.register_on_leaveplayer(function(player) minetest.register_on_leaveplayer(function(player)
@ -87,16 +77,18 @@ local tablecolumns =
local function table_from_results(results, x, y, w, h, selected) local function table_from_results(results, x, y, w, h, selected)
local fs_tab = {} local fs_tab
local function insert(str) local function insert(str)
table.insert(fs_tab, str) fs_tab[#fs_tab+1] = str
end end
insert(tablecolumns) fs_tab = {
insert("table[" .. x .. "," .. y .. ";" .. w .. "," .. h .. ";") tablecolumns,
insert("result_table;") "table[" .. x .. "," .. y .. ";" .. w .. "," .. h .. ";",
insert("Poster,Type,Item,Description,Amount,Rate") "result_table;",
"Poster,Type,Item,Description,Amount,Rate"
}
local all_items = minetest.registered_items local all_items = minetest.registered_items
@ -108,11 +100,8 @@ local function table_from_results(results, x, y, w, h, selected)
insert(",") insert(",")
insert(tostring(row.Item)) insert(tostring(row.Item))
insert(",") insert(",")
if all_items[row.Item] then local def = all_items[row.Item] or {}
insert(all_items[row.Item].description) insert(def.description or "Unknown Item")
else
insert("Unknown Item")
end
insert(",") insert(",")
insert(tostring(row.Amount)) insert(tostring(row.Amount))
insert(",") insert(",")
@ -130,8 +119,6 @@ end
local function mk_main_fs(p_name, new_item, err_str, success) local function mk_main_fs(p_name, new_item, err_str, success)
local fs = "size[8,9]"
local state = main_state[p_name] local state = main_state[p_name]
if not state then return end -- Should have been initialized on player join if not state then return end -- Should have been initialized on player join
@ -145,21 +132,22 @@ local function mk_main_fs(p_name, new_item, err_str, success)
local bal = exchange:get_balance(p_name) local bal = exchange:get_balance(p_name)
local fs
if bal then if bal then
fs = fs .. "label[0,0;Balance: " .. bal .. "]" fs = "label[0,0;Balance: " .. bal .. "]"
else else
fs = fs .. "label[0.2,0.5;Use an ATM to make your account.]" fs = "label[0.2,0.5;Use an ATM to make your account.]"
end end
fs = fs .. "button[4,0;2,1;summary;Market Summary]" fs = fs .. "button[4,0;2,1;summary;Market Summary]" ..
fs = fs .. "button[6,0;2,1;your_orders;Your Orders]" "button[6,0;2,1;your_orders;Your Orders]" ..
fs = fs .. "field[0.2,1.5;3,1;item;Item: ;" .. item_def .. "]" "field[0.2,1.5;3,1;item;Item: ;" .. item_def .. "]" ..
fs = fs .. "field[3.2,1.5;3,1;amount;Amount: ;" .. amount_def .. "]" "field[3.2,1.5;3,1;amount;Amount: ;" .. amount_def .. "]" ..
fs = fs .. "button[6,1;2,1.4;select_item;Select Item]" "button[6,1;2,1.4;select_item;Select Item]" ..
fs = fs .. "checkbox[5,3;sell;Sell;" .. tostring(sell_def) .. "]" "checkbox[5,3;sell;Sell;" .. tostring(sell_def) .. "]" ..
fs = fs .. "field[0.2,2.5;2,1;rate;Rate: ;" .. rate_def .. "]" "field[0.2,2.5;2,1;rate;Rate: ;" .. rate_def .. "]" ..
fs = fs .. "button[2,2;2,1.4;search;Search]" "button[2,2;2,1.4;search;Search]" ..
fs = fs .. "button[4,2;3,1.4;post_order;Post Order]" "button[4,2;3,1.4;post_order;Post Order]"
if err_str then if err_str then
fs = fs .. "label[0,3;Error: " .. err_str .. "]" fs = fs .. "label[0,3;Error: " .. err_str .. "]"
@ -169,9 +157,7 @@ local function mk_main_fs(p_name, new_item, err_str, success)
fs = fs .. "label[0,3;Success!]" fs = fs .. "label[0,3;Success!]"
end end
fs = fs .. table_from_results(results, 0, 4, 8, 5, selected_def) return "size[8,9]" .. fs .. table_from_results(results, 0, 4, 8, 5, selected_def)
return fs
end end
@ -181,15 +167,16 @@ end
-- Something similar to creative inventory -- Something similar to creative inventory
local selectable_inventory_size = 0 local pagemax = 1
-- Create detached inventory after loading all mods -- Create detached inventory after loading all mods
minetest.after(0, function() minetest.after(0, function()
local inv = minetest.create_detached_inventory("global_exchange", { local inv = minetest.create_detached_inventory("global_exchange", {
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player) allow_move = function(inv, from_list, _, to_list, _,_, player)
local p_name = player:get_player_name() local p_name = player:get_player_name()
if from_list == "main" and to_list == "p_" .. p_name then if from_list == "main"
and to_list == "p_" .. p_name then
return 1 return 1
else else
return 0 return 0
@ -201,7 +188,7 @@ minetest.after(0, function()
allow_take = function() allow_take = function()
return 0 return 0
end, end,
on_move = function(inv, from_list, from_index, to_list, to_index, count, player) on_move = function(inv, _, _, _, _, _, player)
local p_name = player:get_player_name() local p_name = player:get_player_name()
local p_list = "p_" .. p_name local p_list = "p_" .. p_name
@ -212,11 +199,14 @@ minetest.after(0, function()
end, end,
}) })
local selectable_list = {} 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 or def.groups.not_in_creative_inventory == 0) if (not def.groups.not_in_creative_inventory
and def.description and def.description ~= "" then or def.groups.not_in_creative_inventory == 0)
table.insert(selectable_list, name) and def.description
and def.description ~= "" then
selectable_list[n] = name
n = n+1
end end
end end
table.sort(selectable_list) table.sort(selectable_list)
@ -225,32 +215,29 @@ minetest.after(0, function()
inv:add_item("main", ItemStack(itemstring)) inv:add_item("main", ItemStack(itemstring))
end end
selectable_inventory_size = #selectable_list pagemax = math.ceil((#selectable_list - 1) / (8 * 4))
end) end)
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
local big_inv = minetest.get_inventory({type="detached", name="global_exchange"}) -- the inventory list name is "p_"..player_name
local p_list = "p_" .. player:get_player_name() minetest.get_inventory({
type="detached",
big_inv:set_size(p_list, 1) name="global_exchange"
}):set_size("p_" .. player:get_player_name(), 1)
end) end)
local select_form = "global_exchange:select_form" local select_form = "global_exchange:select_form"
local function mk_select_formspec(p_name, start_i, pagenum) local function mk_select_formspec(p_name, start_i, pagenum)
pagenum = math.floor(pagenum)
local pagemax = math.floor((selectable_inventory_size - 1) / (8 * 4) + 1)
local p_list = "p_" .. p_name
return "size[9.3,8]" .. return "size[9.3,8]" ..
"list[detached:global_exchange;main;0.3,0.5;8,4;" .. tostring(start_i) .. "]" .. "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[0.3,4.5;1.6,1;select_prev;<<]"..
"button[6.7,4.5;1.6,1;select_next;>>]".. "button[6.7,4.5;1.6,1;select_next;>>]"..
"label[2.0,5.55;"..tostring(pagenum).."/"..tostring(pagemax).."]".. "label[2.0,5.55;"..tostring(math.floor(pagenum)).."/"..tostring(pagemax).."]"..
"list[detached:global_exchange;" .. p_list .. ";0.3,7;1,1;]" "list[detached:global_exchange;p_" .. p_name .. ";0.3,7;1,1;]"
end end
@ -274,17 +261,12 @@ local own_state = {}
-- own_results: Results for own orders. -- own_results: Results for own orders.
local function mk_own_orders_fs(p_name, results, selected) local function mk_own_orders_fs(p_name, results, selected)
local fs = "size[8,8]" return "size[8,8]" ..
"label[0.5,0.2;Your Orders]" ..
local state = main_state[p_name] "button[6,0;2,1;refresh;Refresh]" ..
table_from_results(results, 0, 2, 8, 4.5, selected or "") ..
fs = fs .. "label[0.5,0.2;Your Orders]" "button[0,7;2,1;cancel;Cancel]" ..
fs = fs .. "button[6,0;2,1;refresh;Refresh]" "button[3,7;2,1;back;Back]"
fs = fs .. table_from_results(results, 0, 2, 8, 4.5, selected or "")
fs = fs .. "button[0,7;2,1;cancel;Cancel]"
fs = fs .. "button[3,7;2,1;back;Back]"
return fs
end end
@ -296,11 +278,11 @@ 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_order(player, ex_name, order_type, item_name, 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 == "" then
return false, "You must input an item" return false, "You must input an item"
end end
if 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
@ -323,7 +305,7 @@ local function post_order(player, ex_name, order_type, item_name, amount_str, ra
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) stack:set_count(amount)
if order_type == "buy" then if order_type == "buy" then
if not p_inv:room_for_item("main", stack) then if not p_inv:room_for_item("main", stack) then
return false, "Not enough space in inventory." return false, "Not enough space in inventory."
@ -353,8 +335,7 @@ local function post_order(player, ex_name, order_type, item_name, amount_str, ra
end end
local function handle_main(player, formname, fields) local function handle_main(player, fields)
if formname ~= main_form then return end
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 local old_fields = state.old_fields
@ -363,17 +344,17 @@ local function handle_main(player, formname, fields)
old_fields[k] = v old_fields[k] = v
end end
if fields["select_item"] then if fields.select_item then
show_select(p_name) show_select(p_name)
end end
if fields["search"] then if fields.search then
local now = os.time() local now = os.time()
local last_search = state.last_search_time local last_search = state.last_search_time
if now - last_search < search_cooldown then if now - last_search < search_cooldown then
show_main(p_name, nil, "Please wait before searching again.") show_main(p_name, nil, "Please wait before searching again.")
return true return
end end
-- If the player is selling, she wants "buy" type offers. -- If the player is selling, she wants "buy" type offers.
@ -392,22 +373,18 @@ local function handle_main(player, formname, fields)
show_main(p_name) show_main(p_name)
end end
if fields["sell"] then if fields.sell then
if fields["sell"] == "true" then state.sell = fields.sell == "true"
state.sell = true
else
state.sell = false
end
end end
if fields["post_order"] then
if fields.post_order then
local now = os.time() local now = os.time()
local last_search = state.last_search_time local last_search = state.last_search_time
if now - last_search < search_cooldown then if now - last_search < search_cooldown then
show_main(p_name, nil, "Please wait before posting.") show_main(p_name, nil, "Please wait before posting.")
return true return
end end
local order_type local order_type
@ -416,12 +393,9 @@ local function handle_main(player, formname, fields)
else else
order_type = "buy" order_type = "buy"
end end
local item_name = fields["item"]
local amount_str = fields["amount"]
local rate_str = fields["rate"]
local succ, err = local succ, err =
post_order(player, "", order_type, item_name, amount_str, rate_str) post_order(player, "", order_type, fields.item, fields.amount, fields.rate)
if succ then if succ then
state.search_results = {} state.search_results = {}
@ -432,17 +406,17 @@ local function handle_main(player, formname, fields)
end end
if fields["result_table"] then if fields.result_table then
local results = state.search_results local results = state.search_results
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
return true return
end end
local index = event.row - 1 local index = event.row - 1
result = results[index] result = results[index]
if result then if result then
old_fields.amount = tostring(result.Amount) old_fields.amount = tostring(result.Amount)
old_fields.rate = tostring(result.Rate) old_fields.rate = tostring(result.Rate)
@ -451,11 +425,11 @@ local function handle_main(player, formname, fields)
show_main(p_name) show_main(p_name)
end end
if fields["summary"] then if fields.summary then
show_summary(p_name) show_summary(p_name)
end end
if fields["your_orders"] then if fields.your_orders then
if not own_state[p_name] then if not own_state[p_name] then
own_state[p_name] = {} own_state[p_name] = {}
end end
@ -465,46 +439,37 @@ local function handle_main(player, formname, fields)
show_own_orders(p_name, o_state.own_results) show_own_orders(p_name, o_state.own_results)
end end
return true
end end
local function handle_select(player, formname, fields) local function handle_select(player, fields)
if formname ~= select_form then return end
local p_name = player:get_player_name() local p_name = player:get_player_name()
local pagemax = math.floor((selectable_inventory_size - 1) / (8 * 4) + 1)
local pagenum = player_pages[p_name] or 1 local pagenum = player_pages[p_name] or 1
if fields["select_prev"] then if fields.select_prev then
player_pages[p_name] = math.max(1, pagenum - 1) player_pages[p_name] = math.max(1, pagenum - 1)
show_select(p_name) show_select(p_name)
elseif fields["select_next"] then elseif fields.select_next then
player_pages[p_name] = math.min(pagemax, pagenum + 1) player_pages[p_name] = math.min(pagemax, pagenum + 1)
show_select(p_name) show_select(p_name)
end end
return true
end end
local function handle_own_orders(player, formname, fields) local function handle_own_orders(player, fields)
if formname ~= own_form then return end
local p_name = player:get_player_name() local p_name = player:get_player_name()
local state = own_state[p_name] or {} local state = own_state[p_name] or {}
local results = state.own_results or {} local results = state.own_results or {}
local idx = state.selected_index local idx = state.selected_index
if fields["refresh"] then if fields.refresh then
state.own_results = exchange:search_player_orders(p_name) or {} state.own_results = exchange:search_player_orders(p_name) or {}
show_own_orders(p_name, state.own_results) show_own_orders(p_name, state.own_results)
end end
if fields["cancel"] and idx then if fields.cancel and idx then
local row = results[idx] local row = results[idx]
if not row then return true end if not row then return true end
local p_inv = player:get_inventory() local p_inv = player:get_inventory()
@ -535,39 +500,41 @@ local function handle_own_orders(player, formname, fields)
show_own_orders(p_name, state.own_results) show_own_orders(p_name, state.own_results)
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_own_orders(p_name, results, event.row)
end end
end end
if fields["back"] then if fields.back then
show_main(p_name) show_main(p_name)
end end
return true
end end
local function handle_summary(player, formname, fields) local function handle_summary(player, fields)
if formname ~= summary_form then return end if fields.back then
show_main(player:get_player_name())
local p_name = player:get_player_name()
if fields["back"] then
show_main(p_name)
end end
return true
end end
minetest.register_on_player_receive_fields(handle_main) minetest.register_on_player_receive_fields(function(player, formname, fields)
minetest.register_on_player_receive_fields(handle_select) if formname == main_form then
minetest.register_on_player_receive_fields(handle_own_orders) handle_main(player, fields)
minetest.register_on_player_receive_fields(handle_summary) 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
return
end
return true
end)
minetest.register_node("global_exchange:exchange", { minetest.register_node("global_exchange:exchange", {
@ -577,7 +544,7 @@ minetest.register_node("global_exchange:exchange", {
"global_exchange_exchange_side.png", "global_exchange_exchange_side.png",
}, },
groups = {cracky=2}, groups = {cracky=2},
on_rightclick = function(pos, node, clicker) on_rightclick = function(_, _, clicker)
local p_name = clicker:get_player_name() local p_name = clicker:get_player_name()
local state = main_state[p_name] local state = main_state[p_name]
if state then if state then

View File

@ -1,9 +1,7 @@
local modpath = minetest.get_modpath(minetest.get_current_modname()) .. "/" local modpath = minetest.get_modpath(minetest.get_current_modname()) .. "/"
local savepath = minetest.get_worldpath() .. "/global_exchange.db"
local income_str = minetest.setting_get("citizens_income") local income = tonumber(minetest.setting_get("citizens_income")) or 10
local income = income_str and tonumber(income_str) or 10
local income_interval = 1200 local income_interval = 1200
@ -11,41 +9,40 @@ local income_msg = "You receive your citizen's income (+" .. income .. ")"
local next_payout = os.time() + income_interval local next_payout = os.time() + income_interval
local ex = dofile(modpath .. "exchange.lua") local exchange = (dofile(modpath .. "exchange.lua")).open_exchange(
local exchange = ex.open_exchange(savepath) minetest.get_worldpath() .. "/global_exchange.db"
)
minetest.register_on_shutdown(function() minetest.register_on_shutdown(function()
exchange:close() exchange:close()
end) end)
-- Only check once in a while local function check_giving()
local elapsed = 0 local now = os.time()
if now < next_payout then
return
end
minetest.register_globalstep(function(dtime) next_payout = now + income_interval
elapsed = elapsed + dtime
if elapsed <= 5 then return end
elapsed = 0 for _, player in ipairs(minetest.get_connected_players()) do
local p_name = player:get_player_name()
local now = os.time() local succ = exchange:give_credits(p_name, income,
if now < next_payout then return end "Citizen's Income (+" .. income .. ")")
next_payout = now + income_interval if succ then
minetest.chat_send_player(p_name, income_msg)
for i, 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 end
end) end
minetest.after(5, check_giving)
end
minetest.after(5, check_giving)
assert(loadfile(modpath .. "atm.lua"))(exchange) assert(loadfile(modpath .. "atm.lua"))(exchange)