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