Add purchasing from shops
parent
3830040ad6
commit
8411dfd3ff
|
@ -9,4 +9,5 @@ company.permissions = {
|
|||
SHOP_CREATE = "Can create a shop on commercial areas",
|
||||
SHOP_ADMIN = "Can change the settings of a shop, including prices",
|
||||
SHOP_CHEST = "Can place, modify shop chests",
|
||||
BUY_ITEMS = "Can buy from shops",
|
||||
}
|
||||
|
|
|
@ -92,6 +92,107 @@ function shop.unassign_chest(s, pos, inv)
|
|||
chest.count = 0
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
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()
|
||||
|
|
|
@ -2,8 +2,7 @@ function shop.show_shop_form(pname, pos)
|
|||
if shop.can_admin(pname, pos) then
|
||||
shop.show_admin_form(pname, pos)
|
||||
else
|
||||
minetest.chat_send_player(pname, "Shop checkout unimplemented")
|
||||
-- shop.show_shop_checkout_form(playername, pos)
|
||||
shop.show_customer_form(pname, pos)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -170,3 +169,136 @@ shop.show_chest_form = lib_quickfs.register("shop:chest", {
|
|||
end
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
shop.show_customer_form = lib_quickfs.register("shop:customer", {
|
||||
get = function(context, player, pos)
|
||||
local s = shop.get_by_pos(pos)
|
||||
assert(s)
|
||||
|
||||
local fs = {
|
||||
"size[8,9.25]",
|
||||
company.get_company_header(context.pname, 8, "balance"),
|
||||
"label[4,1;",
|
||||
minetest.formspec_escape(s.name),
|
||||
"]",
|
||||
"tablecolumns[color;text;text;text]",
|
||||
"list[current_player;main;0,5.25;8,1;]",
|
||||
"list[current_player;main;0,6.48;8,3;8]",
|
||||
default.get_hotbar_bg(0, 5.25),
|
||||
"table[0,1;5.8,4;list_items;",
|
||||
"#999,Description,Stock,Price",
|
||||
}
|
||||
|
||||
-- Description Stock PricePI Sold
|
||||
|
||||
local items_kv = s:get_items()
|
||||
local items = {}
|
||||
context.items = items
|
||||
for _, item in pairs(items_kv) do
|
||||
if item.price >= 0 then
|
||||
local def = minetest.registered_items[item.name] or {}
|
||||
local desc = def.description or item.name
|
||||
|
||||
items[#items + 1] = item
|
||||
|
||||
fs[#fs + 1] = ",,"
|
||||
fs[#fs + 1] = desc
|
||||
fs[#fs + 1] = ","
|
||||
fs[#fs + 1] = item.stock
|
||||
fs[#fs + 1] = ","
|
||||
fs[#fs + 1] = item.price
|
||||
end
|
||||
end
|
||||
|
||||
if next(items) and not context.selected then
|
||||
context.selected = 1
|
||||
end
|
||||
|
||||
if context.selected then
|
||||
if context.selected > #items then
|
||||
context.selected = #items
|
||||
end
|
||||
|
||||
if context.selected and context.selected > 0 then
|
||||
fs[#fs + 1] = ";"
|
||||
fs[#fs + 1] = tostring(context.selected + 1)
|
||||
end
|
||||
end
|
||||
|
||||
fs[#fs + 1] = "]"
|
||||
|
||||
if context.selected and context.selected > 0 then
|
||||
local item = items[context.selected]
|
||||
local suc, msg = shop.can_buy(pos, context.pname, item.name, 0, 0)
|
||||
if suc then
|
||||
fs[#fs + 1] = "field[6.3,1.3;2,1;num;;"
|
||||
fs[#fs + 1] = tostring(context.num or 1)
|
||||
fs[#fs + 1] = "]"
|
||||
fs[#fs + 1] = "button[6,2;2,1;buyn;Buy]"
|
||||
else
|
||||
fs[#fs + 1] = "box[6,1;1.8,0.8;#f00]"
|
||||
fs[#fs + 1] = "box[6,2;1.8,0.8;#222]"
|
||||
fs[#fs + 1] = "label[6,1;"
|
||||
fs[#fs + 1] = minetest.formspec_escape(msg)
|
||||
fs[#fs + 1] = "]"
|
||||
end
|
||||
|
||||
if context.error then
|
||||
fs[#fs + 1] = "box[6,3;1.8,0.8;#f00]"
|
||||
fs[#fs + 1] = "label[6,3;"
|
||||
fs[#fs + 1] = minetest.formspec_escape(context.error)
|
||||
fs[#fs + 1] = "]"
|
||||
else
|
||||
fs[#fs + 1] = "box[6,3;1.8,0.8;#222]"
|
||||
end
|
||||
fs[#fs + 1] = "box[6,4;1.8,0.8;#222]"
|
||||
else
|
||||
fs[#fs + 1] = "box[6,1;1.8,0.8;#222]"
|
||||
fs[#fs + 1] = "box[6,2;1.8,0.8;#222]"
|
||||
fs[#fs + 1] = "box[6,3;1.8,0.8;#222]"
|
||||
fs[#fs + 1] = "box[6,4;1.8,0.8;#222]"
|
||||
end
|
||||
|
||||
return table.concat(fs, "")
|
||||
end,
|
||||
|
||||
on_receive_fields = function(context, player, fields, pos)
|
||||
if fields.switch then
|
||||
company.show_company_select_dialog(context.pname, function(player2)
|
||||
shop.show_customer_form(player2:get_player_name(), unpack(context.args))
|
||||
end)
|
||||
return
|
||||
end
|
||||
|
||||
if fields.list_items then
|
||||
local evt = minetest.explode_table_event(fields.list_items)
|
||||
context.selected = evt.row - 1
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.num then
|
||||
context.num = tonumber(fields.num) or 1
|
||||
end
|
||||
|
||||
if fields.buyn then
|
||||
local item = context.items[context.selected]
|
||||
if item then
|
||||
local count = tonumber(fields.num)
|
||||
if not count then
|
||||
context.error = "Not a number!"
|
||||
return true
|
||||
end
|
||||
|
||||
local _, msg = shop.buy(pos, context.pname, item, count)
|
||||
if msg then
|
||||
context.error = msg
|
||||
else
|
||||
context.error = nil
|
||||
end
|
||||
return true
|
||||
end
|
||||
return true
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
|
|
@ -67,6 +67,21 @@ function Shop:get_chest(pos)
|
|||
return self.chests[posstr]
|
||||
end
|
||||
|
||||
function Shop:get_chests_for_item(name, count, filter)
|
||||
local ret = {}
|
||||
for _, chest in pairs(self.chests) do
|
||||
if chest.itemname == name and chest.count > 0 and (not filter or filter(chest)) then
|
||||
count = count - chest.count
|
||||
ret[#ret + 1] = chest
|
||||
if count <= 0 then
|
||||
return ret
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function Shop:chest_poll(pos, inv)
|
||||
local chest = self:get_chest(pos)
|
||||
assert(chest)
|
||||
|
|
Loading…
Reference in New Issue