init.lua 6.1 KB

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