]> git.lizzy.rs Git - Crafter.git/blob - mods/experience/init.lua
Stop xp from reloading
[Crafter.git] / mods / experience / init.lua
1 local
2 minetest,math,vector,os,pairs,type
3 =
4 minetest,math,vector,os,pairs,type
5
6 local mod_storage = minetest.get_mod_storage()
7
8 -- minetest library
9 local get_node_or_nil    = minetest.get_node_or_nil
10 local get_time           = minetest.get_us_time
11 local get_player_by_name = minetest.get_player_by_name
12 local yaw_to_dir         = minetest.yaw_to_dir
13 local dir_to_yaw         = minetest.dir_to_yaw
14 local get_item_group     = minetest.get_item_group
15 local serialize          = minetest.serialize
16 local deserialize        = minetest.deserialize
17 local play_sound         = minetest.sound_play
18 local registered_nodes
19 minetest.register_on_mods_loaded(function()
20         registered_nodes = minetest.registered_nodes
21 end)
22
23 -- vector library
24 local new_vec       = vector.new
25 local vec_distance  = vector.distance
26 local add_vec       = vector.add
27 local multiply_vec  = vector.multiply
28 local vec_direction = vector.direction
29
30 -- math library
31 local pi     = math.pi
32 local random = math.random
33 local abs    = math.abs
34
35 -- string library
36 local s_sub  = string.sub
37 local s_len  = string.len
38
39 local pool = {}
40 -- loads data from mod storage
41 local name
42 local temp_pool
43 local load_data = function(player)
44         name = player:get_player_name()
45         pool[name] = {}
46         temp_pool = pool[name]
47         if mod_storage:get_int(name.."xp_save") > 0 then
48                 temp_pool.xp_level = mod_storage:get_int(name.."xp_level")
49                 temp_pool.xp_bar   = mod_storage:get_int(name.."xp_bar"  )
50                 temp_pool.buffer   = 0
51                 temp_pool.last_time= get_time()/1000000
52         else
53                 temp_pool.xp_level = 0
54                 temp_pool.xp_bar   = 0
55                 temp_pool.buffer   = 0
56                 temp_pool.last_time= get_time()/1000000
57         end
58 end
59
60 -- saves data to be utilized on next login
61 local name
62 local temp_pool
63 local save_data = function(name)
64         if type(name) ~= "string" and name:is_player() then
65                 name = name:get_player_name()
66         end
67         temp_pool = pool[name]
68         
69         mod_storage:set_int(name.."xp_level",temp_pool.xp_level)
70         mod_storage:set_int(name.."xp_bar",  temp_pool.xp_bar  )
71
72         mod_storage:set_int(name.."xp_save",1)
73
74         pool[name] = nil
75 end
76
77 -- saves specific users data for when they relog
78 minetest.register_on_leaveplayer(function(player)
79         save_data(player)
80 end)
81
82 -- is used for shutdowns to save all data
83 local save_all = function()
84         for name,_ in pairs(pool) do
85                 save_data(name)
86         end
87 end
88
89 -- save all data to mod storage on shutdown
90 minetest.register_on_shutdown(function()
91         save_all()
92 end)
93
94
95 local name
96 function get_player_xp_level(player)
97         name = player:get_player_name()
98         return(pool[name].xp_level)
99 end
100
101 local name
102 local temp_pool
103 function set_player_xp_level(player,level)
104         name = player:get_player_name()
105         pool[name].xp_level = level
106         hud_manager.change_hud({
107                 player   = player,
108                 hud_name = "xp_level_fg",
109                 element  = "text",
110                 data     = tostring(level)
111         })
112         hud_manager.change_hud({
113                 player   = player,
114                 hud_name = "xp_level_bg",
115                 element  = "text",
116                 data     = tostring(level)
117         })
118 end
119
120 minetest.hud_replace_builtin("health",{
121     hud_elem_type = "statbar",
122     position = {x = 0.5, y = 1},
123     text = "heart.png",
124     number = core.PLAYER_MAX_HP_DEFAULT,
125     direction = 0,
126     size = {x = 24, y = 24},
127     offset = {x = (-10 * 24) - 25, y = -(48 + 24 + 38)},
128 })
129
130 local name
131 local temp_pool
132 minetest.register_on_joinplayer(function(player)
133
134         load_data(player)
135
136         name = player:get_player_name()
137         temp_pool = pool[name]
138                 
139     hud_manager.add_hud(player,"heart_bar_bg",{
140         hud_elem_type = "statbar",
141         position = {x = 0.5, y = 1},
142         text = "heart_bg.png",
143         number = core.PLAYER_MAX_HP_DEFAULT,
144         direction = 0,
145         size = {x = 24, y = 24},
146         offset = {x = (-10 * 24) - 25, y = -(48 + 24 + 38)},
147         })
148         
149
150     hud_manager.add_hud(player,"experience_bar_background",{
151         hud_elem_type = "statbar",
152         position = {x=0.5, y=1},
153         name = "experience bar background",
154         text = "experience_bar_background.png",
155         number = 36,
156         direction = 0,
157         offset = {x = (-8 * 28) - 29, y = -(48 + 24 + 16)},
158         size = { x=28, y=28 },
159         z_index = 0,
160         })
161         
162     hud_manager.add_hud(player,"experience_bar",{
163         hud_elem_type = "statbar",
164         position = {x=0.5, y=1},
165         name = "experience bar",
166         text = "experience_bar.png",
167         number = temp_pool.xp_bar,
168         direction = 0,
169         offset = {x = (-8 * 28) - 29, y = -(48 + 24 + 16)},
170         size = { x=28, y=28 },
171         z_index = 0,
172     })
173         
174     hud_manager.add_hud(player,"xp_level_bg",{
175         hud_elem_type = "text",
176         position = {x=0.5, y=1},
177         name = "xp_level_bg",
178         text = tostring(temp_pool.xp_level),
179         number = 0x000000,
180         offset = {x = 0, y = -(48 + 24 + 24)},
181         z_index = 0,
182     })                            
183     hud_manager.add_hud(player,"xp_level_fg",{
184         hud_elem_type = "text",
185         position = {x=0.5, y=1},
186         name = "xp_level_fg",
187         text = tostring(temp_pool.xp_level),
188         number = 0xFFFFFF,
189         offset = {x = -1, y = -(48 + 24 + 25)},
190         z_index = 0,
191         })                                                           
192 end)
193
194
195 local name
196 local temp_pool
197 local function level_up_experience(player)
198         name = player:get_player_name()
199         temp_pool = pool[name]
200         
201     temp_pool.xp_level = temp_pool.xp_level + 1
202         
203         hud_manager.change_hud({
204                 player   = player,
205                 hud_name = "xp_level_fg",
206                 element  = "text",
207                 data     = tostring(temp_pool.xp_level)
208         })
209         hud_manager.change_hud({
210                 player   = player,
211                 hud_name = "xp_level_bg",
212                 element  = "text",
213                 data     = tostring(temp_pool.xp_level)
214         })
215 end
216
217
218 local name
219 local temp_pool
220 local function add_experience(player,experience)
221         name = player:get_player_name()
222         temp_pool = pool[name]
223         
224         temp_pool.xp_bar = temp_pool.xp_bar + experience
225         
226         if temp_pool.xp_bar > 36 then
227                 if get_time()/1000000 - temp_pool.last_time > 0.04 then
228                         play_sound("level_up",{gain=0.2,to_player = name})
229                         temp_pool.last_time = get_time()/1000000
230                 end
231         temp_pool.xp_bar = temp_pool.xp_bar - 36
232                 level_up_experience(player)
233         else
234                 if get_time()/1000000 - temp_pool.last_time > 0.01 then
235                         temp_pool.last_time = get_time()/1000000
236                         play_sound("experience",{gain=0.1,to_player = name,pitch=random(75,99)/100})
237                 end
238         end
239         hud_manager.change_hud({
240                 player   = player,
241                 hud_name = "experience_bar",
242                 element  = "number",
243                 data     = temp_pool.xp_bar
244         })
245 end
246
247 --reset player level
248 local name
249 local temp_pool
250 local xp_amount
251 minetest.register_on_dieplayer(function(player)
252         name = player:get_player_name()
253         temp_pool = pool[name]
254         xp_amount = temp_pool.xp_level
255         
256         temp_pool.xp_bar   = 0
257         temp_pool.xp_level = 0
258
259
260         hud_manager.change_hud({
261                 player   = player,
262                 hud_name = "xp_level_fg",
263                 element  = "text",
264                 data     = tostring(temp_pool.xp_level)
265         })
266         hud_manager.change_hud({
267                 player   = player,
268                 hud_name = "xp_level_bg",
269                 element  = "text",
270                 data     = tostring(temp_pool.xp_level)
271         })
272
273         hud_manager.change_hud({
274                 player   = player,
275                 hud_name = "experience_bar",
276                 element  = "number",
277                 data     = temp_pool.xp_bar
278         })
279
280     minetest.throw_experience(player:get_pos(), xp_amount)                       
281 end)
282
283
284 local name
285 local temp_pool
286 local collector
287 local pos
288 local pos2
289 local direction
290 local distance
291 local player_velocity
292 local goal
293 local currentvel
294 local acceleration
295 local multiplier
296 local velocity
297 local node
298 local vel
299 local def
300 local is_moving
301 local is_slippery
302 local slippery
303 local slip_factor
304 local size
305 local data
306 local function xp_step(self, dtime)
307         --if item set to be collected then only execute go to player
308         if self.collected == true then
309                 if not self.collector then
310                         self.collected = false
311                         return
312                 end
313                 collector = get_player_by_name(self.collector)
314                 if collector and collector:get_hp() > 0 and vec_distance(self.object:get_pos(),collector:get_pos()) < 5 then
315                         temp_pool = pool[self.collector]
316
317                         self.object:set_acceleration(new_vec(0,0,0))
318                         self.disable_physics(self)
319                         --get the variables
320                         pos = self.object:get_pos()
321                         pos2 = collector:get_pos()
322                         
323                         player_velocity = collector:get_player_velocity()
324                                                                                 
325                         pos2.y = pos2.y + 0.8
326                                                         
327                         direction = vec_direction(pos,pos2)
328                         distance = vec_distance(pos2,pos)
329                         multiplier = distance
330                         if multiplier < 1 then
331                                 multiplier = 1
332                         end
333                         goal = multiply_vec(direction,multiplier)
334                         currentvel = self.object:get_velocity()
335
336                         if distance > 1 then
337                                 multiplier = 20 - distance
338                                 velocity = multiply_vec(direction,multiplier)
339                                 goal = velocity
340                                 acceleration = new_vec(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
341                                 self.object:add_velocity(add_vec(acceleration,player_velocity))
342                         elseif distance > 0.9 and temp_pool.buffer > 0 then
343                                 temp_pool.buffer = temp_pool.buffer - dtime
344                                 multiplier = 20 - distance
345                                 velocity = multiply_vec(direction,multiplier)
346                                 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)
347                                 goal = add_vec(player_velocity,goal)
348                                 acceleration = new_vec(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
349                                 self.object:add_velocity(acceleration)
350                         end
351                         if distance < 0.4 and temp_pool.buffer <= 0 then
352                                 temp_pool.buffer = 0.04
353                                 add_experience(collector,2)
354                                 self.object:remove()
355                         end
356                         return
357                 else
358                         self.collector = nil
359                         self.enable_physics(self)
360                 end
361         end
362
363                                         
364         self.age = self.age + dtime
365         if self.age > 300 then
366                 self.object:remove()
367                 return
368         end
369
370         pos = self.object:get_pos()
371
372         if pos then
373                 node = get_node_or_nil({
374                         x = pos.x,
375                         y = pos.y -0.25,
376                         z = pos.z
377                 })
378         else
379                 return
380         end
381
382         -- Remove nodes in 'ignore'
383         if node and node.name == "ignore" then
384                 self.object:remove()
385                 return
386         end
387
388         if not self.physical_state then
389                 return -- Don't do anything
390         end
391
392         -- Slide on slippery nodes
393         vel = self.object:get_velocity()
394         def = node and registered_nodes[node.name]
395         is_moving = (def and not def.walkable) or
396                 vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
397         is_slippery = false
398
399         if def and def.walkable then
400                 slippery = get_item_group(node.name, "slippery")
401                 is_slippery = slippery ~= 0
402                 if is_slippery and (abs(vel.x) > 0.2 or abs(vel.z) > 0.2) then
403                         -- Horizontal deceleration
404                         slip_factor = 4.0 / (slippery + 4)
405                         self.object:set_acceleration({
406                                 x = -vel.x * slip_factor,
407                                 y = 0,
408                                 z = -vel.z * slip_factor
409                         })
410                 elseif vel.y == 0 then
411                         is_moving = false
412                 end
413         end
414
415         if self.moving_state == is_moving and self.slippery_state == is_slippery then
416                 -- Do not update anything until the moving state changes
417                 return
418         end
419
420         self.moving_state = is_moving
421         self.slippery_state = is_slippery
422
423         if is_moving then
424                 self.object:set_acceleration({x = 0, y = -9.81, z = 0})
425         else
426                 self.object:set_acceleration({x = 0, y = 0, z = 0})
427                 self.object:set_velocity({x = 0, y = 0, z = 0})
428         end
429 end
430
431 minetest.register_entity("experience:orb", {
432         initial_properties = {
433                 hp_max = 1,
434                 physical = true,
435                 collide_with_objects = false,
436                 collisionbox = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2},
437                 visual = "sprite",
438                 visual_size = {x = 0.4, y = 0.4},
439                 textures = {name="experience_orb.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}},
440                 spritediv = {x = 1, y = 14},
441                 initial_sprite_basepos = {x = 0, y = 0},
442                 is_visible = true,
443                 pointable = false,
444                 static_save = false,
445         },
446         moving_state = true,
447         slippery_state = false,
448         physical_state = true,
449         -- Item expiry
450         age = 0,
451         -- Pushing item out of solid nodes
452         force_out = nil,
453         force_out_start = nil,
454         --Collection Variables
455         collectable = false,
456         try_timer = 0,
457         collected = false,
458         delete_timer = 0,
459         radius = 4,
460
461
462         on_activate = function(self, staticdata, dtime_s)
463                 self.object:set_velocity(new_vec(
464                         random(-2,2)*random(),
465                         random(2,5),
466                         random(-2,2)*random()
467                 ))
468                 self.object:set_armor_groups({immortal = 1})
469                 self.object:set_velocity({x = 0, y = 2, z = 0})
470                 self.object:set_acceleration({x = 0, y = -9.81, z = 0})
471         size = random(20,36)/100
472         self.object:set_properties({
473                         visual_size = {x = size, y = size},
474                         glow = 14,
475                 })
476                 self.object:set_sprite({x=1,y=random(1,14)}, 14, 0.05, false)
477         end,
478
479         enable_physics = function(self)
480                 if not self.physical_state then
481                         self.physical_state = true
482                         self.object:set_properties({physical = true})
483                         self.object:set_velocity({x=0, y=0, z=0})
484                         self.object:set_acceleration({x=0, y=-9.81, z=0})
485                 end
486         end,
487
488         disable_physics = function(self)
489                 if self.physical_state then
490                         self.physical_state = false
491                         self.object:set_properties({physical = false})
492                         self.object:set_velocity({x=0, y=0, z=0})
493                         self.object:set_acceleration({x=0, y=0, z=0})
494                 end
495         end,
496         on_step = function(self, dtime)
497                 xp_step(self, dtime)
498         end,
499 })
500
501
502 minetest.register_chatcommand("xp", {
503         params = "nil",
504         description = "Spawn x amount of a mob, used as /spawn 'mob' 10 or /spawn 'mob' for one",
505         privs = {server=true},
506         func = function(name)
507                 local player = get_player_by_name(name)
508                 local pos = player:get_pos()
509                 pos.y = pos.y + 1.2
510                 minetest.throw_experience(pos, 1000)
511         end,
512 })