]> git.lizzy.rs Git - Crafter.git/blobdiff - mods/experience/init.lua
Make xp slightly faster
[Crafter.git] / mods / experience / init.lua
index 43444d0e78e9ac66d36b95ab5852b70fd192c387..f40f107564aeb83b528fb47dcb6274b6243f9a23 100644 (file)
@@ -1,3 +1,122 @@
+local
+minetest,math,vector,os,pairs,type
+=
+minetest,math,vector,os,pairs,type
+
+local mod_storage = minetest.get_mod_storage()
+
+-- minetest library
+local get_node_or_nil    = minetest.get_node_or_nil
+local get_time           = minetest.get_us_time
+local get_player_by_name = minetest.get_player_by_name
+local yaw_to_dir         = minetest.yaw_to_dir
+local dir_to_yaw         = minetest.dir_to_yaw
+local get_item_group     = minetest.get_item_group
+local serialize          = minetest.serialize
+local deserialize        = minetest.deserialize
+local play_sound         = minetest.sound_play
+local registered_nodes
+minetest.register_on_mods_loaded(function()
+       registered_nodes = minetest.registered_nodes
+end)
+
+-- vector library
+local new_vec       = vector.new
+local vec_distance  = vector.distance
+local add_vec       = vector.add
+local multiply_vec  = vector.multiply
+local vec_direction = vector.direction
+
+-- math library
+local pi     = math.pi
+local random = math.random
+local abs    = math.abs
+
+-- string library
+local s_sub  = string.sub
+local s_len  = string.len
+
+local pool = {}
+-- loads data from mod storage
+local name
+local temp_pool
+local load_data = function(player)
+       name = player:get_player_name()
+       pool[name] = {}
+       temp_pool = pool[name]
+       if mod_storage:get_int(name.."xp_save") > 0 then
+               temp_pool.xp_level = mod_storage:get_int(name.."xp_level")
+               temp_pool.xp_bar   = mod_storage:get_int(name.."xp_bar"  )
+               temp_pool.buffer   = 0
+               temp_pool.last_time= get_time()/1000000
+       else
+               temp_pool.xp_level = 0
+               temp_pool.xp_bar   = 0
+               temp_pool.buffer   = 0
+               temp_pool.last_time= get_time()/1000000
+       end
+end
+
+-- saves data to be utilized on next login
+local name
+local temp_pool
+local save_data = function(name)
+       if type(name) ~= "string" and name:is_player() then
+               name = name:get_player_name()
+       end
+       temp_pool = pool[name]
+       
+       mod_storage:set_int(name.."xp_level",temp_pool.xp_level)
+       mod_storage:set_int(name.."xp_bar",  temp_pool.xp_bar  )
+
+       mod_storage:set_int(name.."xp_save",1)
+
+       pool[name] = nil
+end
+
+-- saves specific users data for when they relog
+minetest.register_on_leaveplayer(function(player)
+       save_data(player)
+end)
+
+-- is used for shutdowns to save all data
+local save_all = function()
+       for name,_ in pairs(pool) do
+               save_data(name)
+       end
+end
+
+-- save all data to mod storage on shutdown
+minetest.register_on_shutdown(function()
+       save_all()
+end)
+
+
+local name
+function get_player_xp_level(player)
+       name = player:get_player_name()
+       return(pool[name].xp_level)
+end
+
+local name
+local temp_pool
+function set_player_xp_level(player,level)
+       name = player:get_player_name()
+       pool[name].xp_level = level
+       hud_manager.change_hud({
+               player   = player,
+               hud_name = "xp_level_fg",
+               element  = "text",
+               data     = tostring(level)
+       })
+       hud_manager.change_hud({
+               player   = player,
+               hud_name = "xp_level_bg",
+               element  = "text",
+               data     = tostring(level)
+       })
+end
+
 minetest.hud_replace_builtin("health",{
     hud_elem_type = "statbar",
     position = {x = 0.5, y = 1},
@@ -8,11 +127,16 @@ minetest.hud_replace_builtin("health",{
     offset = {x = (-10 * 24) - 25, y = -(48 + 24 + 38)},
 })
 
-local experience_bar_max = 36
+local name
+local temp_pool
 minetest.register_on_joinplayer(function(player)
-    local meta = player:get_meta()
-    meta:set_float("experience_collection_buffer",0)
-        player:hud_add({
+
+       load_data(player)
+
+       name = player:get_player_name()
+       temp_pool = pool[name]
+               
+    hud_manager.add_hud(player,"heart_bar_bg",{
         hud_elem_type = "statbar",
         position = {x = 0.5, y = 1},
         text = "heart_bg.png",
@@ -20,202 +144,289 @@ minetest.register_on_joinplayer(function(player)
         direction = 0,
         size = {x = 24, y = 24},
         offset = {x = (-10 * 24) - 25, y = -(48 + 24 + 38)},
-    })
-    player:hud_add({
-        hud_elem_type = "statbar",  -- See HUD element types
-        -- Type of element, can be "image", "text", "statbar", or "inventory"
+       })
+       
 
+    hud_manager.add_hud(player,"experience_bar_background",{
+        hud_elem_type = "statbar",
         position = {x=0.5, y=1},
-        -- Left corner position of element
-
-        name = "experience",
-
-        --scale = {x = 2, y = 2},
-
+        name = "experience bar background",
         text = "experience_bar_background.png",
-
-        number = experience_bar_max,
-
-        --item = 3,
-        -- Selected item in inventory. 0 for no item selected.
-
+        number = 36,
         direction = 0,
-        -- Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
-
         offset = {x = (-8 * 28) - 29, y = -(48 + 24 + 16)},
-
         size = { x=28, y=28 },
-        -- Size of element in pixels
-
         z_index = 0,
-        -- Z index : lower z-index HUDs are displayed behind higher z-index HUDs
-    })
-    local hud_id = player:hud_add({
-        hud_elem_type = "statbar",  -- See HUD element types
-        -- Type of element, can be "image", "text", "statbar", or "inventory"
-
+       })
+       
+    hud_manager.add_hud(player,"experience_bar",{
+        hud_elem_type = "statbar",
         position = {x=0.5, y=1},
-        -- Left corner position of element
-
-        name = "experience",
-
-        --scale = {x = 2, y = 2},
-
+        name = "experience bar",
         text = "experience_bar.png",
-
-        number = meta:get_int("experience_bar_count"),
-
-        --item = 3,
-        -- Selected item in inventory. 0 for no item selected.
-
+        number = temp_pool.xp_bar,
         direction = 0,
-        -- Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
-
         offset = {x = (-8 * 28) - 29, y = -(48 + 24 + 16)},
-
         size = { x=28, y=28 },
-        -- Size of element in pixels
-
         z_index = 0,
-        -- Z index : lower z-index HUDs are displayed behind higher z-index HUDs
     })
-    
-    local meta = player:get_meta()
-    local level = meta:get_int("experience_level")                                
-    local hud_bg_id = player:hud_add({
-        hud_elem_type = "text",  -- See HUD element types
-        -- Type of element, can be "image", "text", "statbar", or "inventory"
-
+       
+    hud_manager.add_hud(player,"xp_level_bg",{
+        hud_elem_type = "text",
         position = {x=0.5, y=1},
-        -- Left corner position of element
-
-        name = "levelbg",
-
-        --scale = {x = 2, y = 2},
-
-        text = tostring(level),
-
-        number = 0x000000,--0xFFFFFF,
-
-        --item = 3,
-        -- Selected item in inventory. 0 for no item selected.
-
-        --direction = 0,
-        -- Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
-
+        name = "xp_level_bg",
+        text = tostring(temp_pool.xp_level),
+        number = 0x000000,
         offset = {x = 0, y = -(48 + 24 + 24)},
-
-        size = { x=28, y=28 },
-        -- Size of element in pixels
-
         z_index = 0,
-        -- Z index : lower z-index HUDs are displayed behind higher z-index HUDs
     })                            
-    local hud_fg_id = player:hud_add({
-        hud_elem_type = "text",  -- See HUD element types
-        -- Type of element, can be "image", "text", "statbar", or "inventory"
-
+    hud_manager.add_hud(player,"xp_level_fg",{
+        hud_elem_type = "text",
         position = {x=0.5, y=1},
-        -- Left corner position of element
-
-        name = "levelfg",
-
-        --scale = {x = 2, y = 2},
-
-        text = tostring(level),
-
+        name = "xp_level_fg",
+        text = tostring(temp_pool.xp_level),
         number = 0xFFFFFF,
-
-        --item = 3,
-        -- Selected item in inventory. 0 for no item selected.
-
-        --direction = 0,
-        -- Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
-
         offset = {x = -1, y = -(48 + 24 + 25)},
-
-        size = { x=28, y=28 },
-        -- Size of element in pixels
-
         z_index = 0,
-        -- Z index : lower z-index HUDs are displayed behind higher z-index HUDs
-    }) 
-    meta:set_int("experience_bar", hud_id)
-    meta:set_int("experience_level_fg", hud_fg_id)                                
-    meta:set_int("experience_level_bg", hud_bg_id)                                                            
+       })                                                           
 end)
 
 
-function level_up_experience(player)
-    local meta = player:get_meta()
-    local level = meta:get_int("experience_level")
-    level = level + 1
-    meta:set_int("experience_level",level)
-    
-    local hud_fg_id = meta:get_int("experience_level_fg")
-    local hud_bg_id = meta:get_int("experience_level_bg")
-    
-    player:hud_change(hud_bg_id, "text", tostring(level))
-    player:hud_change(hud_fg_id, "text", tostring(level))
+local name
+local temp_pool
+local function level_up_experience(player)
+       name = player:get_player_name()
+       temp_pool = pool[name]
+       
+    temp_pool.xp_level = temp_pool.xp_level + 1
+       
+       hud_manager.change_hud({
+               player   = player,
+               hud_name = "xp_level_fg",
+               element  = "text",
+               data     = tostring(temp_pool.xp_level)
+       })
+       hud_manager.change_hud({
+               player   = player,
+               hud_name = "xp_level_bg",
+               element  = "text",
+               data     = tostring(temp_pool.xp_level)
+       })
 end
 
-function add_experience(player,experience)
-    local meta = player:get_meta()
-    local hud_id = meta:get_int("experience_bar")
-    local hud = player:hud_get(hud_id)
-    local bar_count = hud.number
-    bar_count = bar_count + experience
-    if bar_count > experience_bar_max then
-        minetest.sound_play("level_up",{gain=0.2,to_player = player:get_player_name()})
-        bar_count = bar_count - experience_bar_max
-        level_up_experience(player)
-    else
-        minetest.sound_play("experience",{gain=0.1,to_player = player:get_player_name(),pitch=math.random(75,99)/100})
-    end
-    meta:set_int("experience_bar_count",bar_count)
-    player:hud_change(hud_id, number, bar_count)
-end
 
---[[
-local function test_experience()
-    for _, player in pairs(minetest.get_connected_players()) do
-        add_experience(player,math.random(1,3)*2)
-    end
-       
-    minetest.after(0.1, function()
-        test_experience()
-    end)
+local name
+local temp_pool
+local function add_experience(player,experience)
+       name = player:get_player_name()
+       temp_pool = pool[name]
+       
+       temp_pool.xp_bar = temp_pool.xp_bar + experience
+       
+       if temp_pool.xp_bar > 36 then
+               if get_time()/1000000 - temp_pool.last_time > 0.04 then
+                       play_sound("level_up",{gain=0.2,to_player = name})
+                       temp_pool.last_time = get_time()/1000000
+               end
+        temp_pool.xp_bar = temp_pool.xp_bar - 36
+               level_up_experience(player)
+       else
+               if get_time()/1000000 - temp_pool.last_time > 0.01 then
+                       temp_pool.last_time = get_time()/1000000
+                       play_sound("experience",{gain=0.1,to_player = name,pitch=random(75,99)/100})
+               end
+       end
+       hud_manager.change_hud({
+               player   = player,
+               hud_name = "experience_bar",
+               element  = "number",
+               data     = temp_pool.xp_bar
+       })
 end
-test_experience()                  
-]]--
 
 --reset player level
+local name
+local temp_pool
+local xp_amount
 minetest.register_on_dieplayer(function(player)
-    local meta = player:get_meta()
-    local amount_of_experience = (meta:get_int("experience_bar_count")/2) + (meta:get_int("experience_level") * 18)
-    --bar
-    meta:set_int("experience_bar_count",0)
-    local hud_id = meta:get_int("experience_bar")
-    player:hud_change(hud_id, number, 0)
-                              
-    --level number
-    local level = 0
-    meta:set_int("experience_level",level)
-    
-    local hud_fg_id = meta:get_int("experience_level_fg")
-    local hud_bg_id = meta:get_int("experience_level_bg")
-    
-    player:hud_change(hud_bg_id, "text", tostring(level))
-    player:hud_change(hud_fg_id, "text", tostring(level))
-                              
-    minetest.throw_experience(player:get_pos(), amount_of_experience)
-                              
+       name = player:get_player_name()
+       temp_pool = pool[name]
+       xp_amount = temp_pool.xp_level
+       
+       temp_pool.xp_bar   = 0
+       temp_pool.xp_level = 0
+
+
+       hud_manager.change_hud({
+               player   = player,
+               hud_name = "xp_level_fg",
+               element  = "text",
+               data     = tostring(temp_pool.xp_level)
+       })
+       hud_manager.change_hud({
+               player   = player,
+               hud_name = "xp_level_bg",
+               element  = "text",
+               data     = tostring(temp_pool.xp_level)
+       })
+
+       hud_manager.change_hud({
+               player   = player,
+               hud_name = "experience_bar",
+               element  = "number",
+               data     = temp_pool.xp_bar
+       })
+
+    minetest.throw_experience(player:get_pos(), xp_amount)                       
 end)
 
 
-local time_to_live = tonumber(minetest.settings:get("item_entity_ttl")) or 300
-local gravity = tonumber(minetest.settings:get("movement_gravity")) or 9.81
+local name
+local temp_pool
+local collector
+local pos
+local pos2
+local direction
+local distance
+local player_velocity
+local goal
+local currentvel
+local acceleration
+local multiplier
+local velocity
+local node
+local vel
+local def
+local is_moving
+local is_slippery
+local slippery
+local slip_factor
+local size
+local data
+local function xp_step(self, dtime)
+       --if item set to be collected then only execute go to player
+       if self.collected == true then
+               if not self.collector then
+                       self.collected = false
+                       return
+               end
+               collector = get_player_by_name(self.collector)
+               if collector and collector:get_hp() > 0 and vec_distance(self.object:get_pos(),collector:get_pos()) < 5 then
+                       temp_pool = pool[self.collector]
+
+                       self.object:set_acceleration(new_vec(0,0,0))
+                       self.disable_physics(self)
+                       --get the variables
+                       pos = self.object:get_pos()
+                       pos2 = collector:get_pos()
+                       
+                       player_velocity = collector:get_player_velocity()
+                                                                               
+                       pos2.y = pos2.y + 0.8
+                                                       
+                       direction = vec_direction(pos,pos2)
+                       distance = vec_distance(pos2,pos)
+                       multiplier = distance
+                       if multiplier < 1 then
+                               multiplier = 1
+                       end
+                       goal = multiply_vec(direction,multiplier)
+                       currentvel = self.object:get_velocity()
+
+                       if distance > 1 then
+                               multiplier = 20 - distance
+                               velocity = multiply_vec(direction,multiplier)
+                               goal = velocity
+                               acceleration = new_vec(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
+                               self.object:add_velocity(add_vec(acceleration,player_velocity))
+                       elseif distance > 0.9 and temp_pool.buffer > 0 then
+                               temp_pool.buffer = temp_pool.buffer - dtime
+                               multiplier = 20 - distance
+                               velocity = multiply_vec(direction,multiplier)
+                               goal = multiply_vec(yaw_to_dir(dir_to_yaw(vec_direction(new_vec(pos.x,0,pos.z),new_vec(pos2.x,0,pos2.z)))+pi/2),10)
+                               goal = add_vec(player_velocity,goal)
+                               acceleration = new_vec(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
+                               self.object:add_velocity(acceleration)
+                       end
+                       if distance < 0.4 and temp_pool.buffer <= 0 then
+                               temp_pool.buffer = 0.04
+                               add_experience(collector,2)
+                               self.object:remove()
+                       end
+                       return
+               else
+                       self.collector = nil
+                       self.enable_physics(self)
+               end
+       end
+
+                                       
+       self.age = self.age + dtime
+       if self.age > 300 then
+               self.object:remove()
+               return
+       end
+
+       pos = self.object:get_pos()
 
+       if pos then
+               node = get_node_or_nil({
+                       x = pos.x,
+                       y = pos.y -0.25,
+                       z = pos.z
+               })
+       else
+               return
+       end
+
+       -- Remove nodes in 'ignore'
+       if node and node.name == "ignore" then
+               self.object:remove()
+               return
+       end
+
+       if not self.physical_state then
+               return -- Don't do anything
+       end
+
+       -- Slide on slippery nodes
+       vel = self.object:get_velocity()
+       def = node and registered_nodes[node.name]
+       is_moving = (def and not def.walkable) or
+               vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
+       is_slippery = false
+
+       if def and def.walkable then
+               slippery = get_item_group(node.name, "slippery")
+               is_slippery = slippery ~= 0
+               if is_slippery and (abs(vel.x) > 0.2 or abs(vel.z) > 0.2) then
+                       -- Horizontal deceleration
+                       slip_factor = 4.0 / (slippery + 4)
+                       self.object:set_acceleration({
+                               x = -vel.x * slip_factor,
+                               y = 0,
+                               z = -vel.z * slip_factor
+                       })
+               elseif vel.y == 0 then
+                       is_moving = false
+               end
+       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
+
+       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
+end
 
 minetest.register_entity("experience:orb", {
        initial_properties = {
@@ -225,13 +436,12 @@ minetest.register_entity("experience:orb", {
                collisionbox = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2},
                visual = "sprite",
                visual_size = {x = 0.4, y = 0.4},
-               textures = {"experience_orb.png"},
-               spritediv = {x = 1, y = 1},
+               textures = {name="experience_orb.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}},
+               spritediv = {x = 1, y = 14},
                initial_sprite_basepos = {x = 0, y = 0},
                is_visible = true,
                pointable = false,
        },
-
        moving_state = true,
        slippery_state = false,
        physical_state = true,
@@ -241,20 +451,15 @@ minetest.register_entity("experience:orb", {
        force_out = nil,
        force_out_start = nil,
        --Collection Variables
-       collection_timer = 2,
-       collection_timer_goal = collection.collection_time,
-       collection_height = 0.8,
        collectable = false,
        try_timer = 0,
        collected = false,
        delete_timer = 0,
-       radius = collection.magnet_radius,
-       time_to_live = time_to_live,
+       radius = 4,
 
        get_staticdata = function(self)
-               return minetest.serialize({
+               return serialize({
                        age = self.age,
-                       collection_timer = self.collection_timer,
                        collectable = self.collectable,
                        try_timer = self.try_timer,
                        collected = self.collected,
@@ -264,34 +469,32 @@ minetest.register_entity("experience:orb", {
        end,
 
        on_activate = function(self, staticdata, dtime_s)
-               if string.sub(staticdata, 1, string.len("return")) == "return" then
-                       local data = minetest.deserialize(staticdata)
+               if s_sub(staticdata, 1, s_len("return")) == "return" then
+                       data = deserialize(staticdata)
                        if data and type(data) == "table" then
                                self.age = (data.age or 0) + dtime_s
-                               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
-
-                       local x=math.random(-2,2)*math.random()
-                       local y=math.random(2,5)
-                       local z=math.random(-2,2)*math.random()
-                       self.object:setvelocity(vector.new(x,y,z))
-                    -- print(self.collection_timer)
+                       self.object:set_velocity(new_vec(
+                               random(-2,2)*random(),
+                               random(2,5),
+                               random(-2,2)*random()
+                       ))
                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 = -gravity, z = 0})
-        local size = math.random(20,36)/100
+               self.object:set_acceleration({x = 0, y = -9.81, z = 0})
+        size = random(20,36)/100
         self.object:set_properties({
                        visual_size = {x = size, y = size},
                        glow = 14,
                })
+               self.object:set_sprite({x=1,y=random(1,14)}, 14, 0.05, false)
        end,
 
        enable_physics = function(self)
@@ -299,7 +502,7 @@ minetest.register_entity("experience:orb", {
                        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=-gravity, z=0})
+                       self.object:set_acceleration({x=0, y=-9.81, z=0})
                end
        end,
 
@@ -312,201 +515,19 @@ minetest.register_entity("experience:orb", {
                end
        end,
        on_step = function(self, dtime)
-               --if item set to be collected then only execute go to player
-               if self.collected == true then
-                       if not self.collector then
-                               self.collected = false
-                               return
-                       end
-                       local collector = minetest.get_player_by_name(self.collector)
-                       if collector and collector:get_hp() > 0 then
-                               self.object:setacceleration(vector.new(0,0,0))
-                               self.disable_physics(self)
-                               --get the variables
-                               local pos = self.object:getpos()
-                               local pos2 = collector:getpos()
-                               
-                local player_velocity = collector:get_player_velocity()
-                                            
-                               pos2.y = pos2.y + self.collection_height
-                                                               
-                               local direction = vector.direction(pos,pos2)
-                               local distance = vector.distance(pos2,pos)
-                local multiplier = distance
-                if multiplier < 1 then
-                    multiplier = 1
-                end
-                               local goal = vector.multiply(direction,multiplier)
-                local currentvel = self.object:get_velocity()
-                local acceleration
-                               if distance > 1 then
-                    local multiplier = (self.radius*5) - distance
-                    local velocity = vector.multiply(direction,multiplier)
-                    local goal = velocity--vector.add(player_velocity,velocity)
-                    acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
-                else
-                    acceleration = vector.new(goal.x,goal.y,goal.z)
-                end
-                               --acceleration = vector.multiply(acceleration, )
-                                            
-                
-                               
-                               self.object:add_velocity(acceleration)
-                               
-                                            
-                                            
-                    
-                local meta = collector:get_meta()
-                local experience_collection_buffer = meta:get_float("experience_collection_buffer")
-                               if distance < 0.2 and experience_collection_buffer == 0 then
-                    meta:set_float("experience_collection_buffer",0.04)
-                    add_experience(collector,2)
-                                       self.object:remove()
-                               end
-                               
-                               
-                               --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 >= self.collection_timer_goal then
-                       self.collectable = true
-               elseif self.collectable == false then
-                       self.collection_timer = self.collection_timer + dtime
-               end
-                               
-               self.age = self.age + dtime
-               if self.time_to_live > 0 and self.age > self.time_to_live then
-                       self.object:remove()
-                       return
-               end
-
-               local pos = self.object:get_pos()
-               local node = minetest.get_node_or_nil({
-                       x = pos.x,
-                       y = pos.y + self.object:get_properties().collisionbox[2] - 0.05,
-                       z = pos.z
-               })
-               
-
-               -- Remove nodes in 'ignore'
-               if node and node.name == "ignore" then
-                       self.object:remove()
-                       return
-               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
-
-               -- 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
-                       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)
-
-                               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()
-                       end
-               end
-
-               if not self.physical_state then
-                       return -- Don't do anything
-               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
-                               -- Horizontal deceleration
-                               local slip_factor = 4.0 / (slippery + 4)
-                               self.object:set_acceleration({
-                                       x = -vel.x * slip_factor,
-                                       y = 0,
-                                       z = -vel.z * slip_factor
-                               })
-                       elseif vel.y == 0 then
-                               is_moving = false
-                       end
-               end
+               xp_step(self, dtime)
+       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
 
-               self.moving_state = is_moving
-               self.slippery_state = is_slippery
-               
-               if is_moving then
-                       self.object:set_acceleration({x = 0, y = -gravity, 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_chatcommand("xp", {
+       params = "nil",
+       description = "Spawn x amount of a mob, used as /spawn 'mob' 10 or /spawn 'mob' for one",
+       privs = {server=true},
+       func = function(name)
+               local player = get_player_by_name(name)
+               local pos = player:get_pos()
+               pos.y = pos.y + 1.2
+               minetest.throw_experience(pos, 1000)
        end,
 })