]> git.lizzy.rs Git - Crafter.git/blobdiff - mods/itemhandling/init.lua
Overhaul items
[Crafter.git] / mods / itemhandling / init.lua
index 3dfcf575f0eb7fa00fcd23c327c0461cfb2f7b20..dd72ce343bacc531ee1e3fb9982c1ad5b6643bc5 100644 (file)
@@ -151,222 +151,197 @@ end
 local stack
 local itemname
 local def
+local set_item = function(self, item)
+       print(item)
+       stack = ItemStack(item or self.itemstring)
+       self.itemstring = stack:to_string()
+       if self.itemstring == "" then
+               -- item not yet known
+               return
+       end
 
-minetest.register_entity(":__builtin:item", {
-       initial_properties = {
-               hp_max = 1,
-
-               physical = true,
-
-               collide_with_objects = false,
-
-               collisionbox = {-0.21, -0.21, -0.21, 0.21, 0.21, 0.21},
+       itemname = stack:is_known() and stack:get_name() or "unknown"
 
-               selectionbox = {-0.21, -0.21, -0.21, 0.21, 0.21, 0.21},
+       def = minetest.registered_nodes[itemname]
 
-               automatic_rotate = 1.5,
-
-               visual = "wielditem",
+       self.object:set_properties({
+               textures = {itemname},
+               wield_item = self.itemstring,
+               glow = def and def.light_source,
+       })
+end
 
-               visual_size = {x = 0.21, y = 0.21},
 
-               textures = {""},
+local get_staticdata = function(self)
+       return minetest.serialize({
+               itemstring = self.itemstring,
+               age = self.age,
+               dropped_by = self.dropped_by,
+               collection_timer = self.collection_timer,
+               collectable = self.collectable,
+               try_timer = self.try_timer,
+               collected = self.collected,
+               delete_timer = self.delete_timer,
+               collector = self.collector,
+               magnet_timer = self.magnet_timer,
+       })
+end
 
-               spritediv = {x = 1, y = 1},
+local on_activate = function(self, staticdata, dtime_s)
+       if string.sub(staticdata, 1, string.len("return")) == "return" then
+               local data = minetest.deserialize(staticdata)
+               if data and type(data) == "table" then
+                       self.itemstring = data.itemstring
+                       self.age = (data.age or 0) + dtime_s
+                       self.dropped_by = data.dropped_by
+                       self.magnet_timer = data.magnet_timer
+                       self.collection_timer = data.collection_timer
+                       self.collectable = data.collectable
+                       self.try_timer = data.try_timer
+                       self.collected = data.collected
+                       self.delete_timer = data.delete_timer
+                       self.collector = data.collector
+               end
+       else
+               print("failing")
+               self.itemstring = staticdata
+       end
+       self.object:set_armor_groups({immortal = 1})
+       self.object:set_velocity({x = 0, y = 2, z = 0})
+       self.object:set_acceleration({x = 0, y = -9.81, z = 0})
+       set_item(self,self.itemstring)
+end
 
-               initial_sprite_basepos = {x = 0, y = 0},
+local enable_physics = function(self)
+       if not self.physical_state then
+               self.physical_state = true
+               self.object:set_properties({physical = true})
+               self.object:set_velocity({x=0, y=0, z=0})
+               self.object:set_acceleration({x=0, y=-9.81, z=0})
+       end
+end
 
-               is_visible = true,
+local disable_physics = function(self)
+       if self.physical_state then
+               self.physical_state = false
+               self.object:set_properties({physical = false})
+               self.object:set_velocity({x=0, y=0, z=0})
+               self.object:set_acceleration({x=0, y=0, z=0})
+       end
+end
 
-               pointable = false,
-       },
+local burn_nodes = {
+       ["fire:fire"]       = true,
+       ["nether:lava"]     = true,
+       ["nether:lavaflow"] = true,
+       ["main:lava"]       = true,
+       ["main:lavaflow"]   = true
+}
+local order = {
+       {x=1, y=0, z=0}, {x=-1, y=0, z= 0},
+       {x=0, y=0, z=1}, {x= 0, y=0, z=-1},
+}
+local collector
+local pos
+local pos2
+local player_velocity
+local direction
+local distance
+local multiplier
+local velocity
+local node
+local is_stuck
+local snode
+local shootdir
+local cnode
+local cdef
+local fpos
+local vel
+local def
+local slip_factor
+local change
+local item_step = function(self, dtime, moveresult)
+       pos = self.object:get_pos()
+       if not pos then
+               return
+       end
 
-       itemstring = "",
-       moving_state = true,
-       slippery_state = false,
-       physical_state = true,
-       -- Item expiry
-       age = 0,
-       -- Pushing item out of solid nodes
-       force_out = nil,
-       force_out_start = nil,
-       --Collection Variables
-       collection_timer = 2,
-       collectable = false,
-       try_timer = 0,
-       collected = false,
-       delete_timer = 0,
-
-       set_item = function(self, item)
-               stack = ItemStack(item or self.itemstring)
-               self.itemstring = stack:to_string()
-               if self.itemstring == "" then
-                       -- item not yet known
+       --if item set to be collected then only execute go to player
+       if self.collected == true then
+               if not self.collector then
+                       self.object:remove()
                        return
                end
 
-               itemname = stack:is_known() and stack:get_name() or "unknown"
+               collector = minetest.get_player_by_name(self.collector)
+               if collector then
+                       self.magnet_timer = self.magnet_timer + dtime   
 
-               def = minetest.registered_nodes[itemname]
+                       disable_physics(self)
 
-               self.object:set_properties({
-                       textures = {itemname},
-                       wield_item = self.itemstring,
-                       glow = def and def.light_source,
-               })
+                       --get the variables
+                       pos2 = collector:get_pos()
+                       player_velocity = collector:get_player_velocity()
+                       pos2.y = pos2.y + 0.5
+                                                       
+                       distance = vector.distance(pos2,pos)
 
-       end,
+                       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
+                               self.object:remove()
+                               return
+                       end
 
-       get_staticdata = function(self)
-               return minetest.serialize({
-                       itemstring = self.itemstring,
-                       age = self.age,
-                       dropped_by = self.dropped_by,
-                       collection_timer = self.collection_timer,
-                       collectable = self.collectable,
-                       try_timer = self.try_timer,
-                       collected = self.collected,
-                       delete_timer = self.delete_timer,
-                       collector = self.collector,
-                       magnet_timer = self.magnet_timer,
-               })
-       end,
+                       direction = vector.normalize(vector.subtract(pos2,pos))
 
-       on_activate = function(self, staticdata, dtime_s)
-               if string.sub(staticdata, 1, string.len("return")) == "return" then
-                       local data = minetest.deserialize(staticdata)
-                       if data and type(data) == "table" then
-                               self.itemstring = data.itemstring
-                               self.age = (data.age or 0) + dtime_s
-                               self.dropped_by = data.dropped_by
-                               self.magnet_timer = data.magnet_timer
-                               self.collection_timer = data.collection_timer
-                               self.collectable = data.collectable
-                               self.try_timer = data.try_timer
-                               self.collected = data.collected
-                               self.delete_timer = data.delete_timer
-                               self.collector = data.collector
-                               --print("restored timer: "..self.collection_timer)
-                       end
-               else
-                       self.itemstring = staticdata
-                       
-                       local x=math.random(-2,2)*math.random()
-                       local y=math.random(2,5)
-                       local z=math.random(-2,2)*math.random()
-                       self.object:set_velocity(vector.new(x,y,z))
-                    -- print(self.collection_timer)
-               end
-               self.object:set_armor_groups({immortal = 1})
-               self.object:set_velocity({x = 0, y = 2, z = 0})
-               self.object:set_acceleration({x = 0, y = -9.81, z = 0})
-               self:set_item()
-       end,
+                       multiplier = 10 - distance -- changed
 
-       enable_physics = function(self)
-               if not self.physical_state then
-                       self.physical_state = true
-                       self.object:set_properties({physical = true})
-                       self.object:set_velocity({x=0, y=0, z=0})
-                       self.object:set_acceleration({x=0, y=-9.81, z=0})
-               end
-       end,
+                       velocity = vector.add(player_velocity,vector.multiply(direction,multiplier))
+                                               
+                       self.object:set_velocity(velocity)
+                       
+                       self.old_magnet_distance = distance
 
-       disable_physics = function(self)
-               if self.physical_state then
-                       self.physical_state = false
-                       self.object:set_properties({physical = false})
-                       self.object:set_velocity({x=0, y=0, z=0})
-                       self.object:set_acceleration({x=0, y=0, z=0})
-               end
-       end,
-       magnet_timer = 0,
-       on_step = function(self, dtime,moveresult)
-               --if item set to be collected then only execute go to player
-               if self.collected == true then
-                       if not self.collector then
-                               self.object:remove()
-                               return
-                       end
-                       local collector = minetest.get_player_by_name(self.collector)
-                       if collector then
-                               self.magnet_timer = self.magnet_timer + dtime
-                               self.object:set_acceleration(vector.new(0,0,0))
-                               self.disable_physics(self)
-                               --get the variables
-                               local pos = self.object:get_pos()
-                               local pos2 = collector:get_pos()
-                               local player_velocity = collector:get_player_velocity()
-                               pos2.y = pos2.y + 0.5
-                                                               
-                               local direction = vector.normalize(vector.subtract(pos2,pos))
-                               local distance = vector.distance(pos2,pos)
-                                                               
-                               --remove if too far away
-                               if distance > 2 then
-                                       distance = 0
-                               end
-                                                               
-                               local multiplier = 20 - distance
-                               local velocity = vector.multiply(direction,multiplier)
-                               
-                               local velocity = vector.add(player_velocity,velocity)
-                               
-                               self.object:set_velocity(velocity)
-                               
-                               if distance < 0.3 or self.magnet_timer > 0.2 or (self.old_magnet_distance and self.old_magnet_distance < distance) then
-                                       self.object:remove()
-                               end
-                               
-                               self.old_magnet_distance = distance
-                               --self.delete_timer = self.delete_timer + dtime
-                               --this is where the item gets removed from world
-                               --if self.delete_timer > 1 then
-                               --      self.object:remove()
-                               --end
-                               return
-                       else
-                               --print(self.collector.." does not exist")
-                               self.object:remove()
-                       end
-               end
-               
-               --allow entity to be collected after timer
-               if self.collectable == false and self.collection_timer >= 2.5 then
-                       self.collectable = true
-               elseif self.collectable == false then
-                       self.collection_timer = self.collection_timer + dtime
-               end
-                               
-               self.age = self.age + dtime
-               if self.age > 300 then
-                       self.itemstring = ""
+                       return
+               else
+                       -- the collector doesn't exist
                        self.object:remove()
                        return
                end
-
-               local pos = self.object:get_pos()
-               --stop crashing if this ever fails
-               if not pos then
-                       return
+       end
+       
+       --allow entity to be collected after timer
+       if self.collectable == false and self.collection_timer >= 2.5 then
+               self.collectable = true
+       elseif self.collectable == false then
+               self.collection_timer = self.collection_timer + dtime
+       end
+                       
+       self.age = self.age + dtime
+       if self.age > 300 then
+               self.object:remove()
+               return
+       end
+       -- polling eases the server load
+       if self.poll_timer > 0 then
+               self.poll_timer = self.poll_timer - dtime
+               if self.poll_timer <= 0 then
+                       self.poll_timer = 0
                end
-               local node = minetest.get_node_or_nil({
-                       x = pos.x,
-                       y = pos.y + self.object:get_properties().collisionbox[2] - 0.05,
-                       z = pos.z
-               })
-               
+               return
+       end
 
-               -- Remove nodes in 'ignore'
-               if node and node.name == "ignore" then
-                       self.itemstring = ""
+       if moveresult and moveresult.touching_ground and table.getn(moveresult.collisions) > 0 then
+               node = minetest.get_node_or_nil(moveresult.collisions[1].node_pos)
+       else
+               node = nil
+       end
+       
+       -- Remove nodes in 'ignore' and burns items
+       if node then
+               if node.name == "ignore" then
                        self.object:remove()
                        return
-               end
-
-               --burn inside fire nodes
-               local node_inside = minetest.get_node_or_nil(pos)
-               if node_inside and (node_inside.name == "fire:fire" or node_inside.name == "nether:lava" or node_inside.name == "nether:lavaflow" or node_inside.name == "main:lava" or node_inside.name == "main:lavaflow") then
+               elseif node and burn_nodes[node.name] then
                        minetest.add_particlespawner({
                                amount = 6,
                                time = 0.001,
@@ -385,137 +360,147 @@ minetest.register_entity(":__builtin:item", {
                                texture = "smoke.png",
                        })
                        minetest.sound_play("fire_extinguish", {pos=pos,gain=0.3,pitch=math.random(80,100)/100})
-                       self.itemstring = ""
                        self.object:remove()
                        return
                end
+       end
 
 
-               local is_stuck = false
-               local snode = minetest.get_node_or_nil(pos)
-               if snode then
-                       local sdef = minetest.registered_nodes[snode.name] or {}
-                       is_stuck = (sdef.walkable == nil or sdef.walkable == true)
-                               and (sdef.collision_box == nil or sdef.collision_box.type == "regular")
-                               and (sdef.node_box == nil or sdef.node_box.type == "regular")
-               end
+       is_stuck = false
+       snode = minetest.get_node_or_nil(pos)
+       if snode ~= "air" then
+               snode = minetest.registered_nodes[snode.name] or {}
+               is_stuck = (snode.walkable == nil or snode.walkable == true)
+                       and (snode.collision_box == nil or snode.collision_box.type == "regular")
+                       and (snode.node_box == nil or snode.node_box.type == "regular")
+       end
 
-               -- Push item out when stuck inside solid node
-               if is_stuck then
-                       local shootdir
-                       local order = {
-                               {x=1, y=0, z=0}, {x=-1, y=0, z= 0},
-                               {x=0, y=0, z=1}, {x= 0, y=0, z=-1},
-                       }
-
-                       -- Check which one of the 4 sides is free
-                       for o = 1, #order do
-                               local cnode = minetest.get_node(vector.add(pos, order[o])).name
-                               local cdef = minetest.registered_nodes[cnode] or {}
-                               if cnode ~= "ignore" and cdef.walkable == false then
-                                       shootdir = order[o]
-                                       break
-                               end
+       -- Push item out when stuck inside solid node
+       if is_stuck then
+               shootdir = nil
+               -- Check which one of the 4 sides is free
+               for o = 1, #order do
+                       cnode = minetest.get_node(vector.add(pos, order[o])).name
+                       cdef = minetest.registered_nodes[cnode] or {}
+                       if cnode ~= "ignore" and cdef.walkable == false then
+                               shootdir = order[o]
+                               break
                        end
-                       -- If none of the 4 sides is free, check upwards
-                       if not shootdir then
-                               shootdir = {x=0, y=1, z=0}
-                               local cnode = minetest.get_node(vector.add(pos, shootdir)).name
-                               if cnode == "ignore" then
-                                       shootdir = nil -- Do not push into ignore
-                               end
-                       end
-
-                       if shootdir then
-                               -- Set new item moving speed accordingly
-                               local newv = vector.multiply(shootdir, 3)
-                               self:disable_physics()
-                               self.object:set_velocity(newv)
+               end
 
-                               self.force_out = newv
-                               self.force_out_start = vector.round(pos)
-                               return
-                       end
-               elseif self.force_out then
-                       -- This code runs after the entity got a push from the above code.
-                       -- It makes sure the entity is entirely outside the solid node
-                       local c = self.object:get_properties().collisionbox
-                       local s = self.force_out_start
-                       local f = self.force_out
-                       local ok = (f.x > 0 and pos.x + c[1] > s.x + 0.5) or
-                               (f.y > 0 and pos.y + c[2] > s.y + 0.5) or
-                               (f.z > 0 and pos.z + c[3] > s.z + 0.5) or
-                               (f.x < 0 and pos.x + c[4] < s.x - 0.5) or
-                               (f.z < 0 and pos.z + c[6] < s.z - 0.5)
-                       if ok then
-                               -- Item was successfully forced out
-                               self.force_out = nil
-                               self:enable_physics()
+               -- If none of the 4 sides is free, check upwards
+               if not shootdir then
+                       shootdir = {x=0, y=1, z=0}
+                       cnode = minetest.get_node(vector.add(pos, shootdir)).name
+                       if cnode == "ignore" then
+                               shootdir = nil -- Do not push into ignore
                        end
                end
 
-               if not self.physical_state then
-                       return -- Don't do anything
+               if shootdir then
+                       -- shove that thing outta there
+                       fpos = vector.round(pos)
+                       if shootdir.x ~= 0 then
+                               shootdir = vector.multiply(shootdir,0.74)
+                               self.object:move_to(vector.new(fpos.x+shootdir.x,pos.y,pos.z))
+                       elseif shootdir.y ~= 0 then
+                               shootdir = vector.multiply(shootdir,0.72)
+                               self.object:move_to(vector.new(pos.x,fpos.y+shootdir.y,pos.z))
+                       elseif shootdir.z ~= 0 then
+                               shootdir = vector.multiply(shootdir,0.74)
+                               self.object:move_to(vector.new(pos.x,pos.y,fpos.z+shootdir.z))
+                       end
+                       return
                end
+       end
 
-               -- Slide on slippery nodes
-               local vel = self.object:get_velocity()
-               local def = node and minetest.registered_nodes[node.name]
-               local is_moving = (def and not def.walkable) or
-                       vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
-               local is_slippery = false
-
-               if def and def.walkable then
-                       local slippery = minetest.get_item_group(node.name, "slippery")
-                       is_slippery = slippery ~= 0
-                       if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then
+       change = false
+       -- Slide on slippery nodes
+       def = node and minetest.registered_nodes[node.name]
+       vel = self.object:get_velocity()
+       if def and def.walkable then
+               slippery = minetest.get_item_group(node.name, "slippery")
+               if slippery ~= 0 then
+                       if math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2 then
                                -- Horizontal deceleration
-                               local slip_factor = 4.0 / (slippery + 4)
+                               slip_factor = 4.0 / (slippery + 4)
                                self.object:set_acceleration({
                                        x = -vel.x * slip_factor,
-                                       y = 0,
+                                       y = -9.81,
                                        z = -vel.z * slip_factor
                                })
-                       elseif vel.y == 0 then
-                               is_moving = false
-                               --[[
-                               local collisionbox = self.object:get_properties().collisionbox
-                               local move_y = collisionbox[2]
-                               if self.move_up == nil then
-                                       self.move_up = true
-                               end
-                               local addition = 0
-                               if self.move_up == true then
-                                       move_y = move_y + (dtime/10)
-                                       addition = (dtime/8)
-                                       if move_y > -0.21 then
-                                               self.move_up = false
-                                       end
-                               elseif self.move_up == false then
-                                       move_y = move_y - (dtime/10)
-                                       if move_y < -0.5 then
-                                               self.move_up = true
-                                       end
-                               end
-                               collisionbox[2] = move_y
-                               self.object:set_properties({collisionbox=collisionbox,physical = true})
-                               ]]--
+                               change = true
+                       elseif (vel.x ~= 0 or vel.z ~= 0) and math.abs(vel.x) <= 0.2 and math.abs(vel.z) <= 0.2 then
+                               self.object:set_velocity(vector.new(0,vel.y,0))
+                               self.object:set_acceleration(vector.new(0,-9.81,0))
+                       end
+               elseif node then
+                       if math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2 then
+                               self.object:add_velocity({
+                                       x = -vel.x * 0.15,
+                                       y = 0,
+                                       z = -vel.z * 0.15
+                               })
+                               change = true
+                       elseif (vel.x ~= 0 or vel.z ~= 0) and math.abs(vel.x) <= 0.2 and math.abs(vel.z) <= 0.2 then
+                               self.object:set_velocity(vector.new(0,vel.y,0))
+                               self.object:set_acceleration(vector.new(0,-9.81,0))
                        end
                end
+       elseif vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0 then
+               change = true
+       end
 
-               if self.moving_state == is_moving and self.slippery_state == is_slippery then
-                       -- Do not update anything until the moving state changes
-                       return
-               end
+       if change == false and self.poll_timer == 0 then
+               self.poll_timer = 0.5
+       end
+end
 
-               self.moving_state = is_moving
-               self.slippery_state = is_slippery
-               
-               if is_moving then
-                       self.object:set_acceleration({x = 0, y = -9.81, z = 0})
-               else
-                       self.object:set_acceleration({x = 0, y = 0, z = 0})
-                       self.object:set_velocity({x = 0, y = 0, z = 0})
-               end
+
+minetest.register_entity(":__builtin:item", {
+       initial_properties = {
+               hp_max           = 1,
+               visual           = "wielditem",
+               physical         = true,
+               textures         = {""},
+               automatic_rotate = 1.5,
+               is_visible       = true,
+               pointable        = false,
+
+               collide_with_objects = false,
+               collisionbox = {-0.21, -0.21, -0.21, 0.21, 0.21, 0.21},
+               selectionbox = {-0.21, -0.21, -0.21, 0.21, 0.21, 0.21},
+               visual_size  = {x = 0.21, y = 0.21},
+       },
+       itemstring = "",
+       moving_state = true,
+       slippery_state = false,
+       physical_state = true,
+       -- Item expiry
+       age = 0,
+       -- Pushing item out of solid nodes
+       force_out       = nil,
+       force_out_start = nil,
+       -- Collection Variables
+       collection_timer = 2,
+       collectable      = false,
+       try_timer        = 0,
+       collected        = false,
+       delete_timer     = 0,
+       -- Used for server delay
+       magnet_timer = 0,
+       poll_timer = 0,
+
+       set_item = set_item,
+
+       get_staticdata = function(self)
+               return(get_staticdata(self))
+       end,
+       on_activate    = function(self, staticdata, dtime_s)
+               on_activate(self, staticdata, dtime_s)
+       end,
+
+       on_step = function(self, dtime, moveresult)
+               item_step(self, dtime, moveresult)
        end,
-})
+})
\ No newline at end of file