]> git.lizzy.rs Git - Crafter.git/blob - mods/hunger/init.lua
9b42e946c807998da68c596dda263f264bcfdb9b
[Crafter.git] / mods / hunger / init.lua
1 local minetest           = minetest
2 local mod_storage        = minetest.get_mod_storage()
3 local player_hunger_data = {} -- array to hold hunger data
4 local hunger_class       = {}
5 hunger_pointer           = {} -- allow other mods to access local data
6
7
8 -- creates volitile data for the game to use
9 hunger_class.set_data = function(player,data)
10         local name = player:get_player_name()
11         if not player_hunger_data[name] then
12                 player_hunger_data[name] = {}
13         end
14
15         for index,i_data in pairs(data) do
16                 player_hunger_data[name][index] = i_data
17         end
18
19         if data.hunger then
20                 hud_manager.change_hud({
21                         player    =  player ,
22                         hud_name  = "hunger",
23                         element   = "number",
24                         data      =  data.hunger
25                 })
26         end
27 end
28
29 -- indexes hunger data and returns it
30 hunger_class.get_data = function(player,requested_data)
31         local name = player:get_player_name()
32         if player_hunger_data[name] then
33                 local data_list = {}
34                 local count     = 0
35                 for index,i_data in pairs(requested_data) do
36                         if player_hunger_data[name][i_data] then
37                                 data_list[i_data] = player_hunger_data[name][i_data]
38                                 count = count + 1
39                         end
40                 end
41                 if count > 0 then
42                         return(data_list)
43                 else
44                         return(nil)
45                 end
46         end
47         return(nil)
48 end
49
50 -- removes hunger data
51 hunger_class.terminate = function(player)
52         local name = player:get_player_name()
53         if player_hunger_data[name] then
54                 player_hunger_data[name] = nil
55         end
56 end
57
58 -- loads data from mod storage
59 hunger_class.load_data = function(player)
60         local name = player:get_player_name()
61         if mod_storage:get_int(name.."h_save") > 0 then
62                 return({
63                                 hunger                = mod_storage:get_int(name.."hunger"               ),
64                                 satiation             = mod_storage:get_int(name.."satiation"            ),
65                                 exhaustion            = mod_storage:get_int(name.."exhaustion"           ),
66                                 regeneration_interval = mod_storage:get_int(name.."regeneration_interval")
67                           })
68         else
69                 return({
70                                 hunger                = 20,
71                                 satiation             = 20,
72                                 regeneration_interval = 0,
73                                 exhaustion            = 0
74                           })
75         end
76 end
77
78 -- saves data to be utilized on next login
79 hunger_class.save_data = function(player)
80         local name
81         if type(player) ~= "string" and player:is_player() then
82                 name = player:get_player_name()
83         elseif type(player) == "string" then
84                 name = player
85         end
86         if player_hunger_data[name] then
87                 for index,integer in pairs(player_hunger_data[name]) do
88                         mod_storage:set_int(name..index,integer)
89                 end
90         end
91
92         mod_storage:set_int(name.."h_save", 1)
93
94         player_hunger_data[name] = nil
95 end
96
97 -- is used for shutdowns to save all data
98 hunger_class.save_all = function()
99         for name,data in pairs(player_hunger_data) do
100                 hunger_class.save_data(name)
101         end
102 end
103
104 -- an easy translation pool
105 hunger_class.satiation_pool = {
106         [0]   = 1,
107         [0.5] = 3,
108         [1]   = 6,
109         [2]   = 8,
110         [3]   = 1
111 }
112 -- ticks up the exhaustion when counting down satiation
113 hunger_class.tick_up_satiation = function(m_data,exhaustion)
114         return(exhaustion + hunger_class.satiation_pool[m_data])
115 end
116
117 -- an easy translation pool
118 hunger_class.hunger_pool = {
119         [0]   = 1,
120         [0.5] = 2,
121         [1]   = 3,
122         [2]   = 4,
123         [3]   = 1
124 }
125 -- ticks up the exhaustion when counting down hunger
126 hunger_class.tick_up_hunger = function(m_data,exhaustion)
127         return(exhaustion + hunger_class.hunger_pool[m_data])
128 end
129
130 -- allows other mods to set hunger data
131 hunger_pointer.set_data = function(player,data)
132         local name = player:get_player_name()
133         if not player_hunger_data[name] then
134                 player_hunger_data[name] = {}
135         end
136
137         for index,i_data in pairs(data) do
138                 player_hunger_data[name][index] = i_data
139         end
140
141         if data.hunger then
142                 hud_manager.change_hud({
143                         player    =  player ,
144                         hud_name  = "hunger",
145                         element   = "number",
146                         data      =  data.hunger
147                 })
148         end
149 end
150
151 -- allows other mods to index hunger data
152 hunger_pointer.get_data = function(player,requested_data)
153         local name = player:get_player_name()
154         if player_hunger_data[name] then
155                 local data_list = {}
156                 local count     = 0
157                 for index,i_data in pairs(requested_data) do
158                         if player_hunger_data[name][i_data] then
159                                 data_list[i_data] = player_hunger_data[name][i_data]
160                                 count = count + 1
161                         end
162                 end
163                 if count > 0 then
164                         return(data_list)
165                 else
166                         return(nil)
167                 end
168         end
169         return(nil)
170 end
171
172 -- saves specific users data for when they relog
173 minetest.register_on_leaveplayer(function(player)
174         hunger_class.save_data(player)
175         hunger_class.terminate(player)
176 end)
177
178 -- save all data to mod storage on shutdown
179 minetest.register_on_shutdown(function()
180         hunger_class.save_all()
181 end)
182
183 -- create new data for hunger per player
184 minetest.register_on_joinplayer(function(player)
185         local name        = player:get_player_name()
186         local data        = hunger_class.load_data(player)
187
188         hunger_class.set_data(player,data)
189
190         hud_manager.add_hud(player,"hunger_bg",{
191                 hud_elem_type = "statbar",
192                 position      = {x = 0.5, y = 1},
193                 text          = "hunger_icon_bg.png",
194                 number        = 20,
195                 direction     = 1,
196                 size          = {x = 24, y = 24},
197                 offset        = {x = 24*10, y= -(48 + 24 + 39)},
198         })
199         hud_manager.add_hud(player,"hunger",{
200                 hud_elem_type = "statbar",
201                 position      = {x = 0.5, y = 1},
202                 text          = "hunger_icon.png",
203                 number        = data.hunger,
204                 direction     = 1,
205                 size          = {x = 24, y = 24},
206                 offset        = {x = 24*10, y= -(48 + 24 + 39)},
207         })
208 end)
209
210 -- resets the players hunger settings to max
211 minetest.register_on_respawnplayer(function(player)
212         hunger_class.set_data(player,{
213                 hunger                = 20,
214                 satiation             = 20,
215                 regeneration_interval = 0,
216                 exhaustion            = 0,
217         })
218 end)
219
220
221
222 --this is the max exhaustion a player will get before their
223 --satiation goes down and rolls over
224 local exhaustion_peak = 384
225 --when satiation runs out this is when the hunger peak variable
226 --is used, everytime the player rolls over this their hunger ticks down
227 --based on what they're doing
228 local hunger_peak = 64
229
230
231 local function hunger_update()
232         for _,player in ipairs(minetest.get_connected_players()) do
233                 --do not regen player's health if dead - this will be reused for 1up apples
234                 if player:get_hp() > 0 then
235                 
236                         local data = hunger_class.get_data(player,{
237                                 "hunger","satiation","exhaustion","regeneration_interval"
238                         })
239                         
240                         --movement state
241                         local m_data = movement_pointer.get_data(player,{"state"})
242                         if m_data then
243                                 m_data = m_data.state
244                         end
245                         
246                         --we must seperate these two values
247                         if m_data == 0 then
248                                 local input = player:get_player_control()
249                                 if input.jump or input.right or input.left or input.down or input.up then
250                                         m_data = 0.5
251                                 end
252                         end
253                         
254                         -- count up the exhaustion of the player moving around
255
256                         -- count down invisible satiation bar
257                         if data.satiation > 0 and data.hunger >= 20 then
258                                 data.exhaustion = hunger_class.tick_up_satiation(m_data,data.exhaustion)
259                                 if data.exhaustion >= exhaustion_peak then
260                                         data.satiation = data.satiation - 1
261                                         data.exhaustion = data.exhaustion - exhaustion_peak
262                                         
263                                         --reset this to use for the hunger tick
264                                         if data.satiation == 0 then
265                                                 data.exhaustion = 0
266                                         end
267                                         hunger_class.set_data(player,{satiation=data.satiation})
268                                 end
269                                 hunger_class.set_data(player,{exhaustion=data.exhaustion})
270                         -- count down hunger bars
271                         elseif data.hunger > 0 then
272                                 data.exhaustion = hunger_class.tick_up_hunger(m_data,data.exhaustion)
273                                 
274                                 if data.exhaustion >= hunger_peak then
275                                         --don't allow hunger to go negative
276                                         if data.hunger > 0 then
277                                                 data.exhaustion = 0
278                                                 data.hunger = data.hunger - 1
279                                                 hunger_class.set_data(player,{hunger=data.hunger})
280                                         end
281                                 end
282                                 hunger_class.set_data(player,{exhaustion=data.exhaustion})
283                         -- hurt the player if hunger bar empty
284                         elseif data.hunger <= 0 then
285                                 data.exhaustion = data.exhaustion + 1
286                                 local hp = player:get_hp()
287                                 if hp > 0 and data.exhaustion >= 2 then
288                                         player:set_hp(hp-1)
289                                         data.exhaustion = 0
290                                 end
291                                 hunger_class.set_data(player,{exhaustion=data.exhaustion})
292                         end
293                         
294                         
295                         local hp = player:get_hp()
296                         local drowning = drowning_pointer.get_data(player,{"drowning"})
297                         if drowning then
298                                 drowning = drowning.drowning
299                         end
300                         --make regeneration happen every second
301                         if drowning == 0 and data.hunger >= 20 and hp < 20 then --  meta:get_int("on_fire") == 0 
302                                 --print(regeneration_interval,"--------------------------")
303                                 data.regeneration_interval = data.regeneration_interval + 1
304                                 if data.regeneration_interval >= 2 then
305                                         player:set_hp(hp+1)
306                                         data.exhaustion = data.exhaustion + 32
307                                         data.regeneration_interval = 0
308                                         
309                                         hunger_class.set_data(player,{
310                                                 regeneration_interval = data.regeneration_interval,
311                                                 exhaustion            = data.exhaustion           ,
312                                                 satiation             = data.satiation            ,
313                                         })
314                                 else
315                                         hunger_class.set_data(player,{regeneration_interval=data.regeneration_interval})
316                                 end
317                         --reset the regen interval
318                         else
319                                 hunger_class.set_data(player,{regeneration_interval=0})
320                         end
321                 end
322         end
323         
324         minetest.after(0.5, function()
325                 hunger_update()
326         end)
327 end
328
329 minetest.register_on_mods_loaded(function()
330         minetest.after(0,function()
331                 hunger_update()
332         end)
333 end)
334
335 --take away hunger and satiation randomly while mining
336 minetest.register_on_dignode(function(pos, oldnode, digger)
337         if digger and digger:is_player() then
338                 local data = hunger_class.get_data(digger,{"exhaustion"})
339                 data.exhaustion = data.exhaustion + math.random(0,2)
340                 hunger_class.set_data(digger,{exhaustion=data.exhaustion})
341         end
342 end)
343
344 --allow players to eat food
345 function minetest.eat_food(player,item)
346         local meta = player:get_meta()
347         
348         local player_hunger = meta:get_int("hunger")
349         local player_satiation = meta:get_int("satiation")
350         
351         
352         if type(item) == "string" then
353                 item = ItemStack(item)
354         elseif type(item) == "table" then
355                 item = ItemStack(item.name)
356         end
357         
358         item = item:get_name()
359         
360         local satiation = minetest.get_item_group(item, "satiation")
361         local hunger = minetest.get_item_group(item, "hunger")
362         
363         if player_hunger < 20 then
364                 player_hunger = player_hunger + hunger
365                 if player_hunger > 20 then
366                         player_hunger = 20
367                 end
368         end
369         if player_satiation < satiation then
370                 player_satiation =  satiation
371         end
372         
373         meta:set_int("exhaustion", 0)
374         meta:set_int("hunger", player_hunger)
375         meta:set_int("satiation", player_satiation)
376         local hunger_bar = meta:get_int("hunger_bar")
377         player:hud_change(hunger_bar, "number", player_hunger)
378         local stack = player:get_wielded_item()
379         stack:take_item()
380         player:set_wielded_item(stack)
381 end
382
383 function minetest.register_food(name,def)
384         minetest.register_craftitem(":"..name, {
385                 description = def.description,
386                 inventory_image = def.texture,
387                 groups = {satiation=def.satiation,hunger=def.hunger},
388         })
389
390         minetest.register_node(":"..name.."node", {
391                 tiles = {def.texture},
392                 drawtype = "allfaces",
393         })
394 end
395
396
397 minetest.register_chatcommand("hungry", {
398         params = "<mob>",
399         description = "A debug command to test food",
400         privs = {server = true},
401         func = function(name)
402                 local player = minetest.get_player_by_name(name)
403                 hunger_class.set_data(player,{
404                         exhaustion = 0,
405                         hunger     = 1,
406                         satiation  = 0
407                 })
408         end
409 })