init.lua 6.2 KB

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