1 local minetest,math,vector,os,pairs = minetest,math,vector,os,pairs
2 local mod_storage = minetest.get_mod_storage()
5 -- loads data from mod storage
8 local load_data = function(player)
9 name = player:get_player_name()
11 temp_pool = pool[name]
12 if mod_storage:get_int(name.."xp_save") > 0 then
13 temp_pool.xp_level = mod_storage:get_int(name.."xp_level")
14 temp_pool.xp_bar = mod_storage:get_int(name.."xp_bar" )
16 temp_pool.last_time= minetest.get_us_time()/1000000
18 temp_pool.xp_level = 0
21 temp_pool.last_time= minetest.get_us_time()/1000000
25 -- saves data to be utilized on next login
28 local save_data = function(name)
29 if type(name) ~= "string" and name:is_player() then
30 name = name:get_player_name()
32 temp_pool = pool[name]
34 mod_storage:set_int(name.."xp_level",temp_pool.xp_level)
35 mod_storage:set_int(name.."xp_bar", temp_pool.xp_bar )
37 mod_storage:set_int(name.."xp_save",1)
42 -- saves specific users data for when they relog
43 minetest.register_on_leaveplayer(function(player)
47 -- is used for shutdowns to save all data
48 local save_all = function()
49 for name,_ in pairs(pool) do
54 -- save all data to mod storage on shutdown
55 minetest.register_on_shutdown(function()
61 function get_player_xp_level(player)
62 name = player:get_player_name()
63 return(pool[name].xp_level)
68 function set_player_xp_level(player,level)
69 name = player:get_player_name()
70 pool[name].xp_level = level
71 hud_manager.change_hud({
73 hud_name = "xp_level_fg",
75 data = tostring(level)
77 hud_manager.change_hud({
79 hud_name = "xp_level_bg",
81 data = tostring(level)
85 minetest.hud_replace_builtin("health",{
86 hud_elem_type = "statbar",
87 position = {x = 0.5, y = 1},
89 number = core.PLAYER_MAX_HP_DEFAULT,
91 size = {x = 24, y = 24},
92 offset = {x = (-10 * 24) - 25, y = -(48 + 24 + 38)},
97 minetest.register_on_joinplayer(function(player)
101 name = player:get_player_name()
102 temp_pool = pool[name]
104 hud_manager.add_hud(player,"heart_bar_bg",{
105 hud_elem_type = "statbar",
106 position = {x = 0.5, y = 1},
107 text = "heart_bg.png",
108 number = core.PLAYER_MAX_HP_DEFAULT,
110 size = {x = 24, y = 24},
111 offset = {x = (-10 * 24) - 25, y = -(48 + 24 + 38)},
115 hud_manager.add_hud(player,"experience_bar_background",{
116 hud_elem_type = "statbar",
117 position = {x=0.5, y=1},
118 name = "experience bar background",
119 text = "experience_bar_background.png",
122 offset = {x = (-8 * 28) - 29, y = -(48 + 24 + 16)},
123 size = { x=28, y=28 },
127 hud_manager.add_hud(player,"experience_bar",{
128 hud_elem_type = "statbar",
129 position = {x=0.5, y=1},
130 name = "experience bar",
131 text = "experience_bar.png",
132 number = temp_pool.xp_bar,
134 offset = {x = (-8 * 28) - 29, y = -(48 + 24 + 16)},
135 size = { x=28, y=28 },
139 hud_manager.add_hud(player,"xp_level_bg",{
140 hud_elem_type = "text",
141 position = {x=0.5, y=1},
142 name = "xp_level_bg",
143 text = tostring(temp_pool.xp_level),
145 offset = {x = 0, y = -(48 + 24 + 24)},
148 hud_manager.add_hud(player,"xp_level_fg",{
149 hud_elem_type = "text",
150 position = {x=0.5, y=1},
151 name = "xp_level_fg",
152 text = tostring(temp_pool.xp_level),
154 offset = {x = -1, y = -(48 + 24 + 25)},
162 local function level_up_experience(player)
163 name = player:get_player_name()
164 temp_pool = pool[name]
166 temp_pool.xp_level = temp_pool.xp_level + 1
168 hud_manager.change_hud({
170 hud_name = "xp_level_fg",
172 data = tostring(temp_pool.xp_level)
174 hud_manager.change_hud({
176 hud_name = "xp_level_bg",
178 data = tostring(temp_pool.xp_level)
185 local function add_experience(player,experience)
186 name = player:get_player_name()
187 temp_pool = pool[name]
189 temp_pool.xp_bar = temp_pool.xp_bar + experience
191 if temp_pool.xp_bar > 36 then
192 if minetest.get_us_time()/1000000 - temp_pool.last_time > 0.04 then
193 minetest.sound_play("level_up",{gain=0.2,to_player = name})
194 temp_pool.last_time = minetest.get_us_time()/1000000
196 temp_pool.xp_bar = temp_pool.xp_bar - 36
197 level_up_experience(player)
199 if minetest.get_us_time()/1000000 - temp_pool.last_time > 0.01 then
200 temp_pool.last_time = minetest.get_us_time()/1000000
201 minetest.sound_play("experience",{gain=0.1,to_player = name,pitch=math.random(75,99)/100})
204 hud_manager.change_hud({
206 hud_name = "experience_bar",
208 data = temp_pool.xp_bar
216 minetest.register_on_dieplayer(function(player)
217 name = player:get_player_name()
218 temp_pool = pool[name]
219 xp_amount = temp_pool.xp_level
222 temp_pool.xp_level = 0
225 hud_manager.change_hud({
227 hud_name = "xp_level_fg",
229 data = tostring(temp_pool.xp_level)
231 hud_manager.change_hud({
233 hud_name = "xp_level_bg",
235 data = tostring(temp_pool.xp_level)
238 hud_manager.change_hud({
240 hud_name = "experience_bar",
242 data = temp_pool.xp_bar
245 minetest.throw_experience(player:get_pos(), xp_amount)
256 local player_velocity
271 minetest.register_entity("experience:orb", {
272 initial_properties = {
275 collide_with_objects = false,
276 collisionbox = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2},
278 visual_size = {x = 0.4, y = 0.4},
279 textures = {name="experience_orb.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}},
280 spritediv = {x = 1, y = 14},
281 initial_sprite_basepos = {x = 0, y = 0},
286 slippery_state = false,
287 physical_state = true,
290 -- Pushing item out of solid nodes
292 force_out_start = nil,
293 --Collection Variables
300 get_staticdata = function(self)
301 return minetest.serialize({
303 collectable = self.collectable,
304 try_timer = self.try_timer,
305 collected = self.collected,
306 delete_timer = self.delete_timer,
307 collector = self.collector,
311 on_activate = function(self, staticdata, dtime_s)
312 if string.sub(staticdata, 1, string.len("return")) == "return" then
313 data = minetest.deserialize(staticdata)
314 if data and type(data) == "table" then
315 self.age = (data.age or 0) + dtime_s
316 self.collectable = data.collectable
317 self.try_timer = data.try_timer
318 self.collected = data.collected
319 self.delete_timer = data.delete_timer
320 self.collector = data.collector
323 self.object:set_velocity(vector.new(
324 math.random(-2,2)*math.random(),
326 math.random(-2,2)*math.random()
329 self.object:set_armor_groups({immortal = 1})
330 self.object:set_velocity({x = 0, y = 2, z = 0})
331 self.object:set_acceleration({x = 0, y = -9.81, z = 0})
332 size = math.random(20,36)/100
333 self.object:set_properties({
334 visual_size = {x = size, y = size},
337 self.object:set_sprite({x=1,y=math.random(1,14)}, 14, 0.05, false)
340 enable_physics = function(self)
341 if not self.physical_state then
342 self.physical_state = true
343 self.object:set_properties({physical = true})
344 self.object:set_velocity({x=0, y=0, z=0})
345 self.object:set_acceleration({x=0, y=-9.81, z=0})
349 disable_physics = function(self)
350 if self.physical_state then
351 self.physical_state = false
352 self.object:set_properties({physical = false})
353 self.object:set_velocity({x=0, y=0, z=0})
354 self.object:set_acceleration({x=0, y=0, z=0})
357 on_step = function(self, dtime)
358 --if item set to be collected then only execute go to player
359 if self.collected == true then
360 if not self.collector then
361 self.collected = false
364 collector = minetest.get_player_by_name(self.collector)
365 if collector and collector:get_hp() > 0 and vector.distance(self.object:get_pos(),collector:get_pos()) < 5 then
366 temp_pool = pool[self.collector]
368 self.object:set_acceleration(vector.new(0,0,0))
369 self.disable_physics(self)
371 pos = self.object:get_pos()
372 pos2 = collector:get_pos()
374 player_velocity = collector:get_player_velocity()
376 pos2.y = pos2.y + 0.8
378 direction = vector.direction(pos,pos2)
379 distance = vector.distance(pos2,pos)
380 multiplier = distance
381 if multiplier < 1 then
384 goal = vector.multiply(direction,multiplier)
385 currentvel = self.object:get_velocity()
388 multiplier = 20 - distance
389 velocity = vector.multiply(direction,multiplier)
391 acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
392 self.object:add_velocity(vector.add(acceleration,player_velocity))
393 elseif distance > 0.9 and temp_pool.buffer > 0 then
394 temp_pool.buffer = temp_pool.buffer - dtime
395 multiplier = 20 - distance
396 velocity = vector.multiply(direction,multiplier)
397 goal = vector.multiply(minetest.yaw_to_dir(minetest.dir_to_yaw(vector.direction(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z)))+math.pi/2),10)
398 goal = vector.add(player_velocity,goal)
399 acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
400 self.object:add_velocity(acceleration)
402 if distance < 0.4 and temp_pool.buffer <= 0 then
403 temp_pool.buffer = 0.04
404 add_experience(collector,2)
410 self.enable_physics(self)
415 self.age = self.age + dtime
416 if self.age > 300 then
421 pos = self.object:get_pos()
424 node = minetest.get_node_or_nil({
433 -- Remove nodes in 'ignore'
434 if node and node.name == "ignore" then
439 if not self.physical_state then
440 return -- Don't do anything
443 -- Slide on slippery nodes
444 vel = self.object:get_velocity()
445 def = node and minetest.registered_nodes[node.name]
446 is_moving = (def and not def.walkable) or
447 vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
450 if def and def.walkable then
451 slippery = minetest.get_item_group(node.name, "slippery")
452 is_slippery = slippery ~= 0
453 if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then
454 -- Horizontal deceleration
455 slip_factor = 4.0 / (slippery + 4)
456 self.object:set_acceleration({
457 x = -vel.x * slip_factor,
459 z = -vel.z * slip_factor
461 elseif vel.y == 0 then
466 if self.moving_state == is_moving and self.slippery_state == is_slippery then
467 -- Do not update anything until the moving state changes
471 self.moving_state = is_moving
472 self.slippery_state = is_slippery
475 self.object:set_acceleration({x = 0, y = -9.81, z = 0})
477 self.object:set_acceleration({x = 0, y = 0, z = 0})
478 self.object:set_velocity({x = 0, y = 0, z = 0})
484 minetest.register_chatcommand("xp", {
486 description = "Spawn x amount of a mob, used as /spawn 'mob' 10 or /spawn 'mob' for one",
487 privs = {server=true},
488 func = function(name)
489 local player = minetest.get_player_by_name(name)
490 local pos = player:get_pos()
492 minetest.throw_experience(pos, 1000)