breath.lua 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. breath = breath or {}
  2. breath.modpath = minetest.get_modpath("hb4")
  3. function breath.time()
  4. return math.random(20, 200)/10
  5. end
  6. -- Recursive algorithm.
  7. local function floodfill(startpos, maxdepth)
  8. local traversal = {}
  9. local queue = {}
  10. local output = {}
  11. local curpos, hash, exists, name, found, norm, cb, depth
  12. local maxlength = 1
  13. local get_node_hash = minetest.hash_node_position
  14. local get_node = minetest.get_node
  15. startpos.d = 1
  16. queue[#queue+1] = startpos
  17. ::continue::
  18. curpos = queue[#queue]
  19. queue[#queue] = nil
  20. depth = curpos.d
  21. curpos.d = nil
  22. hash = get_node_hash(curpos)
  23. exists = false
  24. if traversal[hash] then
  25. exists = true
  26. if depth >= traversal[hash] then
  27. goto next
  28. end
  29. end
  30. if depth >= maxdepth then
  31. goto next
  32. end
  33. name = get_node(curpos).name
  34. found = false
  35. if name == 'air' then
  36. found = true
  37. end
  38. if not found then
  39. goto next
  40. end
  41. traversal[hash] = depth
  42. if not exists then
  43. output[#output+1] = vector.new(curpos)
  44. end
  45. queue[#queue+1] = {x=curpos.x+1, y=curpos.y, z=curpos.z, d=depth+1}
  46. queue[#queue+1] = {x=curpos.x-1, y=curpos.y, z=curpos.z, d=depth+1}
  47. queue[#queue+1] = {x=curpos.x, y=curpos.y+1, z=curpos.z, d=depth+1}
  48. queue[#queue+1] = {x=curpos.x, y=curpos.y-1, z=curpos.z, d=depth+1}
  49. queue[#queue+1] = {x=curpos.x, y=curpos.y, z=curpos.z+1, d=depth+1}
  50. queue[#queue+1] = {x=curpos.x, y=curpos.y, z=curpos.z-1, d=depth+1}
  51. if #queue > maxlength then
  52. maxlength = #queue
  53. end
  54. ::next::
  55. if #queue > 0 then
  56. goto continue
  57. end
  58. --minetest.chat_send_all("# Server: Array size: " .. maxlength)
  59. return output
  60. end
  61. function breath.on_construct(pos)
  62. end
  63. function breath.on_destruct(pos)
  64. end
  65. function breath.on_timer(pos, elapsed)
  66. end
  67. function breath.ignite_nearby_gas(pos)
  68. --minetest.chat_send_player("MustTest", "# Server: Igniting gas @ " .. minetest.pos_to_string(pos) .. "!")
  69. pos = vector.round(pos)
  70. local gas = minetest.find_node_near(pos, 2, {"group:gas"})
  71. if gas then
  72. minetest.set_node(gas, {name="fire:basic_flame"})
  73. end
  74. end
  75. function breath.extinguish_torches_around(v)
  76. -- Find nearby torches.
  77. local min = {x=v.x-1, y=v.y-1, z=v.z-1}
  78. local max = {x=v.x+1, y=v.y+1, z=v.z+1}
  79. local torches = minetest.find_nodes_in_area(min, max, {"group:torch", "group:fire"})
  80. -- Replace nearby torches or fire with gas.
  81. for i = 1, #torches, 1 do
  82. local nn = minetest.get_node(torches[i]).name
  83. minetest.after(math.random(1, 10), function()
  84. -- We delayed a bit, we must ensure node has not changed.
  85. local n2 = minetest.get_node(torches[i]).name
  86. if n2 == nn then
  87. _nodeupdate.drop_node_as_entity(torches[i])
  88. local node = minetest.get_node(torches[i])
  89. if node.name == "air" then
  90. node.name = "gas:poison"
  91. minetest.set_node(torches[i], node)
  92. end
  93. end
  94. end)
  95. end
  96. end
  97. function breath.spawn_gas(pos)
  98. pos = vector.round(pos)
  99. ambiance.sound_play("tnt_ignite", pos, 1.0, 60)
  100. local positions = floodfill(pos, math.random(10, 30))
  101. local set_node = minetest.set_node
  102. for k, v in ipairs(positions) do
  103. set_node(v, {name="gas:poison"})
  104. breath.extinguish_torches_around(v)
  105. end
  106. end
  107. if not breath.run_once then
  108. -- 8 levels of gas, now depreciated.
  109. for i = 1, 8, 1 do
  110. minetest.register_alias("gas:poison_" .. i, "gas:poison")
  111. end
  112. minetest.register_node(":gas:poison", {
  113. drawtype = "airlike",
  114. --tiles = {"default_gold_block.png"},
  115. description = "Poison Gas",
  116. paramtype = "light",
  117. sunlight_propagates = true,
  118. walkable = false,
  119. pointable = false,
  120. climbable = false,
  121. buildable_to = true,
  122. floodable = true,
  123. drop = "",
  124. post_effect_color = {a = 80, r = 127, g = 127, b = 127},
  125. drowning = 1,
  126. groups = {immovable=1, gas=1, flammable=3},
  127. on_construct = function(...)
  128. return breath.on_construct(...)
  129. end,
  130. on_destruct = function(...)
  131. return breath.on_destruct(...)
  132. end,
  133. on_timer = function(...)
  134. return breath.on_timer(...)
  135. end,
  136. -- Player should not be able to obtain node.
  137. on_collapse_to_entity = function(pos, node)
  138. -- Do nothing.
  139. end,
  140. -- Player should not be able to obtain node.
  141. on_finish_collapse = function(pos, node)
  142. minetest.remove_node(pos)
  143. end,
  144. })
  145. local c = "breath:core"
  146. local f = breath.modpath .. "/breath.lua"
  147. reload.register_file(c, f, false)
  148. breath.run_once = true
  149. end