]> git.lizzy.rs Git - Crafter.git/blob - mods/experience/init.lua
Make enchanting work again
[Crafter.git] / mods / experience / init.lua
1 local minetest,math,vector,os,pairs = minetest,math,vector,os,pairs
2 local mod_storage = minetest.get_mod_storage()
3 local pool = {}
4
5 -- loads data from mod storage
6 local name
7 local temp_pool
8 local load_data = function(player)
9         name = player:get_player_name()
10         pool[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"  )
15                 temp_pool.buffer   = 0
16                 temp_pool.last_time= os.clock()
17         else
18                 temp_pool.xp_level = 0
19                 temp_pool.xp_bar   = 0
20                 temp_pool.buffer   = 0
21                 temp_pool.last_time= os.clock()
22         end
23 end
24
25 -- saves data to be utilized on next login
26 local name
27 local temp_pool
28 local save_data = function(name)
29         if type(name) ~= "string" and name:is_player() then
30                 name = name:get_player_name()
31         end
32         temp_pool = pool[name]
33         
34         mod_storage:set_int(name.."xp_level",temp_pool.xp_level)
35         mod_storage:set_int(name.."xp_bar",  temp_pool.xp_bar  )
36
37         mod_storage:set_int(name.."xp_save",1)
38
39         pool[name] = nil
40 end
41
42 -- saves specific users data for when they relog
43 minetest.register_on_leaveplayer(function(player)
44         save_data(player)
45 end)
46
47 -- is used for shutdowns to save all data
48 local save_all = function()
49         for name,_ in pairs(pool) do
50                 save_data(name)
51         end
52 end
53
54 -- save all data to mod storage on shutdown
55 minetest.register_on_shutdown(function()
56         save_all()
57 end)
58
59
60 local name
61 function get_player_xp_level(player)
62         name = player:get_player_name()
63         return(pool[name].xp_level)
64 end
65
66 local name
67 local temp_pool
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({
72                 player   = player,
73                 hud_name = "xp_level_fg",
74                 element  = "text",
75                 data     = tostring(level)
76         })
77         hud_manager.change_hud({
78                 player   = player,
79                 hud_name = "xp_level_bg",
80                 element  = "text",
81                 data     = tostring(level)
82         })
83 end
84
85 minetest.hud_replace_builtin("health",{
86     hud_elem_type = "statbar",
87     position = {x = 0.5, y = 1},
88     text = "heart.png",
89     number = core.PLAYER_MAX_HP_DEFAULT,
90     direction = 0,
91     size = {x = 24, y = 24},
92     offset = {x = (-10 * 24) - 25, y = -(48 + 24 + 38)},
93 })
94
95 local name
96 local temp_pool
97 minetest.register_on_joinplayer(function(player)
98
99         load_data(player)
100
101         name = player:get_player_name()
102         temp_pool = pool[name]
103                 
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,
109         direction = 0,
110         size = {x = 24, y = 24},
111         offset = {x = (-10 * 24) - 25, y = -(48 + 24 + 38)},
112         })
113         
114
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",
120         number = 36,
121         direction = 0,
122         offset = {x = (-8 * 28) - 29, y = -(48 + 24 + 16)},
123         size = { x=28, y=28 },
124         z_index = 0,
125         })
126         
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,
133         direction = 0,
134         offset = {x = (-8 * 28) - 29, y = -(48 + 24 + 16)},
135         size = { x=28, y=28 },
136         z_index = 0,
137     })
138         
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),
144         number = 0x000000,
145         offset = {x = 0, y = -(48 + 24 + 24)},
146         z_index = 0,
147     })                            
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),
153         number = 0xFFFFFF,
154         offset = {x = -1, y = -(48 + 24 + 25)},
155         z_index = 0,
156         })                                                           
157 end)
158
159
160 local name
161 local temp_pool
162 local function level_up_experience(player)
163         name = player:get_player_name()
164         temp_pool = pool[name]
165         
166     temp_pool.xp_level = temp_pool.xp_level + 1
167         
168         hud_manager.change_hud({
169                 player   = player,
170                 hud_name = "xp_level_fg",
171                 element  = "text",
172                 data     = tostring(temp_pool.xp_level)
173         })
174         hud_manager.change_hud({
175                 player   = player,
176                 hud_name = "xp_level_bg",
177                 element  = "text",
178                 data     = tostring(temp_pool.xp_level)
179         })
180 end
181
182
183 local name
184 local temp_pool
185 local function add_experience(player,experience)
186         name = player:get_player_name()
187         temp_pool = pool[name]
188         
189         temp_pool.xp_bar = temp_pool.xp_bar + experience
190         
191         if temp_pool.xp_bar > 36 then
192                 if os.clock() - temp_pool.last_time > 0.04 then
193                         minetest.sound_play("level_up",{gain=0.2,to_player = name})
194                         temp_pool.last_time = os.clock()
195                 end
196         temp_pool.xp_bar = temp_pool.xp_bar - 36
197                 level_up_experience(player)
198         else
199                 if os.clock() - temp_pool.last_time > 0.01 then
200                         temp_pool.last_time = os.clock()
201                         minetest.sound_play("experience",{gain=0.1,to_player = name,pitch=math.random(75,99)/100})
202                 end
203         end
204         hud_manager.change_hud({
205                 player   = player,
206                 hud_name = "experience_bar",
207                 element  = "number",
208                 data     = temp_pool.xp_bar
209         })
210 end
211
212 --reset player level
213 local name
214 local temp_pool
215 local xp_amount
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
220         
221         temp_pool.xp_bar   = 0
222         temp_pool.xp_level = 0
223
224
225         hud_manager.change_hud({
226                 player   = player,
227                 hud_name = "xp_level_fg",
228                 element  = "text",
229                 data     = tostring(temp_pool.xp_level)
230         })
231         hud_manager.change_hud({
232                 player   = player,
233                 hud_name = "xp_level_bg",
234                 element  = "text",
235                 data     = tostring(temp_pool.xp_level)
236         })
237
238         hud_manager.change_hud({
239                 player   = player,
240                 hud_name = "experience_bar",
241                 element  = "number",
242                 data     = temp_pool.xp_bar
243         })
244
245     minetest.throw_experience(player:get_pos(), xp_amount)                       
246 end)
247
248
249 local name
250 local temp_pool
251 local collector
252 local pos
253 local pos2
254 local direction
255 local distance
256 local player_velocity
257 local goal
258 local currentvel
259 local acceleration
260 local multiplier
261 local velocity
262 local node
263 local vel
264 local def
265 local is_moving
266 local is_slippery
267 local slippery
268 local slip_factor
269 local size
270 local data
271 minetest.register_entity("experience:orb", {
272         initial_properties = {
273                 hp_max = 1,
274                 physical = true,
275                 collide_with_objects = false,
276                 collisionbox = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2},
277                 visual = "sprite",
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},
282                 is_visible = true,
283                 pointable = false,
284         },
285         moving_state = true,
286         slippery_state = false,
287         physical_state = true,
288         -- Item expiry
289         age = 0,
290         -- Pushing item out of solid nodes
291         force_out = nil,
292         force_out_start = nil,
293         --Collection Variables
294         collectable = false,
295         try_timer = 0,
296         collected = false,
297         delete_timer = 0,
298         radius = 4,
299
300         get_staticdata = function(self)
301                 return minetest.serialize({
302                         age = self.age,
303                         collectable = self.collectable,
304                         try_timer = self.try_timer,
305                         collected = self.collected,
306                         delete_timer = self.delete_timer,
307                         collector = self.collector,
308                 })
309         end,
310
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
321                         end
322                 else
323                         self.object:set_velocity(vector.new(
324                                 math.random(-2,2)*math.random(),
325                                 math.random(2,5),
326                                 math.random(-2,2)*math.random()
327                         ))
328                 end
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},
335                         glow = 14,
336                 })
337                 self.object:set_sprite({x=1,y=math.random(1,14)}, 14, 0.05, false)
338         end,
339
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})
346                 end
347         end,
348
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})
355                 end
356         end,
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
362                                 return
363                         end
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]
367
368                                 self.object:set_acceleration(vector.new(0,0,0))
369                                 self.disable_physics(self)
370                                 --get the variables
371                                 pos = self.object:get_pos()
372                                 pos2 = collector:get_pos()
373                                 
374                 player_velocity = collector:get_player_velocity()
375                                             
376                                 pos2.y = pos2.y + 0.8
377                                                                 
378                                 direction = vector.direction(pos,pos2)
379                                 distance = vector.distance(pos2,pos)
380                                 multiplier = distance
381                 if multiplier < 1 then
382                     multiplier = 1
383                 end
384                                 goal = vector.multiply(direction,multiplier)
385                 currentvel = self.object:get_velocity()
386
387                                 if distance > 1 then
388                     multiplier = 20 - distance
389                     velocity = vector.multiply(direction,multiplier)
390                     goal = velocity
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)
401                 end
402                                 if distance < 0.4 and temp_pool.buffer <= 0 then
403                                         temp_pool.buffer = 0.04
404                     add_experience(collector,2)
405                                         self.object:remove()
406                                 end
407                                 return
408                         else
409                                 self.collector = nil
410                                 self.enable_physics(self)
411                         end
412                 end
413                 
414                                                 
415                 self.age = self.age + dtime
416                 if self.age > 300 then
417                         self.object:remove()
418                         return
419                 end
420
421                 pos = self.object:get_pos()
422
423                 if pos then
424                         node = minetest.get_node_or_nil({
425                                 x = pos.x,
426                                 y = pos.y -0.25,
427                                 z = pos.z
428                         })
429                 else
430                         return
431                 end
432
433                 -- Remove nodes in 'ignore'
434                 if node and node.name == "ignore" then
435                         self.object:remove()
436                         return
437                 end
438
439                 if not self.physical_state then
440                         return -- Don't do anything
441                 end
442
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
448                 is_slippery = false
449
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,
458                                         y = 0,
459                                         z = -vel.z * slip_factor
460                                 })
461                         elseif vel.y == 0 then
462                                 is_moving = false
463                         end
464                 end
465
466                 if self.moving_state == is_moving and self.slippery_state == is_slippery then
467                         -- Do not update anything until the moving state changes
468                         return
469                 end
470
471                 self.moving_state = is_moving
472                 self.slippery_state = is_slippery
473                 
474                 if is_moving then
475                         self.object:set_acceleration({x = 0, y = -9.81, z = 0})
476                 else
477                         self.object:set_acceleration({x = 0, y = 0, z = 0})
478                         self.object:set_velocity({x = 0, y = 0, z = 0})
479                 end
480         end,
481 })
482
483
484 minetest.register_chatcommand("xp", {
485         params = "nil",
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()
491                 pos.y = pos.y + 1.2
492                 minetest.throw_experience(pos, 1000)
493         end,
494 })