dd713750fce23e20aa5c81dc5d2e12a89d490e2b
[smartshop.git] / init.lua
1 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={
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}},
3 {{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}},
4 {{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}},
5 {{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}}}
6 }
7
8 minetest.register_craft({
9 output = "smartshop:shop",
10 recipe = {
11 {"default:chest_locked", "default:chest_locked", "default:chest_locked"},
12 {"default:sign_wall_wood", "default:chest_locked", "default:sign_wall_wood"},
13 {"default:sign_wall_wood", "default:torch", "default:sign_wall_wood"},
14 }
15 })
16
17 smartshop.use_offer=function(pos,player,n)
18 local pressed={}
19 pressed["buy" .. n]=true
20 smartshop.user[player:get_player_name()]=pos
21 smartshop.receive_fields(player,pressed)
22 smartshop.user[player:get_player_name()]=nil
23 smartshop.update(pos)
24
25
26 end
27
28 smartshop.get_offer=function(pos)
29 if not pos or not minetest.get_node(pos) then return end
30 if minetest.get_node(pos).name~="smartshop:shop" then return end
31 local meta=minetest.get_meta(pos)
32 local inv=meta:get_inventory()
33 local offer={}
34 for i=1,4,1 do
35 offer[i]={
36 give=inv:get_stack("give" .. i,1):get_name(),
37 give_count=inv:get_stack("give" .. i,1):get_count(),
38 pay=inv:get_stack("pay" .. i,1):get_name(),
39 pay_count=inv:get_stack("pay" .. i,1):get_count(),
40 }
41 end
42 return offer
43 end
44
45 smartshop.send_mail=function(owner, pos, item)
46 if not minetest.get_modpath( "mail" ) then
47 return
48 end
49 item = ItemStack(item)
50 local spos = "("..pos.x..", "..pos.y..", "..pos.z..")"
51 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")
52 end
53
54
55 smartshop.receive_fields=function(player,pressed)
56 if pressed.customer then
57 return smartshop.showform(smartshop.user[player:get_player_name()],player,true)
58 elseif pressed.sellall then
59 local pos=smartshop.user[player:get_player_name()]
60 local meta=minetest.get_meta(pos)
61 local pname=player:get_player_name()
62 if meta:get_int("sellall")==0 then
63 meta:set_int("sellall",1)
64 minetest.chat_send_player(pname, "Sell your stock and give line")
65 else
66 meta:set_int("sellall",0)
67 minetest.chat_send_player(pname, "Sell your stock only")
68 end
69 elseif pressed.tooglelime then
70 local pos=smartshop.user[player:get_player_name()]
71 local meta=minetest.get_meta(pos)
72 local pname=player:get_player_name()
73 if meta:get_int("type")==0 then
74 meta:set_int("type",1)
75 minetest.chat_send_player(pname, "Your stock is limited")
76 else
77 meta:set_int("type",0)
78 minetest.chat_send_player(pname, "Your stock is unlimited")
79 end
80 elseif not pressed.quit then
81 local n=1
82 for i=1,4,1 do
83 n=i
84 if pressed["buy" .. i] then break end
85 end
86 local pos=smartshop.user[player:get_player_name()]
87 local meta=minetest.get_meta(pos)
88 local type=meta:get_int("type")
89 local sellall=meta:get_int("sellall")
90 local inv=meta:get_inventory()
91 local pinv=player:get_inventory()
92 local pname=player:get_player_name()
93 if pressed["buy" .. n] then
94 local name=inv:get_stack("give" .. n,1):get_name()
95 local stack=name .." ".. inv:get_stack("give" .. n,1):get_count()
96 local pay=inv:get_stack("pay" .. n,1):get_name() .." ".. inv:get_stack("pay" .. n,1):get_count()
97 if name~="" then
98 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
99 -- if type==1 and sellall==1 and inv:contains_item("main", stack)==false and inv:contains_item("give" .. n, stack)==true then
100 -- inv:add_item("main", stack)
101 -- inv:remove_item("give" .. n, stack)
102 -- end
103 if meta:get_int("ghost") ~=1 then
104 -- transition shops to ghost inventory.
105 for i=1,4 do
106 if inv:room_for_item("main", "pay"..i) and inv:room_for_item("main", "give"..i) then
107 meta:set_int("ghost", 1)
108 inv:add_item("main", inv:get_stack("pay"..i,1))
109 inv:add_item("main", inv:get_stack("give"..i,1))
110 end
111 end
112 end
113 if type==1 and inv:contains_item("main", stack)==false then
114 minetest.chat_send_player(pname, "Error: The owners stock is end.")
115 if not meta:get_int("alerted") or meta:get_int("alerted") == 0 then
116 meta:set_int("alerted",1) -- Do not alert twice
117 smartshop.send_mail(meta:get_string("owner"), pos, stack)
118 end
119 return
120 end
121 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
122 if not pinv:room_for_item("main", stack) then minetest.chat_send_player(pname, "Error: Your inventory is full, exchange aborted.") return end
123 pinv:remove_item("main", pay)
124 pinv:add_item("main", stack)
125 if type==1 then
126 inv:remove_item("main", stack)
127 inv:add_item("main", pay)
128 if not inv:contains_item("main", stack) and (not meta:get_int("alerted") or meta:get_int("alerted") == 0) then
129 meta:set_int("alerted",1) -- Do not alert twice
130 smartshop.send_mail(meta:get_string("owner"), pos, stack)
131 end
132 end
133 end
134 end
135 else
136 local pos=smartshop.user[player:get_player_name()]
137 smartshop.update_info(pos)
138 if smartshop.user[player:get_player_name()] or minetest.check_player_privs(player:get_player_name(), {protection_bypass=true}) then
139 local meta=minetest.get_meta(smartshop.user[player:get_player_name()])
140 if meta:get_string("owner")==player:get_player_name() then
141 smartshop.update(smartshop.user[player:get_player_name()],"update")
142 end
143 end
144 smartshop.user[player:get_player_name()]=nil
145 end
146 end
147
148 minetest.register_on_player_receive_fields(function(player, form, pressed)
149 if form=="smartshop.showform" then
150 smartshop.receive_fields(player,pressed)
151 end
152 end)
153
154
155
156
157 smartshop.update_info=function(pos)
158 local meta=minetest.get_meta(pos)
159 local inv = meta:get_inventory()
160 local owner=meta:get_string("owner")
161 local gve=0
162 -- if meta:get_int("sellall")==1 then gve=1 end
163 if meta:get_int("type")==0 then
164 meta:set_string("infotext","(Smartshop by " .. owner ..") Stock is unlimited")
165 return false
166 end
167 local name=""
168 local count=0
169 local stuff={}
170 for i=1,4,1 do
171 stuff["count" ..i]=inv:get_stack("give" .. i,1):get_count()
172 stuff["name" ..i]=inv:get_stack("give" .. i,1):get_name()
173 stuff["stock" ..i]=gve*stuff["count" ..i]
174 stuff["buy" ..i]=0
175 for ii=1,32,1 do
176 name=inv:get_stack("main",ii):get_name()
177 count=inv:get_stack("main",ii):get_count()
178 if name==stuff["name" ..i] then
179 stuff["stock" ..i]=stuff["stock" ..i]+count
180 end
181 end
182 local nstr=(stuff["stock" ..i]/stuff["count" ..i]) ..""
183 nstr=nstr.split(nstr, ".")
184 stuff["buy" ..i]=tonumber(nstr[1])
185
186 if stuff["name" ..i]=="" or stuff["buy" ..i]==0 then
187 stuff["buy" ..i]=""
188 stuff["name" ..i]=""
189 else
190 --if string.find(stuff["name" ..i],":")~=nil then
191 -- stuff["name" ..i]=stuff["name" ..i].split(stuff["name" ..i],":")[2]
192 --end
193 if core.registered_items[stuff["name"..i]] then
194 stuff["name"..i] = core.registered_items[stuff["name"..i]].description
195 else
196 stuff["name"..i] = "Unknown Object"
197 end
198 stuff["buy" ..i]="(" ..stuff["buy" ..i] ..") "
199 stuff["name" ..i]=stuff["name" ..i] .."\n"
200 end
201 end
202 meta:set_string("infotext",
203 "(Smartshop by " .. owner ..") Purchases left:\n"
204 .. stuff.buy1 .. stuff.name1
205 .. stuff.buy2 .. stuff.name2
206 .. stuff.buy3 .. stuff.name3
207 .. stuff.buy4 .. stuff.name4
208 )
209 end
210
211
212
213
214 smartshop.update=function(pos,stat)
215 --clear
216 local spos=minetest.pos_to_string(pos)
217 for _, ob in ipairs(minetest.env:get_objects_inside_radius(pos, 2)) do
218 if ob and ob:get_luaentity() and ob:get_luaentity().smartshop and ob:get_luaentity().pos==spos then
219 ob:remove()
220 end
221 end
222 if stat=="clear" then return end
223 --update
224 local meta=minetest.get_meta(pos)
225 local inv = meta:get_inventory()
226 local node=minetest.get_node(pos)
227 local dp = smartshop.dir[node.param2+1]
228 if not dp then return end
229 pos.x = pos.x + dp.x*0.01
230 pos.y = pos.y + dp.y*6.5/16
231 pos.z = pos.z + dp.z*0.01
232 for i=1,4,1 do
233 local item=inv:get_stack("give" .. i,1):get_name()
234 local pos2=smartshop.dpos[node.param2+1][i]
235 if item~="" then
236 smartshop.tmp.item=item
237 smartshop.tmp.pos=spos
238 local e = minetest.env:add_entity({x=pos.x+pos2.x,y=pos.y+pos2.y,z=pos.z+pos2.z},"smartshop:item")
239 e:setyaw(math.pi*2 - node.param2 * math.pi/2)
240 end
241 end
242 end
243
244
245 minetest.register_entity("smartshop:item",{
246 hp_max = 1,
247 visual="wielditem",
248 visual_size={x=.20,y=.20},
249 collisionbox = {0,0,0,0,0,0},
250 physical=false,
251 textures={"air"},
252 smartshop=true,
253 type="",
254 on_activate = function(self, staticdata)
255 if smartshop.tmp.item ~= nil then
256 self.item=smartshop.tmp.item
257 self.pos=smartshop.tmp.pos
258 smartshop.tmp={}
259 else
260 if staticdata ~= nil and staticdata ~= "" then
261 local data = staticdata:split(';')
262 if data and data[1] and data[2] then
263 self.item = data[1]
264 self.pos = data[2]
265 end
266 end
267 end
268 if self.item ~= nil then
269 self.object:set_properties({textures={self.item}})
270 else
271 self.object:remove()
272 end
273 end,
274 get_staticdata = function(self)
275 if self.item ~= nil and self.pos ~= nil then
276 return self.item .. ';' .. self.pos
277 end
278 return ""
279 end,
280 })
281
282
283 smartshop.showform=function(pos,player,re)
284 local meta=minetest.get_meta(pos)
285 local creative=meta:get_int("creative")
286 local inv = meta:get_inventory()
287 local gui=""
288 local spos=pos.x .. "," .. pos.y .. "," .. pos.z
289 local owner=meta:get_string("owner")==player:get_player_name()
290 if minetest.check_player_privs(player:get_player_name(), {protection_bypass=true}) then owner=true end
291 if re then owner=false end
292 smartshop.user[player:get_player_name()]=pos
293 if owner then
294 meta:set_int("alerted",0) -- Player has been there to refill
295 gui=""
296 .."size[8,10]"
297 .."button_exit[6,0;1.5,1;customer;Customer]"
298 .."button[7.2,0;1,1;sellall;All]"
299 .."label[0,0.2;Item:]"
300 .."label[0,1.2;Price:]"
301 .."list[nodemeta:" .. spos .. ";give1;2,0;1,1;]"
302 .."list[nodemeta:" .. spos .. ";pay1;2,1;1,1;]"
303 .."list[nodemeta:" .. spos .. ";give2;3,0;1,1;]"
304 .."list[nodemeta:" .. spos .. ";pay2;3,1;1,1;]"
305 .."list[nodemeta:" .. spos .. ";give3;4,0;1,1;]"
306 .."list[nodemeta:" .. spos .. ";pay3;4,1;1,1;]"
307 .."list[nodemeta:" .. spos .. ";give4;5,0;1,1;]"
308 .."list[nodemeta:" .. spos .. ";pay4;5,1;1,1;]"
309 if creative==1 then
310 gui=gui .."label[0.5,-0.4;Your stock is unlimited becaouse you have creative or give]"
311 .."button[6,1;2.2,1;tooglelime;Toggle limit]"
312 end
313 gui=gui
314 .."list[nodemeta:" .. spos .. ";main;0,2;8,4;]"
315 .."list[current_player;main;0,6.2;8,4;]"
316 .."listring[nodemeta:" .. spos .. ";main]"
317 .."listring[current_player;main]"
318 else
319 gui=""
320 .."size[8,6]"
321 .."list[current_player;main;0,2.2;8,4;]"
322 .."label[0,0.2;Item:]"
323 .."label[0,1.2;Price:]"
324 .."list[nodemeta:" .. spos .. ";give1;2,0;1,1;]"
325 .."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() .."]"
326 .."list[nodemeta:" .. spos .. ";give2;3,0;1,1;]"
327 .."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() .."]"
328 .."list[nodemeta:" .. spos .. ";give3;4,0;1,1;]"
329 .."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() .."]"
330 .."list[nodemeta:" .. spos .. ";give4;5,0;1,1;]"
331 .."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() .."]"
332 end
333 minetest.after((0.1), function(gui)
334 return minetest.show_formspec(player:get_player_name(), "smartshop.showform",gui)
335 end, gui)
336 end
337
338 minetest.register_node("smartshop:shop", {
339 description = "Smartshop",
340 tiles = {"default_chest_top.png^[colorize:#ffffff77^default_obsidian_glass.png"},
341 groups = {choppy = 2, oddly_breakable_by_hand = 1,tubedevice = 1, tubedevice_receiver = 1},
342 drawtype="nodebox",
343 node_box = {type="fixed",fixed={-0.5,-0.5,-0.0,0.5,0.5,0.5}},
344 paramtype2="facedir",
345 paramtype = "light",
346 sunlight_propagates = true,
347 light_source = 10,
348 tube = {insert_object = function(pos, node, stack, direction)
349 local meta = minetest.get_meta(pos)
350 local inv = meta:get_inventory()
351 local added = inv:add_item("main", stack)
352 return added
353 end,
354 can_insert = function(pos, node, stack, direction)
355 local meta = minetest.get_meta(pos)
356 local inv = meta:get_inventory()
357 for i=1,4 do
358 local sellitem = inv:get_stack("give"..i,1):get_name()
359 if sellitem == stack:get_name() then
360 return inv:room_for_item("main", stack)
361 end
362 -- minetest.chat_send_all(sellitem)
363 end
364 --
365 return false
366 end,
367 input_inventory = "main",
368 connect_sides = {left = 1, right = 1, front = 1, back = 1, top = 1, bottom = 1}},
369 after_place_node = function(pos, placer)
370 local meta=minetest.get_meta(pos)
371 meta:set_string("owner",placer:get_player_name())
372 meta:set_string("infotext", "Shop by: " .. placer:get_player_name())
373 meta:set_int("type",1)
374 meta:set_int("sellall",1)
375 if minetest.check_player_privs(placer:get_player_name(), {creative=true}) or minetest.check_player_privs(placer:get_player_name(), {give=true}) then
376 meta:set_int("creative",1)
377 meta:set_int("type",0)
378 meta:set_int("sellall",0)
379 end
380 end,
381 on_construct = function(pos)
382 local meta=minetest.get_meta(pos)
383 meta:set_int("state", 0)
384 meta:get_inventory():set_size("main", 32)
385 meta:get_inventory():set_size("give1", 1)
386 meta:get_inventory():set_size("pay1", 1)
387 meta:get_inventory():set_size("give2", 1)
388 meta:get_inventory():set_size("pay2", 1)
389 meta:get_inventory():set_size("give3", 1)
390 meta:get_inventory():set_size("pay3", 1)
391 meta:get_inventory():set_size("give4", 1)
392 meta:get_inventory():set_size("pay4", 1)
393 meta:set_int("ghost", 1)
394 end,
395 on_rightclick = function(pos, node, player, itemstack, pointed_thing)
396 smartshop.showform(pos,player)
397 end,
398 allow_metadata_inventory_put = function(pos, listname, index, stack, player)
399 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
400 local meta = minetest.get_meta(pos)
401 if meta:get_int("ghost") and (string.find(listname, "pay") or string.find(listname, "give")) then
402 local inv = minetest.get_inventory({type="node", pos=pos})
403 inv:set_stack(listname, index, stack)
404 return 0
405 end
406 return stack:get_count()
407 end
408 return 0
409 end,
410 allow_metadata_inventory_take = function(pos, listname, index, stack, player)
411 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
412 local meta = minetest.get_meta(pos)
413 if meta:get_int("ghost") == 1 and (string.find(listname, "pay") or string.find(listname, "give")) then
414 local inv = minetest.get_inventory({type="node", pos=pos})
415 inv:set_stack(listname, index, ItemStack(""))
416 return 0
417 end
418 return stack:get_count()
419 end
420 return 0
421 end,
422 allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
423 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
424 local meta = minetest.get_meta(pos)
425 local inv = minetest.get_inventory({type="node", pos=pos})
426 if meta:get_int("ghost") ~= 1 then
427 return count
428 end
429 if (string.find(from_list, "pay") or string.find(from_list, "give")) and to_list == "main" then
430 inv:set_stack(from_list, from_index, ItemStack(""))
431 return 0
432 elseif (string.find(to_list, "pay") or string.find(to_list, "give")) and from_list == "main" then
433 inv:set_stack(to_list, to_index, inv:get_stack(from_list, from_index))
434 inv:set_stack(from_list, from_index, inv:get_stack(from_list, from_index))
435 return 0
436 else
437 return count
438 end
439 end
440 return 0
441 end,
442 can_dig = function(pos, player)
443 local meta=minetest.get_meta(pos)
444 local inv=meta:get_inventory()
445 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
446 smartshop.update(pos,"clear")
447 return true
448 end
449 end,
450 })