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