From b746dc91d374d079aec8507a8501c9fc7fdf486d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20P=C3=A9rez-Cerezo?= Date: Wed, 15 Nov 2017 14:27:17 +0100 Subject: Added mail sending when stock is empty, only accept items that get sold by the shop --- Readme.txt | 16 +++ depends.txt | 2 + init.lua | 405 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 423 insertions(+) create mode 100644 Readme.txt create mode 100644 depends.txt create mode 100644 init.lua diff --git a/Readme.txt b/Readme.txt new file mode 100644 index 0000000..2ecdbfe --- /dev/null +++ b/Readme.txt @@ -0,0 +1,16 @@ +Licenses: code and media CC0 +Version: 4r +Name: smartshop +Created by: UjEdwin + + +Like the title says, this is a smart and easy shop, that will also fit everywhere. + +it is a mix of a vending machine, a shop, item frames and light. + +You can toogle it unlimited or limited if you have give or creative +(unlimited will not take or add stuff to its inventory) + +The "All" button will lime your stock to the inventory or and the giveline, its on as default. + +It also works with pipeworks and aliveai \ No newline at end of file diff --git a/depends.txt b/depends.txt new file mode 100644 index 0000000..d589024 --- /dev/null +++ b/depends.txt @@ -0,0 +1,2 @@ +default +mail? diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..0969ead --- /dev/null +++ b/init.lua @@ -0,0 +1,405 @@ +smartshop={user={},tmp={},dir={{x=0,y=0,z=-1},{x=-1,y=0,z=0},{x=0,y=0,z=1},{x=1,y=0,z=0}},dpos={ +{{x=0.2,y=0.2,z=0},{x=-0.2,y=0.2,z=0},{x=0.2,y=-0.2,z=0},{x=-0.2,y=-0.2,z=0}}, +{{x=0,y=0.2,z=0.2},{x=0,y=0.2,z=-0.2},{x=0,y=-0.2,z=0.2},{x=0,y=-0.2,z=-0.2}}, +{{x=-0.2,y=0.2,z=0},{x=0.2,y=0.2,z=0},{x=-0.2,y=-0.2,z=0},{x=0.2,y=-0.2,z=0}}, +{{x=0,y=0.2,z=-0.2},{x=0,y=0.2,z=0.2},{x=0,y=-0.2,z=-0.2},{x=0,y=-0.2,z=0.2}}} +} + +minetest.register_craft({ + output = "smartshop:shop", + recipe = { + {"default:chest_locked", "default:chest_locked", "default:chest_locked"}, + {"default:sign_wall_wood", "default:chest_locked", "default:sign_wall_wood"}, + {"default:sign_wall_wood", "default:torch", "default:sign_wall_wood"}, + } +}) + +smartshop.use_offer=function(pos,player,n) + local pressed={} + pressed["buy" .. n]=true + smartshop.user[player:get_player_name()]=pos + smartshop.receive_fields(player,pressed) + smartshop.user[player:get_player_name()]=nil + smartshop.update(pos) + + +end + +smartshop.get_offer=function(pos) + if not pos or not minetest.get_node(pos) then return end + if minetest.get_node(pos).name~="smartshop:shop" then return end + local meta=minetest.get_meta(pos) + local inv=meta:get_inventory() + local offer={} + for i=1,4,1 do + offer[i]={ + give=inv:get_stack("give" .. i,1):get_name(), + give_count=inv:get_stack("give" .. i,1):get_count(), + pay=inv:get_stack("pay" .. i,1):get_name(), + pay_count=inv:get_stack("pay" .. i,1):get_count(), + } + end + return offer +end + +smartshop.send_mail=function(owner, pos, item) + if not minetest.get_modpath( "mail" ) then + return + end + item = ItemStack(item) + local spos = "("..pos.x..", "..pos.y..", "..pos.z..")" + mail.send("DO NOT REPLY", owner, "Out of stock at "..spos, "Your smartshop at "..spos.." is out of "..core.registered_items[item:get_name()].description..". Please restock") +end + + +smartshop.receive_fields=function(player,pressed) + if pressed.customer then + return smartshop.showform(smartshop.user[player:get_player_name()],player,true) + elseif pressed.sellall then + local pos=smartshop.user[player:get_player_name()] + local meta=minetest.get_meta(pos) + local pname=player:get_player_name() + if meta:get_int("sellall")==0 then + meta:set_int("sellall",1) + minetest.chat_send_player(pname, "Sell your stock and give line") + else + meta:set_int("sellall",0) + minetest.chat_send_player(pname, "Sell your stock only") + end + elseif pressed.tooglelime then + local pos=smartshop.user[player:get_player_name()] + local meta=minetest.get_meta(pos) + local pname=player:get_player_name() + if meta:get_int("type")==0 then + meta:set_int("type",1) + minetest.chat_send_player(pname, "Your stock is limited") + else + meta:set_int("type",0) + minetest.chat_send_player(pname, "Your stock is unlimited") + end + elseif not pressed.quit then + local n=1 + for i=1,4,1 do + n=i + if pressed["buy" .. i] then break end + end + local pos=smartshop.user[player:get_player_name()] + local meta=minetest.get_meta(pos) + local type=meta:get_int("type") + local sellall=meta:get_int("sellall") + local inv=meta:get_inventory() + local pinv=player:get_inventory() + local pname=player:get_player_name() + if pressed["buy" .. n] then + local name=inv:get_stack("give" .. n,1):get_name() + local stack=name .." ".. inv:get_stack("give" .. n,1):get_count() + local pay=inv:get_stack("pay" .. n,1):get_name() .." ".. inv:get_stack("pay" .. n,1):get_count() + if name~="" then + if type==1 and inv:room_for_item("main", pay)==false then minetest.chat_send_player(pname, "Error: The owners stock is full, cant receive, exchange aborted.") return end + if type==1 and sellall==1 and inv:contains_item("main", stack)==false and inv:contains_item("give" .. n, stack)==true then + inv:add_item("main", stack) + inv:remove_item("give" .. n, stack) + end + if type==1 and inv:contains_item("main", stack)==false then + minetest.chat_send_player(pname, "Error: The owners stock is end.") + if not meta:get_int("alerted") or meta:get_int("alerted") == 0 then + meta:set_int("alerted",1) -- Do not alert twice + smartshop.send_mail(meta:get_string("owner"), pos, stack) + end + return + end + if not pinv:contains_item("main", pay) then minetest.chat_send_player(pname, "Error: You dont have enough in your inventory to buy this, exchange aborted.") return end + if not pinv:room_for_item("main", stack) then minetest.chat_send_player(pname, "Error: Your inventory is full, exchange aborted.") return end + pinv:remove_item("main", pay) + pinv:add_item("main", stack) + if type==1 then + inv:remove_item("main", stack) + inv:add_item("main", pay) + end + end + end + else + local pos=smartshop.user[player:get_player_name()] + smartshop.update_info(pos) + if smartshop.user[player:get_player_name()] or minetest.check_player_privs(player:get_player_name(), {protection_bypass=true}) then + local meta=minetest.get_meta(smartshop.user[player:get_player_name()]) + if meta:get_string("owner")==player:get_player_name() then + smartshop.update(smartshop.user[player:get_player_name()],"update") + end + end + smartshop.user[player:get_player_name()]=nil + end +end + +minetest.register_on_player_receive_fields(function(player, form, pressed) + if form=="smartshop.showform" then + smartshop.receive_fields(player,pressed) + end +end) + + + + +smartshop.update_info=function(pos) + local meta=minetest.get_meta(pos) + local inv = meta:get_inventory() + local owner=meta:get_string("owner") + local gve=0 + if meta:get_int("sellall")==1 then gve=1 end + if meta:get_int("type")==0 then + meta:set_string("infotext","(Smartshop by " .. owner ..") Stock is unlimited") + return false + end + local name="" + local count=0 + local stuff={} + for i=1,4,1 do + stuff["count" ..i]=inv:get_stack("give" .. i,1):get_count() + stuff["name" ..i]=inv:get_stack("give" .. i,1):get_name() + stuff["stock" ..i]=gve*stuff["count" ..i] + stuff["buy" ..i]=0 + for ii=1,32,1 do + name=inv:get_stack("main",ii):get_name() + count=inv:get_stack("main",ii):get_count() + if name==stuff["name" ..i] then + stuff["stock" ..i]=stuff["stock" ..i]+count + end + end + local nstr=(stuff["stock" ..i]/stuff["count" ..i]) .."" + nstr=nstr.split(nstr, ".") + stuff["buy" ..i]=tonumber(nstr[1]) + + if stuff["name" ..i]=="" or stuff["buy" ..i]==0 then + stuff["buy" ..i]="" + stuff["name" ..i]="" + else + --if string.find(stuff["name" ..i],":")~=nil then + -- stuff["name" ..i]=stuff["name" ..i].split(stuff["name" ..i],":")[2] + --end + stuff["name"..i] = core.registered_items[stuff["name"..i]].description + stuff["buy" ..i]="(" ..stuff["buy" ..i] ..") " + stuff["name" ..i]=stuff["name" ..i] .."\n" + end + end + meta:set_string("infotext", + "(Smartshop by " .. owner ..") Purchases left:\n" + .. stuff.buy1 .. stuff.name1 + .. stuff.buy2 .. stuff.name2 + .. stuff.buy3 .. stuff.name3 + .. stuff.buy4 .. stuff.name4 + ) +end + + + + +smartshop.update=function(pos,stat) +--clear + local spos=minetest.pos_to_string(pos) + for _, ob in ipairs(minetest.env:get_objects_inside_radius(pos, 2)) do + if ob and ob:get_luaentity() and ob:get_luaentity().smartshop and ob:get_luaentity().pos==spos then + ob:remove() + end + end + if stat=="clear" then return end +--update + local meta=minetest.get_meta(pos) + local inv = meta:get_inventory() + local node=minetest.get_node(pos) + local dp = smartshop.dir[node.param2+1] + if not dp then return end + pos.x = pos.x + dp.x*0.01 + pos.y = pos.y + dp.y*6.5/16 + pos.z = pos.z + dp.z*0.01 + for i=1,4,1 do + local item=inv:get_stack("give" .. i,1):get_name() + local pos2=smartshop.dpos[node.param2+1][i] + if item~="" then + smartshop.tmp.item=item + smartshop.tmp.pos=spos + local e = minetest.env:add_entity({x=pos.x+pos2.x,y=pos.y+pos2.y,z=pos.z+pos2.z},"smartshop:item") + e:setyaw(math.pi*2 - node.param2 * math.pi/2) + end + end +end + + +minetest.register_entity("smartshop:item",{ + hp_max = 1, + visual="wielditem", + visual_size={x=.20,y=.20}, + collisionbox = {0,0,0,0,0,0}, + physical=false, + textures={"air"}, + smartshop=true, + type="", + on_activate = function(self, staticdata) + if smartshop.tmp.item ~= nil then + self.item=smartshop.tmp.item + self.pos=smartshop.tmp.pos + smartshop.tmp={} + else + if staticdata ~= nil and staticdata ~= "" then + local data = staticdata:split(';') + if data and data[1] and data[2] then + self.item = data[1] + self.pos = data[2] + end + end + end + if self.item ~= nil then + self.object:set_properties({textures={self.item}}) + else + self.object:remove() + end + end, + get_staticdata = function(self) + if self.item ~= nil and self.pos ~= nil then + return self.item .. ';' .. self.pos + end + return "" + end, +}) + + +smartshop.showform=function(pos,player,re) + local meta=minetest.get_meta(pos) + local creative=meta:get_int("creative") + local inv = meta:get_inventory() + local gui="" + local spos=pos.x .. "," .. pos.y .. "," .. pos.z + local owner=meta:get_string("owner")==player:get_player_name() + if minetest.check_player_privs(player:get_player_name(), {protection_bypass=true}) then owner=true end + if re then owner=false end + smartshop.user[player:get_player_name()]=pos + if owner then + meta:set_int("alerted",0) -- Player has been there to refill + gui="" + .."size[8,10]" + .."button_exit[6,0;1.5,1;customer;Customer]" + .."button[7.2,0;1,1;sellall;All]" + .."label[0,0.2;Item:]" + .."label[0,1.2;Price:]" + .."list[nodemeta:" .. spos .. ";give1;2,0;1,1;]" + .."list[nodemeta:" .. spos .. ";pay1;2,1;1,1;]" + .."list[nodemeta:" .. spos .. ";give2;3,0;1,1;]" + .."list[nodemeta:" .. spos .. ";pay2;3,1;1,1;]" + .."list[nodemeta:" .. spos .. ";give3;4,0;1,1;]" + .."list[nodemeta:" .. spos .. ";pay3;4,1;1,1;]" + .."list[nodemeta:" .. spos .. ";give4;5,0;1,1;]" + .."list[nodemeta:" .. spos .. ";pay4;5,1;1,1;]" + if creative==1 then + gui=gui .."label[0.5,-0.4;Your stock is unlimited becaouse you have creative or give]" + .."button[6,1;2.2,1;tooglelime;Toggle limit]" + end + gui=gui + .."list[nodemeta:" .. spos .. ";main;0,2;8,4;]" + .."list[current_player;main;0,6.2;8,4;]" + .."listring[nodemeta:" .. spos .. ";main]" + .."listring[current_player;main]" + else + gui="" + .."size[8,6]" + .."list[current_player;main;0,2.2;8,4;]" + .."label[0,0.2;Item:]" + .."label[0,1.2;Price:]" + .."list[nodemeta:" .. spos .. ";give1;2,0;1,1;]" + .."item_image_button[2,1;1,1;".. inv:get_stack("pay1",1):get_name() ..";buy1;\n\n\b\b\b\b\b" .. inv:get_stack("pay1",1):get_count() .."]" + .."list[nodemeta:" .. spos .. ";give2;3,0;1,1;]" + .."item_image_button[3,1;1,1;".. inv:get_stack("pay2",1):get_name() ..";buy2;\n\n\b\b\b\b\b" .. inv:get_stack("pay2",1):get_count() .."]" + .."list[nodemeta:" .. spos .. ";give3;4,0;1,1;]" + .."item_image_button[4,1;1,1;".. inv:get_stack("pay3",1):get_name() ..";buy3;\n\n\b\b\b\b\b" .. inv:get_stack("pay3",1):get_count() .."]" + .."list[nodemeta:" .. spos .. ";give4;5,0;1,1;]" + .."item_image_button[5,1;1,1;".. inv:get_stack("pay4",1):get_name() ..";buy4;\n\n\b\b\b\b\b" .. inv:get_stack("pay4",1):get_count() .."]" + end + minetest.after((0.1), function(gui) + return minetest.show_formspec(player:get_player_name(), "smartshop.showform",gui) + end, gui) +end + +minetest.register_node("smartshop:shop", { + description = "Smartshop", + tiles = {"default_chest_top.png^[colorize:#ffffff77^default_obsidian_glass.png"}, + groups = {choppy = 2, oddly_breakable_by_hand = 1,tubedevice = 1, tubedevice_receiver = 1}, + drawtype="nodebox", + node_box = {type="fixed",fixed={-0.5,-0.5,-0.0,0.5,0.5,0.5}}, + paramtype2="facedir", + paramtype = "light", + sunlight_propagates = true, + light_source = 10, + tube = {insert_object = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local added = inv:add_item("main", stack) + return added + end, + can_insert = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + for i=1,4 do + local sellitem = inv:get_stack("give"..i,1):get_name() + if sellitem == stack:get_name() then + return inv:room_for_item("main", stack) + end +-- minetest.chat_send_all(sellitem) + end + -- + return false + end, + input_inventory = "main", + connect_sides = {left = 1, right = 1, front = 1, back = 1, top = 1, bottom = 1}}, +after_place_node = function(pos, placer) + local meta=minetest.get_meta(pos) + meta:set_string("owner",placer:get_player_name()) + meta:set_string("infotext", "Shop by: " .. placer:get_player_name()) + meta:set_int("type",1) + meta:set_int("sellall",1) + if minetest.check_player_privs(placer:get_player_name(), {creative=true}) or minetest.check_player_privs(placer:get_player_name(), {give=true}) then + meta:set_int("creative",1) + meta:set_int("type",0) + meta:set_int("sellall",0) + end + end, +on_construct = function(pos) + local meta=minetest.get_meta(pos) + meta:set_int("state", 0) + meta:get_inventory():set_size("main", 32) + meta:get_inventory():set_size("give1", 1) + meta:get_inventory():set_size("pay1", 1) + meta:get_inventory():set_size("give2", 1) + meta:get_inventory():set_size("pay2", 1) + meta:get_inventory():set_size("give3", 1) + meta:get_inventory():set_size("pay3", 1) + meta:get_inventory():set_size("give4", 1) + meta:get_inventory():set_size("pay4", 1) + end, +on_rightclick = function(pos, node, player, itemstack, pointed_thing) + smartshop.showform(pos,player) + end, +allow_metadata_inventory_put = function(pos, listname, index, stack, player) + if minetest.get_meta(pos):get_string("owner")==player:get_player_name() or minetest.check_player_privs(player:get_player_name(), {protection_bypass=true}) then + return stack:get_count() + end + return 0 + end, +allow_metadata_inventory_take = function(pos, listname, index, stack, player) + if minetest.get_meta(pos):get_string("owner")==player:get_player_name() or minetest.check_player_privs(player:get_player_name(), {protection_bypass=true}) then + return stack:get_count() + end + return 0 + end, +allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + if minetest.get_meta(pos):get_string("owner")==player:get_player_name() or minetest.check_player_privs(player:get_player_name(), {protection_bypass=true}) then + return count + end + return 0 + end, +can_dig = function(pos, player) + local meta=minetest.get_meta(pos) + local inv=meta:get_inventory() + if ((meta:get_string("owner")==player:get_player_name() or minetest.check_player_privs(player:get_player_name(), {protection_bypass=true})) and inv:is_empty("main") and inv:is_empty("pay1") and inv:is_empty("pay2") and inv:is_empty("pay3") and inv:is_empty("pay4") and inv:is_empty("give1") and inv:is_empty("give2") and inv:is_empty("give3") and inv:is_empty("give4")) or meta:get_string("owner")=="" then + smartshop.update(pos,"clear") + return true + end + end, +}) -- cgit v1.2.3