VoxeLibre/mods/HUD/mcl_experience/orb.lua

225 lines
5.9 KiB
Lua
Raw Normal View History

2024-04-28 10:22:27 +02:00
-- Constants
local size_min = 20 / 100 -- minimum size, prescaled
local size_max = 59 / 100 -- maximum size, prescaled
local delta_size = (size_max - size_min) / 10 -- Size change for each XP size level
2024-04-28 10:22:27 +02:00
local max_orb_age = 300 -- seconds
local gravity = vector.new(0, -((tonumber(minetest.settings:get("movement_gravity"))) or 9.81), 0)
2021-11-03 19:36:57 +01:00
local size_to_xp = {
2024-04-28 10:22:27 +02:00
-- min and max XP amount for a given size
2021-11-03 19:36:57 +01:00
{-32768, 2}, -- 1
{ 3, 6}, -- 2
{ 7, 16}, -- 3
{ 17, 36}, -- 4
{ 37, 72}, -- 5
{ 73, 148}, -- 6
{ 149, 306}, -- 7
{ 307, 616}, -- 8
{ 617, 1236}, -- 9
{ 1237, 2476}, -- 10
{ 2477, 32767} -- 11
}
local function xp_to_size(xp)
xp = xp or 0
2021-11-03 19:36:57 +01:00
-- Find the size for the xp amount
for i=1,11 do
local bucket = size_to_xp[i]
if xp >= bucket[1] and xp <= bucket[2] then
return (i - 1) * delta_size + size_min
end
2021-11-03 19:36:57 +01:00
end
-- Fallback is the minimum size
return size_min
2021-11-03 19:36:57 +01:00
end
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
2024-04-28 10:22:27 +02:00
local collector = minetest.get_player_by_name(self.collector)
2021-11-03 19:36:57 +01:00
if collector and collector:get_hp() > 0 and vector.distance(self.object:get_pos(),collector:get_pos()) < 7.25 then
self.object:set_acceleration(vector.new(0,0,0))
self.disable_physics(self)
--get the variables
2024-04-28 10:22:27 +02:00
local pos = self.object:get_pos()
local pos2 = collector:get_pos()
2021-11-03 19:36:57 +01:00
2024-04-28 10:22:27 +02:00
local player_velocity = collector:get_velocity() or collector:get_player_velocity()
2021-11-03 19:36:57 +01:00
pos2.y = pos2.y + 0.8
2024-04-28 10:22:27 +02:00
local direction = vector.direction(pos,pos2)
local distance = vector.distance(pos2,pos)
local multiplier = distance
2021-11-03 19:36:57 +01:00
if multiplier < 1 then
multiplier = 1
end
2024-04-28 10:22:27 +02:00
local goal = vector.multiply(direction,multiplier)
local currentvel = self.object:get_velocity()
2021-11-03 19:36:57 +01:00
if distance > 1 then
multiplier = 20 - distance
2024-04-28 10:22:27 +02:00
local velocity = vector.multiply(direction,multiplier)
2021-11-03 19:36:57 +01:00
goal = velocity
2024-04-28 10:22:27 +02:00
local acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
2021-11-03 19:36:57 +01:00
self.object:add_velocity(vector.add(acceleration,player_velocity))
elseif distance < 0.8 then
mcl_experience.add_xp(collector, self._xp)
self.object:remove()
end
return
else
self.collector = nil
self:enable_physics()
2021-11-03 19:36:57 +01:00
end
end
-- Age orbs
2021-11-03 19:36:57 +01:00
self.age = self.age + dtime
if self.age > max_orb_age then
self.object:remove()
return
end
2024-04-28 10:22:27 +02:00
local pos = self.object:get_pos()
if not pos then return end
2021-11-03 19:36:57 +01:00
2024-04-28 10:22:27 +02:00
local node = minetest.get_node_or_nil({
x = pos.x,
y = pos.y -0.25,
z = pos.z
})
2021-11-03 19:36:57 +01:00
-- 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
2024-04-28 10:22:27 +02:00
local vel = self.object:get_velocity()
local def = node and minetest.registered_nodes[node.name]
local is_moving = (def and not def.walkable) or
2021-11-03 19:36:57 +01:00
vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
2024-04-28 10:22:27 +02:00
local is_slippery = false
2021-11-03 19:36:57 +01:00
if def and def.walkable then
2024-04-28 10:22:27 +02:00
local slippery = minetest.get_item_group(node.name, "slippery")
2021-11-03 19:36:57 +01:00
is_slippery = slippery ~= 0
if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then
-- Horizontal deceleration
2024-04-28 10:22:27 +02:00
local slip_factor = 4.0 / (slippery + 4)
2021-11-03 19:36:57 +01:00
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(gravity)
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("mcl_experience:orb", {
initial_properties = {
hp_max = 1,
physical = true,
collide_with_objects = false,
collisionbox = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2},
visual = "sprite",
visual_size = {x = 0.4, y = 0.4},
textures = {"mcl_experience_orb.png"},
2021-11-03 19:36:57 +01:00
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,
-- Item expiry
age = 0,
-- Pushing item out of solid nodes
force_out = nil,
force_out_start = nil,
--Collection Variables
collectable = false,
try_timer = 0,
collected = false,
delete_timer = 0,
radius = 4,
on_activate = function(self, staticdata, dtime_s)
self.object:set_velocity(vector.new(
math.random(-2,2)*math.random(),
math.random(2,5),
math.random(-2,2)*math.random()
))
self.object:set_armor_groups({immortal = 1})
self.object:set_velocity({x = 0, y = 2, z = 0})
self.object:set_acceleration(gravity)
-- Assign 0 xp in case the entity was persisted even though it should not have been (static_save = false)
-- This was a minetest bug for a while: https://github.com/minetest/minetest/issues/14420
local xp = tonumber(staticdata) or 0
2021-11-03 19:36:57 +01:00
self._xp = xp
2024-04-28 10:22:27 +02:00
local size = xp_to_size(xp)
self.object:set_properties({
2021-11-03 19:36:57 +01:00
visual_size = {x = size, y = size},
glow = 14,
})
self.object:set_sprite({x=1,y=math.random(1,14)}, 14, 0.05, false)
end,
get_staticdata = function(self)
2024-04-28 10:46:13 +02:00
return tostring(self._xp or 0)
end,
2021-11-03 19:36:57 +01:00
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(gravity)
end
end,
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,
on_step = function(self, dtime)
xp_step(self, dtime)
end,
})