]> git.lizzy.rs Git - dragonfireclient.git/blob - builtin/common/misc_helpers.lua
Fix healthbar not beeing hidden on disabled damage
[dragonfireclient.git] / builtin / common / misc_helpers.lua
1 -- Minetest: builtin/misc_helpers.lua
2
3 --------------------------------------------------------------------------------
4 function basic_dump2(o)
5         if type(o) == "number" then
6                 return tostring(o)
7         elseif type(o) == "string" then
8                 return string.format("%q", o)
9         elseif type(o) == "boolean" then
10                 return tostring(o)
11         elseif type(o) == "function" then
12                 return "<function>"
13         elseif type(o) == "userdata" then
14                 return "<userdata>"
15         elseif type(o) == "nil" then
16                 return "nil"
17         else
18                 error("cannot dump a " .. type(o))
19                 return nil
20         end
21 end
22
23 --------------------------------------------------------------------------------
24 function dump2(o, name, dumped)
25         name = name or "_"
26         dumped = dumped or {}
27         io.write(name, " = ")
28         if type(o) == "number" or type(o) == "string" or type(o) == "boolean"
29                         or type(o) == "function" or type(o) == "nil"
30                         or type(o) == "userdata" then
31                 io.write(basic_dump2(o), "\n")
32         elseif type(o) == "table" then
33                 if dumped[o] then
34                         io.write(dumped[o], "\n")
35                 else
36                         dumped[o] = name
37                         io.write("{}\n") -- new table
38                         for k,v in pairs(o) do
39                                 local fieldname = string.format("%s[%s]", name, basic_dump2(k))
40                                 dump2(v, fieldname, dumped)
41                         end
42                 end
43         else
44                 error("cannot dump a " .. type(o))
45                 return nil
46         end
47 end
48
49 --------------------------------------------------------------------------------
50 function dump(o, dumped)
51         dumped = dumped or {}
52         if type(o) == "number" then
53                 return tostring(o)
54         elseif type(o) == "string" then
55                 return string.format("%q", o)
56         elseif type(o) == "table" then
57                 if dumped[o] then
58                         return "<circular reference>"
59                 end
60                 dumped[o] = true
61                 local t = {}
62                 for k,v in pairs(o) do
63                         t[#t+1] = "[" .. dump(k, dumped) .. "] = " .. dump(v, dumped)
64                 end
65                 return "{" .. table.concat(t, ", ") .. "}"
66         elseif type(o) == "boolean" then
67                 return tostring(o)
68         elseif type(o) == "function" then
69                 return "<function>"
70         elseif type(o) == "userdata" then
71                 return "<userdata>"
72         elseif type(o) == "nil" then
73                 return "nil"
74         else
75                 error("cannot dump a " .. type(o))
76                 return nil
77         end
78 end
79
80 --------------------------------------------------------------------------------
81 function string:split(sep)
82         local sep, fields = sep or ",", {}
83         local pattern = string.format("([^%s]+)", sep)
84         self:gsub(pattern, function(c) fields[#fields+1] = c end)
85         return fields
86 end
87
88 --------------------------------------------------------------------------------
89 function file_exists(filename)
90         local f = io.open(filename, "r")
91         if f==nil then
92                 return false
93         else
94                 f:close()
95                 return true
96         end
97 end
98
99 --------------------------------------------------------------------------------
100 function string:trim()
101         return (self:gsub("^%s*(.-)%s*$", "%1"))
102 end
103
104 assert(string.trim("\n \t\tfoo bar\t ") == "foo bar")
105
106 --------------------------------------------------------------------------------
107 function math.hypot(x, y)
108         local t
109         x = math.abs(x)
110         y = math.abs(y)
111         t = math.min(x, y)
112         x = math.max(x, y)
113         if x == 0 then return 0 end
114         t = t / x
115         return x * math.sqrt(1 + t * t)
116 end
117
118 --------------------------------------------------------------------------------
119 function get_last_folder(text,count)
120         local parts = text:split(DIR_DELIM)
121         
122         if count == nil then
123                 return parts[#parts]
124         end
125         
126         local retval = ""
127         for i=1,count,1 do
128                 retval = retval .. parts[#parts - (count-i)] .. DIR_DELIM
129         end
130         
131         return retval
132 end
133
134 --------------------------------------------------------------------------------
135 function cleanup_path(temppath)
136         
137         local parts = temppath:split("-")
138         temppath = ""   
139         for i=1,#parts,1 do
140                 if temppath ~= "" then
141                         temppath = temppath .. "_"
142                 end
143                 temppath = temppath .. parts[i]
144         end
145         
146         parts = temppath:split(".")
147         temppath = ""   
148         for i=1,#parts,1 do
149                 if temppath ~= "" then
150                         temppath = temppath .. "_"
151                 end
152                 temppath = temppath .. parts[i]
153         end
154         
155         parts = temppath:split("'")
156         temppath = ""   
157         for i=1,#parts,1 do
158                 if temppath ~= "" then
159                         temppath = temppath .. ""
160                 end
161                 temppath = temppath .. parts[i]
162         end
163         
164         parts = temppath:split(" ")
165         temppath = ""   
166         for i=1,#parts,1 do
167                 if temppath ~= "" then
168                         temppath = temppath
169                 end
170                 temppath = temppath .. parts[i]
171         end
172         
173         return temppath
174 end
175
176 function core.formspec_escape(text)
177         if text ~= nil then
178                 text = string.gsub(text,"\\","\\\\")
179                 text = string.gsub(text,"%]","\\]")
180                 text = string.gsub(text,"%[","\\[")
181                 text = string.gsub(text,";","\\;")
182                 text = string.gsub(text,",","\\,")
183         end
184         return text
185 end
186
187
188 function core.splittext(text,charlimit)
189         local retval = {}
190
191         local current_idx = 1
192         
193         local start,stop = string.find(text," ",current_idx)
194         local nl_start,nl_stop = string.find(text,"\n",current_idx)
195         local gotnewline = false
196         if nl_start ~= nil and (start == nil or nl_start < start) then
197                 start = nl_start
198                 stop = nl_stop
199                 gotnewline = true
200         end
201         local last_line = ""
202         while start ~= nil do
203                 if string.len(last_line) + (stop-start) > charlimit then
204                         table.insert(retval,last_line)
205                         last_line = ""
206                 end
207                 
208                 if last_line ~= "" then
209                         last_line = last_line .. " "
210                 end
211                 
212                 last_line = last_line .. string.sub(text,current_idx,stop -1)
213                 
214                 if gotnewline then
215                         table.insert(retval,last_line)
216                         last_line = ""
217                         gotnewline = false
218                 end
219                 current_idx = stop+1
220                 
221                 start,stop = string.find(text," ",current_idx)
222                 nl_start,nl_stop = string.find(text,"\n",current_idx)
223         
224                 if nl_start ~= nil and (start == nil or nl_start < start) then
225                         start = nl_start
226                         stop = nl_stop
227                         gotnewline = true
228                 end
229         end
230         
231         --add last part of text
232         if string.len(last_line) + (string.len(text) - current_idx) > charlimit then
233                         table.insert(retval,last_line)
234                         table.insert(retval,string.sub(text,current_idx))
235         else
236                 last_line = last_line .. " " .. string.sub(text,current_idx)
237                 table.insert(retval,last_line)
238         end
239         
240         return retval
241 end
242
243 --------------------------------------------------------------------------------
244
245 if INIT == "game" then
246         local dirs1 = {9, 18, 7, 12}
247         local dirs2 = {20, 23, 22, 21}
248
249         function core.rotate_and_place(itemstack, placer, pointed_thing,
250                                 infinitestacks, orient_flags)
251                 orient_flags = orient_flags or {}
252
253                 local unode = core.get_node_or_nil(pointed_thing.under)
254                 if not unode then
255                         return
256                 end
257                 local undef = core.registered_nodes[unode.name]
258                 if undef and undef.on_rightclick then
259                         undef.on_rightclick(pointed_thing.under, unode, placer,
260                                         itemstack, pointed_thing)
261                         return
262                 end
263                 local pitch = placer:get_look_pitch()
264                 local fdir = core.dir_to_facedir(placer:get_look_dir())
265                 local wield_name = itemstack:get_name()
266
267                 local above = pointed_thing.above
268                 local under = pointed_thing.under
269                 local iswall = (above.y == under.y)
270                 local isceiling = not iswall and (above.y < under.y)
271                 local anode = core.get_node_or_nil(above)
272                 if not anode then
273                         return
274                 end
275                 local pos = pointed_thing.above
276                 local node = anode
277
278                 if undef and undef.buildable_to then
279                         pos = pointed_thing.under
280                         node = unode
281                         iswall = false
282                 end
283
284                 if core.is_protected(pos, placer:get_player_name()) then
285                         core.record_protection_violation(pos,
286                                         placer:get_player_name())
287                         return
288                 end
289
290                 local ndef = core.registered_nodes[node.name]
291                 if not ndef or not ndef.buildable_to then
292                         return
293                 end
294
295                 if orient_flags.force_floor then
296                         iswall = false
297                         isceiling = false
298                 elseif orient_flags.force_ceiling then
299                         iswall = false
300                         isceiling = true
301                 elseif orient_flags.force_wall then
302                         iswall = true
303                         isceiling = false
304                 elseif orient_flags.invert_wall then
305                         iswall = not iswall
306                 end
307
308                 if iswall then
309                         core.set_node(pos, {name = wield_name,
310                                         param2 = dirs1[fdir+1]})
311                 elseif isceiling then
312                         if orient_flags.force_facedir then
313                                 core.set_node(pos, {name = wield_name,
314                                                 param2 = 20})
315                         else
316                                 core.set_node(pos, {name = wield_name,
317                                                 param2 = dirs2[fdir+1]})
318                         end
319                 else -- place right side up
320                         if orient_flags.force_facedir then
321                                 core.set_node(pos, {name = wield_name,
322                                                 param2 = 0})
323                         else
324                                 core.set_node(pos, {name = wield_name,
325                                                 param2 = fdir})
326                         end
327                 end
328
329                 if not infinitestacks then
330                         itemstack:take_item()
331                         return itemstack
332                 end
333         end
334
335
336 --------------------------------------------------------------------------------
337 --Wrapper for rotate_and_place() to check for sneak and assume Creative mode
338 --implies infinite stacks when performing a 6d rotation.
339 --------------------------------------------------------------------------------
340
341
342         core.rotate_node = function(itemstack, placer, pointed_thing)
343                 core.rotate_and_place(itemstack, placer, pointed_thing,
344                                 core.setting_getbool("creative_mode"),
345                                 {invert_wall = placer:get_player_control().sneak})
346                 return itemstack
347         end
348 end
349
350 --------------------------------------------------------------------------------
351 function core.explode_table_event(evt)
352         if evt ~= nil then
353                 local parts = evt:split(":")
354                 if #parts == 3 then
355                         local t = parts[1]:trim()
356                         local r = tonumber(parts[2]:trim())
357                         local c = tonumber(parts[3]:trim())
358                         if type(r) == "number" and type(c) == "number" and t ~= "INV" then
359                                 return {type=t, row=r, column=c}
360                         end
361                 end
362         end
363         return {type="INV", row=0, column=0}
364 end
365
366 --------------------------------------------------------------------------------
367 function core.explode_textlist_event(evt)
368         if evt ~= nil then
369                 local parts = evt:split(":")
370                 if #parts == 2 then
371                         local t = parts[1]:trim()
372                         local r = tonumber(parts[2]:trim())
373                         if type(r) == "number" and t ~= "INV" then
374                                 return {type=t, index=r}
375                         end
376                 end
377         end
378         return {type="INV", index=0}
379 end
380
381 function core.pos_to_string(pos)
382         return "(" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")"
383 end
384
385 --------------------------------------------------------------------------------
386 -- mainmenu only functions
387 --------------------------------------------------------------------------------
388 if INIT == "mainmenu" then
389         function core.get_game(index)
390                 local games = game.get_games()
391                 
392                 if index > 0 and index <= #games then
393                         return games[index]
394                 end
395                 
396                 return nil
397         end
398         
399         function fgettext(text, ...)
400                 text = core.gettext(text)
401                 local arg = {n=select('#', ...), ...}
402                 if arg.n >= 1 then
403                         -- Insert positional parameters ($1, $2, ...)
404                         result = ''
405                         pos = 1
406                         while pos <= text:len() do
407                                 newpos = text:find('[$]', pos)
408                                 if newpos == nil then
409                                         result = result .. text:sub(pos)
410                                         pos = text:len() + 1
411                                 else
412                                         paramindex = tonumber(text:sub(newpos+1, newpos+1))
413                                         result = result .. text:sub(pos, newpos-1) .. tostring(arg[paramindex])
414                                         pos = newpos + 2
415                                 end
416                         end
417                         text = result
418                 end
419                 return core.formspec_escape(text)
420         end
421 end
422