-
Notifications
You must be signed in to change notification settings - Fork 0
/
hunger.lua
168 lines (157 loc) · 5.32 KB
/
hunger.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
-- Keep these for backwards compatibility
function hbhunger.save_hunger(player)
hbhunger.set_hunger_raw(player)
end
function hbhunger.load_hunger(player)
hbhunger.get_hunger_raw(player)
end
-- HACK: We register our on_item_eat handler after the other mods have loaded
-- so their on_item_eat handlers run first. This is because Luanti refuses
-- to run ANY further on_item_eat handler once one of the callback functions
-- has returned an itemstack. (as of Luanti 5.10.0)
-- FIXME: Remove the register_on_mods_loaded as soon Luanti handles
-- on_item_eat events in a less weird manner.
minetest.register_on_mods_loaded(function()
minetest.register_on_item_eat(function(hp_change, replace_with_item, itemstack, user, pointed_thing)
-- Our own item eat handler
return hbhunger.eat(hp_change, replace_with_item, ItemStack(itemstack), user, pointed_thing)
end)
end)
-- food functions
local food = hbhunger.food
function hbhunger.register_food(name, hunger_change, replace_with_item, poisen, heal, sound)
food[name] = {}
food[name].saturation = hunger_change -- hunger points added
food[name].replace = replace_with_item -- what item is given back after eating
food[name].poisen = poisen -- time its poisening
food[name].healing = heal -- amount of HP
food[name].sound = sound -- special sound that is played when eating
end
function hbhunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
local item = itemstack:get_name()
local def = food[item]
if not def then
def = {}
if type(hp_change) ~= "number" then
hp_change = 1
minetest.log("error", "Wrong on_use() definition for item '" .. item .. "'")
end
def.saturation = hp_change * 1.3
def.replace = replace_with_item
end
local func = hbhunger.item_eat(def.saturation, def.replace, def.poisen, def.healing, def.sound)
return func(itemstack, user, pointed_thing)
end
-- Poison player
local function poisenp(tick, time, time_left, player)
-- First check if player is still there
if not player:is_player() then
return
end
time_left = time_left + tick
if time_left < time then
minetest.after(tick, poisenp, tick, time, time_left, player)
else
hbhunger.poisonings[player:get_player_name()] = hbhunger.poisonings[player:get_player_name()] - 1
if hbhunger.poisonings[player:get_player_name()] <= 0 then
-- Reset HUD bar color
hb.change_hudbar(player, "health", nil, nil, "hudbars_icon_health.png", nil, "hudbars_bar_health.png")
end
end
if player:get_hp()-1 > 0 then
player:set_hp(player:get_hp()-1)
end
end
function hbhunger.item_eat(hunger_change, replace_with_item, poisen, heal, sound)
return function(itemstack, user, pointed_thing)
if itemstack:take_item() ~= nil and user ~= nil then
local name = user:get_player_name()
local h = tonumber(hbhunger.hunger[name])
local hp = user:get_hp()
if h == nil or hp == nil then
return
end
if user:is_player() then
local object, object_pos
-- Check if user is a "fake player" (unofficial imitation of a the player data structure)
if type(user) == "userdata" then
object = user
else
object_pos = user:get_pos()
end
minetest.sound_play(
{name = sound or "hbhunger_eat_generic",
gain = 1},
{object=object,
pos=object_pos,
max_hear_distance = 16,
pitch = 1 + math.random(-10, 10)*0.005,},
true
)
end
-- Saturation
if h < hbhunger.SAT_MAX and hunger_change then
h = h + hunger_change
if h > hbhunger.SAT_MAX then h = hbhunger.SAT_MAX end
hbhunger.hunger[name] = h
hbhunger.set_hunger_raw(user)
end
-- Healing
local hp_max = user:get_properties().hp_max or minetest.PLAYER_MAX_HP_DEFAULT or 20
if hp < hp_max and heal then
hp = hp + heal
if hp > hp_max then hp = hp_max end
user:set_hp(hp)
end
-- Poison
if poisen then
-- Set poison bar
hb.change_hudbar(user, "health", nil, nil, "hbhunger_icon_health_poison.png", nil, "hbhunger_bar_health_poison.png")
hbhunger.poisonings[name] = hbhunger.poisonings[name] + 1
poisenp(1, poisen, 0, user)
end
if itemstack:get_count() == 0 then
itemstack:add_item(replace_with_item)
else
local inv = user:get_inventory()
if inv:room_for_item("main", replace_with_item) then
inv:add_item("main", replace_with_item)
else
minetest.add_item(user:get_pos(), replace_with_item)
end
end
end
return itemstack
end
end
-- player-action based hunger changes
function hbhunger.handle_node_actions(pos, oldnode, player, ext)
-- is_fake_player comes from the pipeworks, we are not interested in those
if not player or not player:is_player() or player.is_fake_player == true then
return
end
local name = player:get_player_name()
local exhaus = hbhunger.exhaustion[name]
if exhaus == nil then return end
local new = hbhunger.EXHAUST_PLACE
-- placenode event
if not ext then
new = hbhunger.EXHAUST_DIG
end
-- assume its send by main timer when movement detected
if not pos and not oldnode then
new = hbhunger.EXHAUST_MOVE
end
exhaus = exhaus + new
if exhaus > hbhunger.EXHAUST_LVL then
exhaus = 0
local h = tonumber(hbhunger.hunger[name])
h = h - 1
if h < 0 then h = 0 end
hbhunger.hunger[name] = h
hbhunger.set_hunger_raw(player)
end
hbhunger.exhaustion[name] = exhaus
end
minetest.register_on_placenode(hbhunger.handle_node_actions)
minetest.register_on_dignode(hbhunger.handle_node_actions)