1 minetest.hud_replace_builtin("health",{
2 hud_elem_type = "statbar",
3 position = {x = 0.5, y = 1},
5 number = core.PLAYER_MAX_HP_DEFAULT,
7 size = {x = 24, y = 24},
8 offset = {x = (-10 * 24) - 25, y = -(48 + 24 + 38)},
11 local experience_bar_max = 36
12 minetest.register_on_joinplayer(function(player)
13 local meta = player:get_meta()
14 meta:set_float("experience_collection_buffer",0)
16 hud_elem_type = "statbar",
17 position = {x = 0.5, y = 1},
18 text = "heart_bg.png",
19 number = core.PLAYER_MAX_HP_DEFAULT,
21 size = {x = 24, y = 24},
22 offset = {x = (-10 * 24) - 25, y = -(48 + 24 + 38)},
25 hud_elem_type = "statbar", -- See HUD element types
26 -- Type of element, can be "image", "text", "statbar", or "inventory"
28 position = {x=0.5, y=1},
29 -- Left corner position of element
33 --scale = {x = 2, y = 2},
35 text = "experience_bar_background.png",
37 number = experience_bar_max,
40 -- Selected item in inventory. 0 for no item selected.
43 -- Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
45 offset = {x = (-8 * 28) - 29, y = -(48 + 24 + 16)},
47 size = { x=28, y=28 },
48 -- Size of element in pixels
51 -- Z index : lower z-index HUDs are displayed behind higher z-index HUDs
53 local hud_id = player:hud_add({
54 hud_elem_type = "statbar", -- See HUD element types
55 -- Type of element, can be "image", "text", "statbar", or "inventory"
57 position = {x=0.5, y=1},
58 -- Left corner position of element
62 --scale = {x = 2, y = 2},
64 text = "experience_bar.png",
66 number = meta:get_int("experience_bar_count"),
69 -- Selected item in inventory. 0 for no item selected.
72 -- Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
74 offset = {x = (-8 * 28) - 29, y = -(48 + 24 + 16)},
76 size = { x=28, y=28 },
77 -- Size of element in pixels
80 -- Z index : lower z-index HUDs are displayed behind higher z-index HUDs
83 local meta = player:get_meta()
84 local level = meta:get_int("experience_level")
85 local hud_bg_id = player:hud_add({
86 hud_elem_type = "text", -- See HUD element types
87 -- Type of element, can be "image", "text", "statbar", or "inventory"
89 position = {x=0.5, y=1},
90 -- Left corner position of element
94 --scale = {x = 2, y = 2},
96 text = tostring(level),
98 number = 0x000000,--0xFFFFFF,
101 -- Selected item in inventory. 0 for no item selected.
104 -- Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
106 offset = {x = 0, y = -(48 + 24 + 24)},
108 size = { x=28, y=28 },
109 -- Size of element in pixels
112 -- Z index : lower z-index HUDs are displayed behind higher z-index HUDs
114 local hud_fg_id = player:hud_add({
115 hud_elem_type = "text", -- See HUD element types
116 -- Type of element, can be "image", "text", "statbar", or "inventory"
118 position = {x=0.5, y=1},
119 -- Left corner position of element
123 --scale = {x = 2, y = 2},
125 text = tostring(level),
130 -- Selected item in inventory. 0 for no item selected.
133 -- Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
135 offset = {x = -1, y = -(48 + 24 + 25)},
137 size = { x=28, y=28 },
138 -- Size of element in pixels
141 -- Z index : lower z-index HUDs are displayed behind higher z-index HUDs
143 meta:set_int("experience_bar", hud_id)
144 meta:set_int("experience_level_fg", hud_fg_id)
145 meta:set_int("experience_level_bg", hud_bg_id)
149 function level_up_experience(player)
150 local meta = player:get_meta()
151 local level = meta:get_int("experience_level")
153 meta:set_int("experience_level",level)
155 local hud_fg_id = meta:get_int("experience_level_fg")
156 local hud_bg_id = meta:get_int("experience_level_bg")
158 player:hud_change(hud_bg_id, "text", tostring(level))
159 player:hud_change(hud_fg_id, "text", tostring(level))
162 function add_experience(player,experience)
163 local meta = player:get_meta()
164 local hud_id = meta:get_int("experience_bar")
165 local hud = player:hud_get(hud_id)
166 local bar_count = hud.number
167 bar_count = bar_count + experience
168 if bar_count > experience_bar_max then
169 minetest.sound_play("level_up",{gain=0.2,to_player = player:get_player_name()})
170 bar_count = bar_count - experience_bar_max
171 level_up_experience(player)
173 minetest.sound_play("experience",{gain=0.1,to_player = player:get_player_name(),pitch=math.random(75,99)/100})
175 meta:set_int("experience_bar_count",bar_count)
176 player:hud_change(hud_id, number, bar_count)
180 local function test_experience()
181 for _, player in pairs(minetest.get_connected_players()) do
182 add_experience(player,math.random(1,3)*2)
185 minetest.after(0.1, function()
193 minetest.register_on_dieplayer(function(player)
194 local meta = player:get_meta()
195 local amount_of_experience = (meta:get_int("experience_bar_count")/2) + (meta:get_int("experience_level") * 18)
197 meta:set_int("experience_bar_count",0)
198 local hud_id = meta:get_int("experience_bar")
199 player:hud_change(hud_id, number, 0)
203 meta:set_int("experience_level",level)
205 local hud_fg_id = meta:get_int("experience_level_fg")
206 local hud_bg_id = meta:get_int("experience_level_bg")
208 player:hud_change(hud_bg_id, "text", tostring(level))
209 player:hud_change(hud_fg_id, "text", tostring(level))
211 minetest.throw_experience(player:get_pos(), amount_of_experience)
216 local time_to_live = tonumber(minetest.settings:get("item_entity_ttl")) or 300
217 local gravity = tonumber(minetest.settings:get("movement_gravity")) or 9.81
220 minetest.register_entity("experience:orb", {
221 initial_properties = {
224 collide_with_objects = false,
225 collisionbox = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2},
227 visual_size = {x = 0.4, y = 0.4},
228 textures = {name="experience_orb.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}},
229 spritediv = {x = 1, y = 14},
230 initial_sprite_basepos = {x = 0, y = 0},
235 slippery_state = false,
236 physical_state = true,
239 -- Pushing item out of solid nodes
241 force_out_start = nil,
242 --Collection Variables
243 collection_timer = 2,
244 collection_timer_goal = collection.collection_time,
245 collection_height = 0.8,
250 radius = collection.magnet_radius,
251 time_to_live = time_to_live,
253 get_staticdata = function(self)
254 return minetest.serialize({
256 collection_timer = self.collection_timer,
257 collectable = self.collectable,
258 try_timer = self.try_timer,
259 collected = self.collected,
260 delete_timer = self.delete_timer,
261 collector = self.collector,
265 on_activate = function(self, staticdata, dtime_s)
266 if string.sub(staticdata, 1, string.len("return")) == "return" then
267 local data = minetest.deserialize(staticdata)
268 if data and type(data) == "table" then
269 self.age = (data.age or 0) + dtime_s
270 self.collection_timer = data.collection_timer
271 self.collectable = data.collectable
272 self.try_timer = data.try_timer
273 self.collected = data.collected
274 self.delete_timer = data.delete_timer
275 self.collector = data.collector
276 --print("restored timer: "..self.collection_timer)
280 local x=math.random(-2,2)*math.random()
281 local y=math.random(2,5)
282 local z=math.random(-2,2)*math.random()
283 self.object:setvelocity(vector.new(x,y,z))
284 -- print(self.collection_timer)
286 self.object:set_armor_groups({immortal = 1})
287 self.object:set_velocity({x = 0, y = 2, z = 0})
288 self.object:set_acceleration({x = 0, y = -gravity, z = 0})
289 local size = math.random(20,36)/100
290 self.object:set_properties({
291 visual_size = {x = size, y = size},
294 self.object:set_sprite({x=1,y=math.random(1,14)}, 14, 0.05, false)
297 enable_physics = function(self)
298 if not self.physical_state then
299 self.physical_state = true
300 self.object:set_properties({physical = true})
301 self.object:set_velocity({x=0, y=0, z=0})
302 self.object:set_acceleration({x=0, y=-gravity, z=0})
306 disable_physics = function(self)
307 if self.physical_state then
308 self.physical_state = false
309 self.object:set_properties({physical = false})
310 self.object:set_velocity({x=0, y=0, z=0})
311 self.object:set_acceleration({x=0, y=0, z=0})
314 on_step = function(self, dtime)
315 --if item set to be collected then only execute go to player
316 if self.collected == true then
317 if not self.collector then
318 self.collected = false
321 local collector = minetest.get_player_by_name(self.collector)
322 if collector and collector:get_hp() > 0 then
323 self.object:setacceleration(vector.new(0,0,0))
324 self.disable_physics(self)
326 local pos = self.object:getpos()
327 local pos2 = collector:getpos()
329 local player_velocity = collector:get_player_velocity()
331 pos2.y = pos2.y + self.collection_height
333 local direction = vector.direction(pos,pos2)
334 local distance = vector.distance(pos2,pos)
335 local multiplier = distance
336 if multiplier < 1 then
339 local goal = vector.multiply(direction,multiplier)
340 local currentvel = self.object:get_velocity()
343 local multiplier = (self.radius*5) - distance
344 local velocity = vector.multiply(direction,multiplier)
345 local goal = velocity--vector.add(player_velocity,velocity)
346 acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
348 acceleration = vector.new(goal.x,goal.y,goal.z)
350 --acceleration = vector.multiply(acceleration, )
354 self.object:add_velocity(acceleration)
359 local meta = collector:get_meta()
360 local experience_collection_buffer = meta:get_float("experience_collection_buffer")
361 if distance < 0.2 and experience_collection_buffer == 0 then
362 meta:set_float("experience_collection_buffer",0.04)
363 add_experience(collector,2)
368 --self.delete_timer = self.delete_timer + dtime
369 --this is where the item gets removed from world
370 --if self.delete_timer > 1 then
371 -- self.object:remove()
375 print(self.collector.." does not exist")
380 --allow entity to be collected after timer
381 if self.collectable == false and self.collection_timer >= self.collection_timer_goal then
382 self.collectable = true
383 elseif self.collectable == false then
384 self.collection_timer = self.collection_timer + dtime
387 self.age = self.age + dtime
388 if self.time_to_live > 0 and self.age > self.time_to_live then
393 local pos = self.object:get_pos()
394 local node = minetest.get_node_or_nil({
396 y = pos.y + self.object:get_properties().collisionbox[2] - 0.05,
401 -- Remove nodes in 'ignore'
402 if node and node.name == "ignore" then
407 local is_stuck = false
408 local snode = minetest.get_node_or_nil(pos)
410 local sdef = minetest.registered_nodes[snode.name] or {}
411 is_stuck = (sdef.walkable == nil or sdef.walkable == true)
412 and (sdef.collision_box == nil or sdef.collision_box.type == "regular")
413 and (sdef.node_box == nil or sdef.node_box.type == "regular")
416 -- Push item out when stuck inside solid node
420 {x=1, y=0, z=0}, {x=-1, y=0, z= 0},
421 {x=0, y=0, z=1}, {x= 0, y=0, z=-1},
424 -- Check which one of the 4 sides is free
426 local cnode = minetest.get_node(vector.add(pos, order[o])).name
427 local cdef = minetest.registered_nodes[cnode] or {}
428 if cnode ~= "ignore" and cdef.walkable == false then
433 -- If none of the 4 sides is free, check upwards
435 shootdir = {x=0, y=1, z=0}
436 local cnode = minetest.get_node(vector.add(pos, shootdir)).name
437 if cnode == "ignore" then
438 shootdir = nil -- Do not push into ignore
443 -- Set new item moving speed accordingly
444 local newv = vector.multiply(shootdir, 3)
445 self:disable_physics()
446 self.object:set_velocity(newv)
448 self.force_out = newv
449 self.force_out_start = vector.round(pos)
452 elseif self.force_out then
453 -- This code runs after the entity got a push from the above code.
454 -- It makes sure the entity is entirely outside the solid node
455 local c = self.object:get_properties().collisionbox
456 local s = self.force_out_start
457 local f = self.force_out
458 local ok = (f.x > 0 and pos.x + c[1] > s.x + 0.5) or
459 (f.y > 0 and pos.y + c[2] > s.y + 0.5) or
460 (f.z > 0 and pos.z + c[3] > s.z + 0.5) or
461 (f.x < 0 and pos.x + c[4] < s.x - 0.5) or
462 (f.z < 0 and pos.z + c[6] < s.z - 0.5)
464 -- Item was successfully forced out
466 self:enable_physics()
470 if not self.physical_state then
471 return -- Don't do anything
474 -- Slide on slippery nodes
475 local vel = self.object:get_velocity()
476 local def = node and minetest.registered_nodes[node.name]
477 local is_moving = (def and not def.walkable) or
478 vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
479 local is_slippery = false
481 if def and def.walkable then
482 local slippery = minetest.get_item_group(node.name, "slippery")
483 is_slippery = slippery ~= 0
484 if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then
485 -- Horizontal deceleration
486 local slip_factor = 4.0 / (slippery + 4)
487 self.object:set_acceleration({
488 x = -vel.x * slip_factor,
490 z = -vel.z * slip_factor
492 elseif vel.y == 0 then
497 if self.moving_state == is_moving and self.slippery_state == is_slippery then
498 -- Do not update anything until the moving state changes
502 self.moving_state = is_moving
503 self.slippery_state = is_slippery
506 self.object:set_acceleration({x = 0, y = -gravity, z = 0})
508 self.object:set_acceleration({x = 0, y = 0, z = 0})
509 self.object:set_velocity({x = 0, y = 0, z = 0})