init.lua 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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
  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 get_node = minetest.get_node
  74. for k, v in ipairs(ps) do
  75. local n = get_node(v).name
  76. if is_exposed(v) then
  77. if n == "default:lava_source" then
  78. total = total + 0.2
  79. elseif n == "default:lava_flowing" then
  80. total = total + 0.2
  81. elseif n == "lbrim:lava_source" then
  82. total = total + 0.15
  83. elseif n == "lbrim:lava_flowing" then
  84. total = total + 0.15
  85. elseif n == "fire:basic_flame" then
  86. total = total + 0.06
  87. elseif n == "fire:nether_flame" then
  88. total = total + 0.08
  89. elseif n == "fire:permanent_flame" then
  90. total = total + 0.06
  91. end
  92. end
  93. end
  94. -- Cache results for next time.
  95. local idx = #cache + 1
  96. cache[idx] = {pos=loc, counts=total}
  97. heatdamage.cache_miss = heatdamage.cache_miss + 1
  98. return total
  99. end
  100. local steptimer = 0
  101. local cachetimer = 0
  102. local serverstep = heatdamage.server_step
  103. local cacheclean = heatdamage.cache_clean
  104. heatdamage.globalstep = function(dtime)
  105. steptimer = steptimer + dtime
  106. if steptimer < serverstep then return end
  107. steptimer = 0
  108. cachetimer = cachetimer + serverstep
  109. if cachetimer >= cacheclean then
  110. heatdamage.environment_cache = {}
  111. heatdamage.cache_hit = 0
  112. heatdamage.cache_miss = 0
  113. cachetimer = 0
  114. end
  115. local floor = math_floor
  116. local scan = heatdamage.environment_scan
  117. local players = minetest.get_connected_players()
  118. for k, v in ipairs(players) do
  119. local name = v:get_player_name()
  120. if heatdamage.immune_players[name] == nil then
  121. if v:get_hp() > 0 then -- Don't bother if player already dead.
  122. -- Scan environment for nearby heat sources capable of causing damage to players.
  123. local total = floor(scan(v:getpos()) + 0.5)
  124. if total > 0 then
  125. sprint.set_stamina(v, 0)
  126. v:set_hp(v:get_hp() - total * serverstep)
  127. if v:get_hp() <= 0 then
  128. -- Player died.
  129. if player_labels.query_nametag_onoff(name) == true and not cloaking.is_cloaked(name) then
  130. minetest.chat_send_all("# Server: <" .. rename.gpn(name) .. "> caught fire.")
  131. else
  132. minetest.chat_send_all("# Server: Someone caught fire.")
  133. end
  134. end
  135. end
  136. end
  137. end
  138. end
  139. local removenames = {}
  140. for k, v in pairs(heatdamage.immune_players) do
  141. if v.timer > 0 then
  142. v.timer = v.timer - serverstep
  143. if v.timer <= 0 then
  144. removenames[k] = true
  145. minetest.chat_send_player(k, "# Server: Your protection from heat fades away.")
  146. end
  147. end
  148. end
  149. for k, v in pairs(removenames) do
  150. heatdamage.immune_players[k] = nil
  151. end
  152. end
  153. if not heatdamage.run_once then
  154. minetest.register_globalstep(function(...) return heatdamage.globalstep(...) end)
  155. local c = "heatdamage:core"
  156. local f = heatdamage.modpath .. "/init.lua"
  157. reload.register_file(c, f, false)
  158. heatdamage.run_once = true
  159. end