capitalism_game/mods/capitalism/shop/api.lua

233 lines
5.2 KiB
Lua

--- Adds shops
--
-- @module shop
_.extend(shop, {
_shops = {},
_shops_by_area = {},
_context = {}
})
--- Get a shop by its `land` area ID
--
-- @int aid
function shop.get_by_area(aid)
assert(type(aid) == "number")
return shop._shops_by_area[aid]
end
--- @pos pos
function shop.get_by_pos(pos)
assert(type(pos) == "table")
local area = land.get_by_pos(pos)
return area and shop.get_by_area(area.id)
end
--- @tparam table s
function shop.add_shop(s)
assert(not shop._shops_by_area[s.a_id])
shop._shops[#shop._shops + 1] = s
shop._shops_by_area[s.a_id] = s
return true
end
--- Checks whether a user can use the admin interface for the shop
--
-- @player pname
-- @pos pos
function shop.can_admin(pname, pos)
local area = land.get_by_pos(pos)
local comp = company.get_by_name(area.owner)
return comp and
company.check_perm(pname, comp.name, "SHOP_ADMIN", { pos = pos })
end
--- Creates shops, checks permissions
--
-- @player pname
-- @pos pos
-- @treturn true
-- @error Error message
function shop.create_shop(pname, pos)
local area = land.get_by_pos(pos)
local comp = company.get_by_name(area.owner)
if not comp then
return false, "You need to select a company to operate as"
end
if not company.check_perm(pname, comp.name, "SHOP_CREATE", { pos = pos }) then
return false, "Missing permission: SHOP_CREATE"
end
local s = shop.Shop:new()
s.a_id = area.id
s.name = area.name
shop.add_shop(s)
shop.dirty = true
return true
end
--- Unassigns item allocation of chest. Will return any items.
--
-- @shop s
-- @pos pos
-- @param inv Inventory userdata
function shop.unassign_chest(s, pos, inv)
local chest = s:get_chest(pos)
if chest.itemname then
local stack = ItemStack(chest.itemname)
stack:set_count(chest.count)
if inv and inv:room_for_item("main", stack) then
inv:add_item("main", stack)
end
local node_inv = minetest.get_inventory({ type = "node", pos = pos })
node_inv:set_list("main", {})
local new = s:get_item_or_make(chest.itemname)
new.stock = new.stock - chest.count
end
chest.itemname = nil
chest.count = 0
end
--- Can user buy from shop, checks permissions
--
-- @pos pos
-- @player pname
-- @string itemname
-- @int count
-- @int price
-- @treturn true
-- @error Error message
function shop.can_buy(pos, pname, itemname, count, price)
assert(type(pos) == "table")
assert(type(pname) == "string")
assert(type(itemname) == "string" and minetest.registered_items[itemname])
assert(type(count) == "number" and count >= 0)
assert(type(price) == "number" and price >= 0)
local comp = company.get_active(pname)
if comp and not comp:check_perm(pname, "BUY_ITEMS",
{ itemname = itemname, count = count, price = price }) then
return false, "Missing permission: BUY_ITEMS"
end
local acc = banking.get_by_owner(comp and comp.name or pname)
if not acc then
return false, "You don't have a bank account"
end
if acc.balance < price then
return false, "Insufficient funds"
end
return true
end
--- Buy from shop, checks permissions
--
-- @pos pos
-- @player pname
-- @tparam table item
-- @int count
--
-- @treturn true
-- @error Error message
function shop.buy(pos, pname, item, count)
assert(type(pos) == "table")
assert(type(pname) == "string")
assert(type(item) == "table")
assert(type(count) == "number" and count >= 0)
if count > item.stock then
return false, "Not enough stock"
end
local price = count * item.price
local suc, msg = shop.can_buy(pos, pname, item.name, count, price)
if not suc then
return false, msg
end
local to_give = ItemStack({ name = item.name, count = count })
local pinv = minetest.get_inventory({ type = "player", name = pname })
if not pinv:room_for_item("main", to_give) then
return false, "Not enough room in inv"
end
local area = land.get_by_pos(pos)
assert(area.owner:sub(1, 2) == "c:")
local s = shop.get_by_area(area.id)
local comp = company.get_active(pname)
local account = banking.get_by_owner(comp and comp.name or pname)
local owner_account = banking.get_by_owner(area.owner)
assert(account)
assert(owner_account)
-- Locate chest
local chests = s:get_chests_for_item(item.name, count, function(chest)
return minetest.get_node(chest.pos) ~= "ignore"
end)
if not chests then
return false, "Map unloaded"
-- chests = s:get_chests_for_item(item.name, count)
--
-- if not chests then
-- return false, "Error: unexpected out of stock. This should never happen."
-- end
end
local took = 0
for i=1, #chests do
local inv = minetest.get_inventory({ type = "node", pos = chests[i].pos })
local stack = inv:remove_item("main", { name = item.name, count = count - took })
if not stack:is_empty() then
took = took + stack:get_count()
s:chest_remove_item(chests[i].pos, stack)
if took == count then
break
end
end
end
assert(took == count)
if not banking.transfer(pname, account.owner, owner_account.owner, price,
"Purchase of item name=" .. item.name .. ", count=" .. count) then
return false, "Card payment error"
end
pinv:add_item("main", to_give)
shop.dirty = true
return true
end
-- Minetest won't be available in tests
if minetest then
local storage = minetest.get_mod_storage()
lib_utils.make_saveload(shop, storage, "_shops", "add_shop", shop.Shop)
shop.load()
end