init.lua 5.6 KB

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