people/actions/buy_and_sell.lua

149 lines
5.0 KiB
Lua

local dbg
if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=function() end,v3=function() end} end
-- Find a shop in range of the given position that's dealing in the
-- item specified. If 'buy' is true, we want to buy, otherwise we
-- want to sell. Returns shopinfo. (or nil)
local function near_shop(pos, item, buy)
local range = {x=4, y=2, z=4}
local minp = vector.subtract(pos, range)
local maxp = vector.add(pos, range)
local shops = minetest.find_nodes_in_area(minp, maxp, {"barrel:shop_barrel"})
for _, p in pairs(shops) do
local shopinfo = barrel.get_shopinfo(p)
if shopinfo and shopinfo.item == item then
if buy then
if shopinfo.saleunit > 0 and
shopinfo.price > 0 and
shopinfo.stock >= shopinfo.saleunit then
return shopinfo
end
else
if shopinfo.saleunit > 0 and
shopinfo.buyprice > 0 then
return shopinfo
end
end
end
end
return nil
end
local function move_all(srcinv, srclist, destinv, destlist, item)
local moved_all = true
local moved_num = 0
for i=1,srcinv:get_size(srclist) do
local stk = srcinv:get_stack(srclist, i)
if not item or stk:get_name() == item then
if destinv:room_for_item(destlist, stk) then
moved_num = moved_num + stk:get_count()
srcinv:set_stack(srclist, i, nil)
destinv:add_item(destlist, stk)
else
moved_all = false
end
end
end
return moved_all, moved_num
end
people.actions.buy = function(state)
if not (state.action.item or state.action.num) then
dbg.v1(state.ent.name.." has invalid buy action")
return true, false
end
local shopinfo = near_shop(state.pos, state.action.item, true)
if not shopinfo then
dbg.v1(state.ent.name.." is not near an appropriate shop")
return true, false
end
local yaw = vector.get_yaw(state.pos, shopinfo.pos)
-- Need to be fuzzy about comparing this, because of the
-- lua double/minetest float issue
if math.abs(yaw - state.yaw) > 0.2 then
dbg.v3(state.ent.name.." turning to face shop")
state.action = {"face", yaw=yaw, prevaction=state.action}
return false
end
local shopinv = shopinfo.meta:get_inventory()
local repeats = math.ceil(state.action.num / shopinfo.saleunit)
local cashneeded = repeats * shopinfo.price
dbg.v3(state.ent.name.." trying to put $"..cashneeded.." into shop")
if not currency.remove_from_inv(state.ent.inventory, "main", cashneeded) then
dbg.v1(state.ent.name.." doesn't have enough money to buy")
return true, false
end
-- TODO - the following just assumes there's room for it - really need
-- to check and roll back, as we do for getting money
currency.put_to_inv(shopinv, "exchange", cashneeded)
local bought = 0
while repeats > 0 do
local success, msg = barrel.do_buy(shopinfo.pos)
if not success then
dbg.v3(state.ent.name.." failed during buy loop - shop said: "..msg)
break
end
bought = bought + shopinfo.saleunit
repeats = repeats - 1
end
if not move_all(shopinv, "exchange", state.ent.inventory, "main", nil) then
dbg.v1(state.ent.name.." couldn't retrieve everything from shop inventory")
end
dbg.v1(state.ent.name.." finished buy action - bought "..bought.." "..state.action.item)
return true, true
end
people.actions.sell = function(state)
if not state.action.item then
dbg.v1(state.ent.name.." has invalid sell action")
return true, false
end
local shopinfo = near_shop(state.pos, state.action.item, false)
if not shopinfo then
dbg.v1(state.ent.name.." is not near an appropriate shop")
return true, false
end
local yaw = vector.get_yaw(state.pos, shopinfo.pos)
-- Need to be fuzzy about comparing this, because of the
-- lua double/minetest float issue
if math.abs(yaw - state.yaw) > 0.2 then
dbg.v3(state.ent.name.." turning to face shop")
state.action = {"face", yaw=yaw, prevaction=state.action}
return false
end
local shopinv = shopinfo.meta:get_inventory()
local moved_all, num = move_all(state.ent.inventory, "main",
shopinv, "exchange", state.action.item)
if num == 0 then
dbg.v1(state.ent.name.." failed to put any "..state.action.item.." for sale into the shop")
return true, false
end
local repeats = math.floor(num / shopinfo.saleunit)
while repeats > 0 do
if not barrel.do_sell(shopinfo.pos) then break end
repeats = repeats - 1
end
if not move_all(shopinv, "exchange", state.ent.inventory, "main") then
dbg.v1(state.ent.name.." couldn't retrieve everything from shop inventory")
end
dbg.v1(state.ent.name.." finished sell action")
return true, true
end