]> git.lizzy.rs Git - Crafter.git/blob - mods/itemhandling/init.lua
Add in api elements to the train mod
[Crafter.git] / mods / itemhandling / init.lua
1 local minetest,math,vector,pairs,ItemStack,ipairs = minetest,math,vector,pairs,ItemStack,ipairs
2
3 local path = minetest.get_modpath("itemhandling")
4 dofile(path.."/magnet.lua")
5
6
7 local creative_mode = minetest.settings:get_bool("creative_mode")
8
9 --handle node drops
10 --survival
11 local meta
12 local careful
13 local fortune
14 local autorepair
15 local count
16 local name
17 local object
18 if not creative_mode then
19         function minetest.handle_node_drops(pos, drops, digger)
20                 meta = digger:get_wielded_item():get_meta()
21                 --careful = meta:get_int("careful")
22                 fortune = 1--meta:get_int("fortune") + 1
23                 autorepair = meta:get_int("autorepair")
24                 --if careful > 0 then
25                 --      drops = {minetest.get_node(pos).name}
26                 --end
27                 for i = 1,fortune do
28                         for _,item in ipairs(drops) do
29
30                                 if type(item) == "string" then
31                                         count = 1
32                                         name = item
33                                 else
34                                         count = item:get_count()
35                                         name = item:get_name()
36                                 end
37                                 for i=1,count do
38                                         object = minetest.add_item(pos, name)
39                                         if object ~= nil then
40                                                 object:set_velocity({
41                                                         x=math.random(-2,2)*math.random(), 
42                                                         y=math.random(2,5), 
43                                                         z=math.random(-2,2)*math.random()
44                                                 })
45                                         end
46                                 end
47                         end
48                 local experience_amount = minetest.get_item_group(minetest.get_node(pos).name,"experience")
49                 if experience_amount > 0 then
50                     minetest.throw_experience(pos, experience_amount)
51                 end
52                 end
53                 --auto repair the item
54                 if autorepair > 0 and math.random(0,1000) < autorepair then
55                         local itemstack = digger:get_wielded_item()
56                         itemstack:add_wear(autorepair*-100)
57                         digger:set_wielded_item(itemstack)
58                 end
59         end
60 --creative
61 else
62         function minetest.handle_node_drops(pos, drops, digger)
63         end
64         minetest.register_on_dignode(function(pos, oldnode, digger)
65                 
66                 --if digger and digger:is_player() then
67                 --      local inv = digger:get_inventory()
68                 --      if inv and not inv:contains_item("main", oldnode) and inv:room_for_item("main", oldnode) then
69                 --              inv:add_item("main", oldnode)
70                 --      end
71                 --end
72         end)
73         minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
74                 return(itemstack:get_name())
75         end)
76 end
77
78 local stack
79 local object
80 function minetest.throw_item(pos, item)
81         -- Take item in any format
82         stack = item
83         object = minetest.add_entity(pos, "__builtin:item")     
84         if object then
85                 object:get_luaentity():set_item(stack)
86                 object:set_velocity({
87                         x=math.random(-2,2)*math.random(), 
88                         y=math.random(2,5), 
89                         z=math.random(-2,2)*math.random()
90                 })
91         end
92         return object
93 end
94
95 local object
96 function minetest.throw_experience(pos, amount)
97     for i = 1,amount do
98         object = minetest.add_entity(pos, "experience:orb")
99         if object then
100             object:set_velocity({
101                                 x=math.random(-2,2)*math.random(), 
102                                 y=math.random(2,5), 
103                                 z=math.random(-2,2)*math.random()
104                         })
105         end
106     end
107         --return obj
108 end
109
110 --override drops
111 local dropper_is_player
112 local c_pos
113 local count
114 local sneak
115 local item
116 local object
117 local dir
118 function minetest.item_drop(itemstack, dropper, pos)
119         dropper_is_player = dropper and dropper:is_player()
120         c_pos = table.copy(pos)
121         if dropper_is_player then
122                 sneak = dropper:get_player_control().sneak
123                 c_pos.y = c_pos.y + 1.2
124                 if not sneak then
125                         count = itemstack:get_count()
126                 else
127                         count = 1
128                 end
129         else
130                 count = itemstack:get_count()
131         end
132
133         item = itemstack:take_item(count)
134         object = minetest.add_item(c_pos, item)
135         if object then
136                 if dropper_is_player then
137                         dir = dropper:get_look_dir()
138                         dir.x = dir.x * 2.9
139                         dir.y = dir.y * 2.9 + 2
140                         dir.z = dir.z * 2.9
141                         dir = vector.add(dir,dropper:get_player_velocity())
142                         object:set_velocity(dir)
143                         object:get_luaentity().dropped_by = dropper:get_player_name()
144                         object:get_luaentity().collection_timer = 0
145                 end
146                 return itemstack
147         end
148 end
149
150
151 local stack
152 local itemname
153 local def
154 local set_item = function(self, item)
155         stack = ItemStack(item or self.itemstring)
156         self.itemstring = stack:to_string()
157         if self.itemstring == "" then
158                 -- item not yet known
159                 return
160         end
161
162         itemname = stack:is_known() and stack:get_name() or "unknown"
163
164         def = minetest.registered_nodes[itemname]
165
166         self.object:set_properties({
167                 textures = {itemname},
168                 wield_item = self.itemstring,
169                 glow = def and def.light_source,
170         })
171 end
172
173
174 local get_staticdata = function(self)
175         return minetest.serialize({
176                 itemstring = self.itemstring,
177                 age = self.age,
178                 dropped_by = self.dropped_by,
179                 collection_timer = self.collection_timer,
180                 collectable = self.collectable,
181                 try_timer = self.try_timer,
182                 collected = self.collected,
183                 delete_timer = self.delete_timer,
184                 collector = self.collector,
185                 magnet_timer = self.magnet_timer,
186         })
187 end
188
189 local data
190 local on_activate = function(self, staticdata, dtime_s)
191         if string.sub(staticdata, 1, string.len("return")) == "return" then
192                 data = minetest.deserialize(staticdata)
193                 if data and type(data) == "table" then
194                         self.itemstring = data.itemstring
195                         self.age = (data.age or 0) + dtime_s
196                         self.dropped_by = data.dropped_by
197                         self.magnet_timer = data.magnet_timer
198                         self.collection_timer = data.collection_timer
199                         self.collectable = data.collectable
200                         self.try_timer = data.try_timer
201                         self.collected = data.collected
202                         self.delete_timer = data.delete_timer
203                         self.collector = data.collector
204                 end
205         else
206                 self.itemstring = staticdata
207         end
208         self.object:set_armor_groups({immortal = 1})
209         self.object:set_velocity({x = 0, y = 2, z = 0})
210         self.object:set_acceleration({x = 0, y = -9.81, z = 0})
211         set_item(self,self.itemstring)
212 end
213
214 local enable_physics = function(self)
215         if not self.physical_state then
216                 self.physical_state = true
217                 self.object:set_properties({physical = true})
218                 self.object:set_velocity({x=0, y=0, z=0})
219                 self.object:set_acceleration({x=0, y=-9.81, z=0})
220         end
221 end
222
223 local disable_physics = function(self)
224         if self.physical_state then
225                 self.physical_state = false
226                 self.object:set_properties({physical = false})
227                 self.object:set_velocity({x=0, y=0, z=0})
228                 self.object:set_acceleration({x=0, y=0, z=0})
229         end
230 end
231
232 local burn_nodes = {
233         ["fire:fire"]       = true,
234         ["nether:lava"]     = true,
235         ["nether:lavaflow"] = true,
236         ["main:lava"]       = true,
237         ["main:lavaflow"]   = true
238 }
239 local order = {
240         {x=1, y=0, z=0}, {x=-1, y=0, z= 0},
241         {x=0, y=0, z=1}, {x= 0, y=0, z=-1},
242 }
243 local collector
244 local pos
245 local pos2
246 local player_velocity
247 local direction
248 local distance
249 local multiplier
250 local velocity
251 local node
252 local is_stuck
253 local snode
254 local shootdir
255 local cnode
256 local cdef
257 local fpos
258 local vel
259 local def
260 local slip_factor
261 local change
262 local slippery
263 local i_node
264 local flow_dir
265 local item_step = function(self, dtime, moveresult)
266         pos = self.object:get_pos()
267         if not pos then
268                 return
269         end
270
271         --if item set to be collected then only execute go to player
272         if self.collected == true then
273                 if not self.collector then
274                         self.object:remove()
275                         return
276                 end
277
278                 collector = minetest.get_player_by_name(self.collector)
279                 if collector then
280                         self.magnet_timer = self.magnet_timer + dtime   
281
282                         disable_physics(self)
283
284                         --get the variables
285                         pos2 = collector:get_pos()
286                         player_velocity = collector:get_player_velocity()
287                         pos2.y = pos2.y + 0.5
288                                                         
289                         distance = vector.distance(pos2,pos)
290
291                         if distance > 2 or distance < 0.3 or self.magnet_timer > 0.2 or self.old_magnet_distance and self.old_magnet_distance < distance then
292                                 self.object:remove()
293                                 return
294                         end
295
296                         direction = vector.normalize(vector.subtract(pos2,pos))
297
298                         multiplier = 10 - distance -- changed
299
300                         velocity = vector.add(player_velocity,vector.multiply(direction,multiplier))
301                                                 
302                         self.object:set_velocity(velocity)
303                         
304                         self.old_magnet_distance = distance
305
306                         return
307                 else
308                         -- the collector doesn't exist
309                         self.object:remove()
310                         return
311                 end
312         end
313         
314         --allow entity to be collected after timer
315         if self.collectable == false and self.collection_timer >= 2.5 then
316                 self.collectable = true
317         elseif self.collectable == false then
318                 self.collection_timer = self.collection_timer + dtime
319         end
320                         
321         self.age = self.age + dtime
322         if self.age > 300 then
323                 self.object:remove()
324                 return
325         end
326         -- polling eases the server load
327         if self.poll_timer > 0 then
328                 self.poll_timer = self.poll_timer - dtime
329                 if self.poll_timer <= 0 then
330                         self.poll_timer = 0
331                 end
332                 return
333         end
334
335         if moveresult and moveresult.touching_ground and table.getn(moveresult.collisions) > 0 then
336                 node = minetest.get_node_or_nil(moveresult.collisions[1].node_pos)
337         else
338                 node = nil
339         end
340         
341
342         i_node = minetest.get_node_or_nil(pos)
343
344         -- Remove nodes in 'ignore' and burns items
345         if i_node then
346                 if i_node.name == "ignore" then
347                         self.object:remove()
348                         return
349                 elseif i_node and burn_nodes[i_node.name] then
350                         minetest.add_particlespawner({
351                                 amount = 6,
352                                 time = 0.001,
353                                 minpos = pos,
354                                 maxpos = pos,
355                                 minvel = vector.new(-1,0.5,-1),
356                                 maxvel = vector.new(1,1,1),
357                                 minacc = {x=0, y=1, z=0},
358                                 maxacc = {x=0, y=2, z=0},
359                                 minexptime = 1.1,
360                                 maxexptime = 1.5,
361                                 minsize = 1,
362                                 maxsize = 2,
363                                 collisiondetection = false,
364                                 vertical = false,
365                                 texture = "smoke.png",
366                         })
367                         minetest.sound_play("fire_extinguish", {pos=pos,gain=0.3,pitch=math.random(80,100)/100})
368                         self.object:remove()
369                         return
370                 end
371         end
372
373
374         is_stuck = false
375         snode = minetest.get_node_or_nil(pos)
376         if snode and snode ~= "air" then
377                 snode = minetest.registered_nodes[snode.name] or {}
378                 is_stuck = (snode.walkable == nil or snode.walkable == true)
379                         and (snode.collision_box == nil or snode.collision_box.type == "regular")
380                         and (snode.node_box == nil or snode.node_box.type == "regular")
381         end
382
383         -- Push item out when stuck inside solid node
384         if is_stuck then
385                 shootdir = nil
386                 -- Check which one of the 4 sides is free
387                 for o = 1, #order do
388                         cnode = minetest.get_node(vector.add(pos, order[o])).name
389                         cdef = minetest.registered_nodes[cnode] or {}
390                         if cnode ~= "ignore" and cdef.walkable == false then
391                                 shootdir = order[o]
392                                 break
393                         end
394                 end
395
396                 -- If none of the 4 sides is free, check upwards
397                 if not shootdir then
398                         shootdir = {x=0, y=1, z=0}
399                         cnode = minetest.get_node(vector.add(pos, shootdir)).name
400                         if cnode == "ignore" then
401                                 shootdir = nil -- Do not push into ignore
402                         end
403                 end
404
405                 if shootdir then
406                         -- shove that thing outta there
407                         fpos = vector.round(pos)
408                         if shootdir.x ~= 0 then
409                                 shootdir = vector.multiply(shootdir,0.74)
410                                 self.object:move_to(vector.new(fpos.x+shootdir.x,pos.y,pos.z))
411                         elseif shootdir.y ~= 0 then
412                                 shootdir = vector.multiply(shootdir,0.72)
413                                 self.object:move_to(vector.new(pos.x,fpos.y+shootdir.y,pos.z))
414                         elseif shootdir.z ~= 0 then
415                                 shootdir = vector.multiply(shootdir,0.74)
416                                 self.object:move_to(vector.new(pos.x,pos.y,fpos.z+shootdir.z))
417                         end
418                         return
419                 end
420         end
421
422
423         flow_dir = flow(pos)
424         
425         if flow_dir then
426                 flow_dir = vector.multiply(flow_dir,10)
427                 local vel = self.object:get_velocity()
428                 local acceleration = vector.new(flow_dir.x-vel.x,flow_dir.y-vel.y,flow_dir.z-vel.z)
429                 acceleration = vector.multiply(acceleration, 0.01)
430                 self.object:add_velocity(acceleration)
431                 return
432         end
433
434         change = false
435         -- Slide on slippery nodes
436         def = node and minetest.registered_nodes[node.name]
437         vel = self.object:get_velocity()
438         if def and def.walkable then
439                 slippery = minetest.get_item_group(node.name, "slippery")
440                 if slippery ~= 0 then
441                         if math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2 then
442                                 -- Horizontal deceleration
443                                 slip_factor = 4.0 / (slippery + 4)
444                                 self.object:set_acceleration({
445                                         x = -vel.x * slip_factor,
446                                         y = -9.81,
447                                         z = -vel.z * slip_factor
448                                 })
449                                 change = true
450                         elseif (vel.x ~= 0 or vel.z ~= 0) and math.abs(vel.x) <= 0.2 and math.abs(vel.z) <= 0.2 then
451                                 self.object:set_velocity(vector.new(0,vel.y,0))
452                                 self.object:set_acceleration(vector.new(0,-9.81,0))
453                         end
454                 elseif node then
455                         if math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2 then
456                                 self.object:add_velocity({
457                                         x = -vel.x * 0.15,
458                                         y = 0,
459                                         z = -vel.z * 0.15
460                                 })
461                                 change = true
462                         elseif (vel.x ~= 0 or vel.z ~= 0) and math.abs(vel.x) <= 0.2 and math.abs(vel.z) <= 0.2 then
463                                 self.object:set_velocity(vector.new(0,vel.y,0))
464                                 self.object:set_acceleration(vector.new(0,-9.81,0))
465                         end
466                 end
467         elseif vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0 then
468                 change = true
469         end
470
471         if change == false and self.poll_timer == 0 then
472                 self.poll_timer = 0.5
473         end
474 end
475
476
477 minetest.register_entity(":__builtin:item", {
478         initial_properties = {
479                 hp_max           = 1,
480                 visual           = "wielditem",
481                 physical         = true,
482                 textures         = {""},
483                 automatic_rotate = 1.5,
484                 is_visible       = true,
485                 pointable        = false,
486
487                 collide_with_objects = false,
488                 collisionbox = {-0.21, -0.21, -0.21, 0.21, 0.21, 0.21},
489                 selectionbox = {-0.21, -0.21, -0.21, 0.21, 0.21, 0.21},
490                 visual_size  = {x = 0.21, y = 0.21},
491         },
492         itemstring = "",
493         moving_state = true,
494         slippery_state = false,
495         physical_state = true,
496         -- Item expiry
497         age = 0,
498         -- Pushing item out of solid nodes
499         force_out       = nil,
500         force_out_start = nil,
501         -- Collection Variables
502         collection_timer = 2,
503         collectable      = false,
504         try_timer        = 0,
505         collected        = false,
506         delete_timer     = 0,
507         -- Used for server delay
508         magnet_timer = 0,
509         poll_timer = 0,
510
511         set_item = set_item,
512
513         get_staticdata = function(self)
514                 return(get_staticdata(self))
515         end,
516         on_activate    = function(self, staticdata, dtime_s)
517                 on_activate(self, staticdata, dtime_s)
518         end,
519
520         on_step = function(self, dtime, moveresult)
521                 item_step(self, dtime, moveresult)
522         end,
523 })
524
525
526 minetest.register_chatcommand("gimme", {
527         params = "nil",
528         description = "Spawn x amount of a mob, used as /spawn 'mob' 10 or /spawn 'mob' for one",
529         privs = {server=true},
530         func = function(name)
531                 local player = minetest.get_player_by_name(name)
532                 local pos = player:get_pos()
533                 pos.y = pos.y + 5
534                 pos.x = pos.x + 8
535                 for i = 1,1000 do
536                         minetest.throw_item(pos, "main:dirt")
537                 end
538         end,
539 })