advanced_market/init.lua
2013-12-05 13:40:09 +00:00

255 lines
11 KiB
Lua

--[[
--Advanced market mod by arsdragonfly
--]]
advanced_market = {}
advanced_market.data = {}
function advanced_market.save_data()
if advanced_market.data.orders == nil then
advanced_market.data = {}
end
if advanced_market.data.stacks == nil then
advanced_market.data.stacks = {}
end
if advanced_market.data.buffers == nil then
advanced_market.data.buffers = {}
end
if advanced_market.data.orders == nil then
advanced_market.data.orders = {}
end
local output = io.open(minetest.get_worldpath() .. "/advanced_market","w")
output:write(minetest.serialize(advanced_market.data))
io.close(output)
end
function advanced_market.initialize()
local input = io.open(minetest.get_worldpath() .. "/advanced_market","r")
if input then
advanced_market.data = minetest.deserialize(input:read("*l"))
io.close(input)
else --first run; create the data file
advanced_market.save_data()
end
advanced_market.save_data()
end
function advanced_market.order(orderer,item,amount,price,ordertype)
--check if the buyer has sufficient money
if ordertype == "buy" then
if amount * price > money.get_money(orderer) then
return false
end
end
--pick an order number
local order_number = advanced_market.data.max_order_number or 1
advanced_market.data.max_order_number = order_number + 1
--initialize some stuff in the buffer if it's the orderer's first order
--into: everything going in; out: everything goint out(money to be paid etc.)
if advanced_market.data.buffers[orderer] == nil then
advanced_market.data.buffers[orderer] = {}
end
if advanced_market.data.buffers[orderer].out == nil then
advanced_market.data.buffers[orderer].out = {}
end
if advanced_market.data.buffers[orderer].into == nil then
advanced_market.data.buffers[orderer].into = {}
end
if advanced_market.data.buffers[orderer].out.money == nil then
advanced_market.data.buffers[orderer].out.money = 0
end
if advanced_market.data.buffers[orderer].out.items == nil then
advanced_market.data.buffers[orderer].out.items = {}
end
if advanced_market.data.buffers[orderer].out.items[item] == nil then
advanced_market.data.buffers[orderer].out.items[item] = 0
end
if advanced_market.data.buffers[orderer].into.money == nil then
advanced_market.data.buffers[orderer].into.money = 0
end
if advanced_market.data.buffers[orderer].into.items == nil then
advanced_market.data.buffers[orderer].into.items = {}
end
if advanced_market.data.buffers[orderer].into.items[item] == nil then
advanced_market.data.buffers[orderer].into.items[item] = 0
end
--add some stuff to the buffer
if ordertype == "buy" then
advanced_market.data.buffers[orderer].out.money = advanced_market.data.buffers[orderer].out.money + amount * price
money.set_money(orderer,money.get_money(orderer) - amount * price)
else -- ordertype is sell
advanced_market.data.buffers[orderer].out.items[item] = advanced_market.data.buffers[orderer].out.items[item] + amount
end
--add to the orders list
advanced_market.save_order(order_number,orderer,item,amount,price,ordertype,amount)
advanced_market.save_order_in_stack(order_number,orderer,item,amount,price,ordertype,amount)
--process the order in stack
if advanced_market.search_for_target_order_in_stack(item,price,ordertype) then
while true do
local target_order_number = advanced_market.search_for_target_order_in_stack(item,price,ordertype)
advanced_market.transact(order_number,target_order_number,item)
--don't stop until there's no more items/available orders
if advanced_market.data.orders[order_number].amount_left == 0 then break end
if not advanced_market.search_for_target_order_in_stack(item,price,ordertype) then break end
end
end
advanced_market.save_data()
end
function advanced_market.save_order(order_number,orderer,item,amount,price,ordertype,amount_left)
if advanced_market.data.orders[order_number] == nil then
advanced_market.data.orders[order_number] = {}
end
advanced_market.data.orders[order_number].orderer = orderer
advanced_market.data.orders[order_number].item = item
advanced_market.data.orders[order_number].amount = amount
advanced_market.data.orders[order_number].price = price
advanced_market.data.orders[order_number].ordertype = ordertype
advanced_market.data.orders[order_number].amount_left = amount_left
advanced_market.save_data()
end
function advanced_market.save_order_in_stack(order_number,orderer,item,amount,price,ordertype,amount_left)
if advanced_market.data.stacks[item] == nil then
advanced_market.data.stacks[item] = {}
end
if advanced_market.data.stacks[item][order_number] == nil then
advanced_market.data.stacks[item][order_number] = {}
end
advanced_market.data.stacks[item][order_number].orderer = orderer
advanced_market.data.stacks[item][order_number].item = item
advanced_market.data.stacks[item][order_number].amount = amount
advanced_market.data.stacks[item][order_number].price = price
advanced_market.data.stacks[item][order_number].ordertype = ordertype
advanced_market.data.stacks[item][order_number].amount_left = amount_left
advanced_market.save_data()
end
function advanced_market.search_for_target_order_in_stack(item,price,ordertype)
--return the best target order number or false
--orders are sorted according to price and time (order number)
if advanced_market.data.stacks[item] == nil then
return false
end
local best_order_number = 0
if ordertype == "buy" then
target_ordertype = "sell"
else
target_ordertype = "buy"
end
for order_number , content in pairs(advanced_market.data.stacks[item]) do
if advanced_market.data.stacks[item][best_order_number] == nil then
best_price = price
else
best_price = advanced_market.data.stacks[item][best_order_number].price
end
if target_ordertype == "buy" then
if content.ordertype == "buy" then
if content.price > best_price then
best_order_number = order_number
else if (content.price == best_price) and ((order_number < best_order_number) or (best_order_number == 0 )) then
best_order_number = order_number
end
end
end
else -- target ordertype is sell
if content.ordertype == "sell" then
if content.price < best_price then
best_order_number = order_number
else if (content.price == best_price) and ((order_number < best_order_number) or (best_order_number == 0)) then
best_order_number = order_number
end
end
end
end
end
if best_order_number == 0 then
return false
else
return best_order_number
end
end
function advanced_market.transact(order_number,target_order_number,item)
local orderer = advanced_market.data.orders[order_number].orderer
local target_orderer = advanced_market.data.orders[target_order_number].orderer
local price = advanced_market.data.orders[target_order_number].price
local transaction_amount = (advanced_market.data.stacks[item][order_number].amount_left < advanced_market.data.stacks[item][target_order_number].amount_left) and advanced_market.data.stacks[item][order_number].amount_left or advanced_market.data.stacks[item][target_order_number].amount_left
--choose the smaller one of the two order numbers as the transaction amount; .. and .. or .. is a ternary operator
advanced_market.data.stacks[item][order_number].amount_left = advanced_market.data.stacks[item][order_number].amount_left - transaction_amount
advanced_market.data.stacks[item][target_order_number].amount_left = advanced_market.data.stacks[item][target_order_number].amount_left - transaction_amount
if advanced_market.data.stacks[item][order_number].amount_left == 0 then advanced_market.remove_order_from_stack(order_number)end
if advanced_market.data.stacks[item][target_order_number].amount_left == 0 then advanced_market.remove_order_from_stack(target_order_number)end
--Modify the stack
advanced_market.data.orders[order_number].amount_left = advanced_market.data.orders[order_number].amount_left - transaction_amount
advanced_market.data.orders[target_order_number].amount_left = advanced_market.data.orders[target_order_number].amount_left - transaction_amount
--Modify the orders list
if advanced_market.data.orders[order_number].ordertype == "buy" then
--set the money and item in buffers
advanced_market.data.buffers[orderer].out.money = advanced_market.data.buffers[orderer].out.money - transaction_amount * price
advanced_market.data.buffers[target_orderer].into.money = advanced_market.data.buffers[target_orderer].into.money + transaction_amount * price
advanced_market.data.buffers[orderer].into.items[item] = advanced_market.data.buffers[orderer].into.items[item] + transaction_amount
advanced_market.data.buffers[target_orderer].out.items[item] = advanced_market.data.buffers[target_orderer].out.items[item] - transaction_amount
else --ordertype is sell
--set the money and item in buffers
advanced_market.data.buffers[orderer].into.money = advanced_market.data.buffers[orderer].into.money + transaction_amount * price
advanced_market.data.buffers[target_orderer].out.money = advanced_market.data.buffers[target_orderer].out.money - transaction_amount * price
advanced_market.data.buffers[orderer].out.items[item] = advanced_market.data.buffers[orderer].out.items[item] - transaction_amount
advanced_market.data.buffers[target_orderer].into.items[item] = advanced_market.data.buffers[target_orderer].into.items[item] + transaction_amount
end
advanced_market.save_data()
end
function advanced_market.remove_order_from_stack(order_number)
advanced_market.data.stacks[advanced_market.data.orders[order_number].item][order_number] = nil
end
advanced_market.initialize()
local register_chatcommand_table = {
params = "[buy <item> <amount> <price> | sell <price> | viewstack <item> | viewbuffer | refreshbuffer]",
description = "trade on the market",
func = function(name,param)
advanced_market.data.log = (advanced_market.data.log or "") .. name .. " , " .. param .. ";"
local t = string.split(param, " ")
if t[1] == "buy" then
advanced_market.order(name,t[2],tonumber(t[3]),tonumber(t[4]),"buy")
end
if t[1] == "sell" then
local player = minetest.get_player_by_name(name)
local wielditem = player:get_wielded_item()
local wieldname = wielditem:get_name()
advanced_market.data.log = advanced_market.data.log .. wieldname
local wieldcount = wielditem:get_count()
advanced_market.order(name,wieldname,wieldcount,tonumber(t[2]),"sell")
player:set_wielded_item(ItemStack(""))
end
if t[1] == "viewlog" then
minetest.chat_send_player(name,advanced_market.data.log)
end
if t[1] == "viewstack" then
minetest.chat_send_player(name,minetest.serialize(advanced_market.data.stacks[t[2]]))
end
if t[1] == "viewbuffer" then
minetest.chat_send_player(name,minetest.serialize(advanced_market.data.buffers[name]))
end
if t[1] == "refreshbuffer" then
local player = minetest.get_player_by_name(name)
local playerinv = player:get_inventory()
for k,v in pairs(advanced_market.data.buffers[name].into.items) do
playerinv:add_item("main",ItemStack(tostring(k).." "..tostring(v)))
advanced_market.data.buffers[name].into.items[k] = 0
end
money.set_money(name,money.get_money(name) + advanced_market.data.buffers[name].into.money)
advanced_market.data.buffers[name].into.money = 0
end
advanced_market.data.log = advanced_market.data.log .. "\n"
advanced_market.save_data()
end
}
minetest.register_chatcommand("advanced_market", register_chatcommand_table)
minetest.register_chatcommand("am", register_chatcommand_table)
minetest.register_chatcommand("amarket", register_chatcommand_table)