Fix negative offsets not being supported by container[]
[oweals/minetest.git] / builtin / game / statbars.lua
1 -- cache setting
2 local enable_damage = core.settings:get_bool("enable_damage")
3
4 local health_bar_definition =
5 {
6         hud_elem_type = "statbar",
7         position = { x=0.5, y=1 },
8         text = "heart.png",
9         number = core.PLAYER_MAX_HP_DEFAULT,
10         direction = 0,
11         size = { x=24, y=24 },
12         offset = { x=(-10*24)-25, y=-(48+24+16)},
13 }
14
15 local breath_bar_definition =
16 {
17         hud_elem_type = "statbar",
18         position = { x=0.5, y=1 },
19         text = "bubble.png",
20         number = core.PLAYER_MAX_BREATH_DEFAULT,
21         direction = 0,
22         size = { x=24, y=24 },
23         offset = {x=25,y=-(48+24+16)},
24 }
25
26 local hud_ids = {}
27
28 local function scaleToDefault(player, field)
29         -- Scale "hp" or "breath" to the default dimensions
30         local current = player["get_" .. field](player)
31         local nominal = core["PLAYER_MAX_".. field:upper() .. "_DEFAULT"]
32         local max_display = math.max(nominal,
33                 math.max(player:get_properties()[field .. "_max"], current))
34         return current / max_display * nominal 
35 end
36
37 local function update_builtin_statbars(player)
38         local name = player:get_player_name()
39
40         if name == "" then
41                 return
42         end
43
44         local flags = player:hud_get_flags()
45         if not hud_ids[name] then
46                 hud_ids[name] = {}
47                 -- flags are not transmitted to client on connect, we need to make sure
48                 -- our current flags are transmitted by sending them actively
49                 player:hud_set_flags(flags)
50         end
51         local hud = hud_ids[name]
52
53         local immortal = player:get_armor_groups().immortal == 1
54         if flags.healthbar and enable_damage and not immortal then
55                 local number = scaleToDefault(player, "hp")
56                 if hud.id_healthbar == nil then
57                         local hud_def = table.copy(health_bar_definition)
58                         hud_def.number = number
59                         hud.id_healthbar = player:hud_add(hud_def)
60                 else
61                         player:hud_change(hud.id_healthbar, "number", number)
62                 end
63         elseif hud.id_healthbar then
64                 player:hud_remove(hud.id_healthbar)
65                 hud.id_healthbar = nil
66         end
67
68         local breath_max = player:get_properties().breath_max
69         if flags.breathbar and enable_damage and not immortal and
70                         player:get_breath() < breath_max then
71                 local number = 2 * scaleToDefault(player, "breath")
72                 if hud.id_breathbar == nil then
73                         local hud_def = table.copy(breath_bar_definition)
74                         hud_def.number = number
75                         hud.id_breathbar = player:hud_add(hud_def)
76                 else
77                         player:hud_change(hud.id_breathbar, "number", number)
78                 end
79         elseif hud.id_breathbar then
80                 player:hud_remove(hud.id_breathbar)
81                 hud.id_breathbar = nil
82         end
83 end
84
85 local function cleanup_builtin_statbars(player)
86         local name = player:get_player_name()
87
88         if name == "" then
89                 return
90         end
91
92         hud_ids[name] = nil
93 end
94
95 local function player_event_handler(player,eventname)
96         assert(player:is_player())
97
98         local name = player:get_player_name()
99
100         if name == "" or not hud_ids[name] then
101                 return
102         end
103
104         if eventname == "health_changed" then
105                 update_builtin_statbars(player)
106
107                 if hud_ids[name].id_healthbar then
108                         return true
109                 end
110         end
111
112         if eventname == "breath_changed" then
113                 update_builtin_statbars(player)
114
115                 if hud_ids[name].id_breathbar then
116                         return true
117                 end
118         end
119
120         if eventname == "hud_changed" or eventname == "properties_changed" then
121                 update_builtin_statbars(player)
122                 return true
123         end
124
125         return false
126 end
127
128 function core.hud_replace_builtin(name, definition)
129
130         if type(definition) ~= "table" or
131                         definition.hud_elem_type ~= "statbar" then
132                 return false
133         end
134
135         if name == "health" then
136                 health_bar_definition = definition
137
138                 for name, ids in pairs(hud_ids) do
139                         local player = core.get_player_by_name(name)
140                         if player and ids.id_healthbar then
141                                 player:hud_remove(ids.id_healthbar)
142                                 ids.id_healthbar = nil
143                                 update_builtin_statbars(player)
144                         end
145                 end
146                 return true
147         end
148
149         if name == "breath" then
150                 breath_bar_definition = definition
151
152                 for name, ids in pairs(hud_ids) do
153                         local player = core.get_player_by_name(name)
154                         if player and ids.id_breathbar then
155                                 player:hud_remove(ids.id_breathbar)
156                                 ids.id_breathbar = nil
157                                 update_builtin_statbars(player)
158                         end
159                 end
160                 return true
161         end
162
163         return false
164 end
165
166 -- Append "update_builtin_statbars" as late as possible
167 -- This ensures that the HUD is hidden when the flags are updated in this callback
168 core.register_on_mods_loaded(function()
169         core.register_on_joinplayer(update_builtin_statbars)
170 end)
171 core.register_on_leaveplayer(cleanup_builtin_statbars)
172 core.register_playerevent(player_event_handler)