init.lua 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. heatdamage = heatdamage or {}
  2. heatdamage.modpath = minetest.get_modpath("heatdamage")
  3. -- Localize for performance.
  4. local math_floor = math.floor
  5. heatdamage.immune_players = heatdamage.immune_players or {}
  6. heatdamage.cache_range = 2
  7. heatdamage.scan_range = 2
  8. heatdamage.server_step = 1
  9. heatdamage.environment_cache = heatdamage.environment_cache or {}
  10. heatdamage.cache_hit = heatdamage.cache_hit or 0
  11. heatdamage.cache_miss = heatdamage.cache_miss or 0
  12. heatdamage.cache_clean = 20
  13. heatdamage.immune_players["MustTest"] = {timer=-1}
  14. heatdamage.immune_players["singleplayer"] = {timer=-1}
  15. heatdamage.is_immune = function(pname)
  16. if heatdamage.immune_players[pname] then
  17. if heatdamage.immune_players[pname].timer > 0 then
  18. return true
  19. end
  20. end
  21. return false
  22. end
  23. heatdamage.immunize_player = function(pname, add_seconds)
  24. assert(add_seconds > 0)
  25. if heatdamage.immune_players[pname] then
  26. local timer = heatdamage.immune_players[pname].timer
  27. if timer >= 0 then
  28. timer = timer + add_seconds
  29. heatdamage.immune_players[pname].timer = timer
  30. end
  31. else
  32. heatdamage.immune_players[pname] = {timer=add_seconds}
  33. end
  34. local total = heatdamage.immune_players[pname].timer
  35. minetest.chat_send_player(pname, "# Server: You are protected from heat for " .. math_floor(total) .. " seconds.")
  36. end
  37. local is_exposed = function(pos)
  38. -- Table is ordered for performance.
  39. local points = {
  40. {x=pos.x, y=pos.y+1, z=pos.z}, -- Top first. Most common case.
  41. {x=pos.x-1, y=pos.y, z=pos.z},
  42. {x=pos.x+1, y=pos.y, z=pos.z},
  43. {x=pos.x, y=pos.y, z=pos.z-1},
  44. {x=pos.x, y=pos.y, z=pos.z+1},
  45. {x=pos.x, y=pos.y-1, z=pos.z},
  46. }
  47. local get_node = minetest.get_node
  48. for i=1, #points do
  49. local n = get_node(points[i]).name
  50. if n == "air" then return true end
  51. end
  52. return false
  53. end
  54. local vector_round = vector.round
  55. heatdamage.environment_scan = function(pos)
  56. local cache = heatdamage.environment_cache
  57. local range = heatdamage.cache_range
  58. local distance = vector.distance
  59. -- If this position was scanned already, just return our cached information.
  60. for k, v in ipairs(cache) do
  61. if distance(pos, v.pos) < range then
  62. heatdamage.cache_hit = heatdamage.cache_hit + 1
  63. return v.counts, v.lava
  64. end
  65. end
  66. local rad = heatdamage.scan_range
  67. local loc = vector_round(pos)
  68. local ps, counts = minetest.find_nodes_in_area(
  69. {x=loc.x-rad, y=loc.y-rad, z=loc.z-rad},
  70. {x=loc.x+rad, y=loc.y+rad, z=loc.z+rad},
  71. {"group:lava", "group:flame"})
  72. local total = 0
  73. local lava = 0
  74. local get_node = minetest.get_node
  75. for k, v in ipairs(ps) do
  76. local n = get_node(v).name
  77. if is_exposed(v) then
  78. if n == "default:lava_source" then
  79. total = total + 0.2
  80. lava = lava + 1
  81. elseif n == "default:lava_flowing" then
  82. total = total + 0.2
  83. lava = lava + 1
  84. elseif n == "lbrim:lava_source" then
  85. total = total + 0.15
  86. lava = lava + 1
  87. elseif n == "lbrim:lava_flowing" then
  88. total = total + 0.15
  89. lava = lava + 1
  90. elseif n == "fire:basic_flame" then
  91. total = total + 0.06
  92. elseif n == "fire:nether_flame" then
  93. total = total + 0.08
  94. elseif n == "fire:permanent_flame" then
  95. total = total + 0.06
  96. end
  97. end
  98. end
  99. -- Cache results for next time.
  100. local idx = #cache + 1
  101. cache[idx] = {pos=loc, counts=total, lava=lava}
  102. heatdamage.cache_miss = heatdamage.cache_miss + 1
  103. return total, lava
  104. end
  105. local steptimer = 0
  106. local cachetimer = 0
  107. local serverstep = heatdamage.server_step
  108. local cacheclean = heatdamage.cache_clean
  109. heatdamage.globalstep = function(dtime)
  110. steptimer = steptimer + dtime
  111. if steptimer < serverstep then return end
  112. steptimer = 0
  113. cachetimer = cachetimer + serverstep
  114. if cachetimer >= cacheclean then
  115. heatdamage.environment_cache = {}
  116. heatdamage.cache_hit = 0
  117. heatdamage.cache_miss = 0
  118. cachetimer = 0
  119. end
  120. local floor = math_floor
  121. local scan = heatdamage.environment_scan
  122. local players = minetest.get_connected_players()
  123. for k, v in ipairs(players) do
  124. local name = v:get_player_name()
  125. if heatdamage.immune_players[name] == nil then
  126. if v:get_hp() > 0 then -- Don't bother if player already dead.
  127. -- Scan environment for nearby heat sources capable of causing damage to players.
  128. local total, lava = scan(v:get_pos())
  129. total = floor(total + 0.5)
  130. if total > 0 then
  131. sprint.set_stamina(v, 0)
  132. v:set_hp(v:get_hp() - total * serverstep)
  133. if lava and lava > 2 then
  134. local p = minetest.find_node_near(v:get_pos(), 1, "air", true)
  135. if p then
  136. minetest.set_node(p, {name="fire:basic_flame"})
  137. end
  138. end
  139. if v:get_hp() <= 0 then
  140. -- Player died.
  141. if player_labels.query_nametag_onoff(name) == true and not cloaking.is_cloaked(name) then
  142. minetest.chat_send_all("# Server: <" .. rename.gpn(name) .. "> caught fire.")
  143. else
  144. minetest.chat_send_all("# Server: Someone caught fire.")
  145. end
  146. end
  147. end
  148. end
  149. end
  150. end
  151. local removenames = {}
  152. for k, v in pairs(heatdamage.immune_players) do
  153. if v.timer > 0 then
  154. v.timer = v.timer - serverstep
  155. if v.timer <= 0 then
  156. removenames[k] = true
  157. minetest.chat_send_player(k, "# Server: Your protection from heat fades away.")
  158. end
  159. end
  160. end
  161. for k, v in pairs(removenames) do
  162. heatdamage.immune_players[k] = nil
  163. end
  164. end
  165. if not heatdamage.run_once then
  166. minetest.register_globalstep(function(...) return heatdamage.globalstep(...) end)
  167. local c = "heatdamage:core"
  168. local f = heatdamage.modpath .. "/init.lua"
  169. reload.register_file(c, f, false)
  170. heatdamage.run_once = true
  171. end