spawner.lua 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. local random = math.random
  2. local pi = math.pi
  3. local node_ok = mobs.node_ok
  4. local attempt_spawn_mob = function(pos, moblimit, mobrange, daynight, miny, maxy, name, minl, maxl, prange_min, prange_max, minc, maxc, spawn_height, absolute_mob_limit)
  5. -- If toggle set to nil then ignore day/night check.
  6. if daynight ~= nil then
  7. local tod = (minetest.get_timeofday() or 0) * 24000
  8. if tod > 4500 and tod < 19500 then
  9. -- Daylight, but mob wants night.
  10. if daynight == false then
  11. return
  12. end
  13. else
  14. -- Night time but mob wants day.
  15. if daynight == true then
  16. return
  17. end
  18. end
  19. end
  20. -- Spawn above node.
  21. pos.y = pos.y + 1
  22. -- Check if height levels are ok.
  23. if pos.y > maxy or pos.y < miny then return end
  24. -- Check if light level is ok.
  25. local light = minetest.get_node_light(pos)
  26. if not light or light > maxl or light < minl then return end
  27. -- Count mobs in mob range.
  28. local mobcount = 0
  29. local absmobcount = 0
  30. local objs = minetest.get_objects_inside_radius(pos, mobrange)
  31. for n = 1, #objs do
  32. local obj = objs[n]
  33. if not obj:is_player() then
  34. local ref = obj:get_luaentity()
  35. if ref then
  36. if ref.name == name then mobcount = mobcount + 1 end
  37. if ref.mob then absmobcount = absmobcount + 1 end
  38. end
  39. end
  40. end
  41. -- Don't spawn mob if there are already too many entities in area.
  42. if mobcount > moblimit then return end
  43. if absmobcount > absolute_mob_limit then return end
  44. -- Find nearest player.
  45. local neardist = prange_max+1
  46. local players = minetest.get_connected_players()
  47. for n = 1, #players do
  48. local ref = players[n]
  49. local p = ref:getpos()
  50. local d = vector.distance(pos, p)
  51. if d < neardist then neardist = d end
  52. end
  53. -- Don't spawn if too near player or if too far.
  54. if neardist < prange_min or neardist > prange_max then return end
  55. -- Are we spawning inside solid nodes?
  56. for i = 1, spawn_height, 1 do
  57. local p = {x=pos.x, y=(pos.y+i)-1, z=pos.z}
  58. local ndef = minetest.reg_ns_nodes[node_ok(p).name]
  59. if not ndef or ndef.walkable == true then return end
  60. end
  61. -- Spawn mob half block higher than ground.
  62. pos.y = pos.y + 0.5
  63. for i = minc, maxc do
  64. local mob = minetest.add_entity(pos, name)
  65. if mob then
  66. mob:setyaw((random(0, 360) - 180) / 180 * pi)
  67. end
  68. end
  69. end
  70. mobs.register_spawn = function(def)
  71. -- The new mob spawning registration function.
  72. -- Mobs are spawned with a special algorithm that doesn't use ABMs.
  73. mob_spawn.register_spawn(def)
  74. end
  75. -- Kept because certain mobs (like the griefer) NEED AMB spawn behavior.
  76. mobs.register_spawn_abm = function(def)
  77. -- Name of mob.
  78. local name = def.name
  79. -- Min/max light allowed.
  80. local minl = def.min_light or 0
  81. local maxl = def.max_light or default.LIGHT_MAX
  82. -- Min/max elevations.
  83. local miny = def.min_height or -31000
  84. local maxy = def.max_height or 31000
  85. -- Min/max amount of mobs to spawn.
  86. local minc = def.min_count or 1
  87. local maxc = def.max_count or 1
  88. -- Mob count limit and scanning range.
  89. local moblimit = def.mob_limit or 3
  90. local mobrange = def.mob_range or 20
  91. local absolute_mob_limit = def.absolute_mob_limit or 5
  92. -- True to spawn only at daytime. False to spawn only at night.
  93. local daynight = def.day_toggle -- May be nil.
  94. -- Min/max allowed ranges to nearest player.
  95. local prange_min = def.player_min_range or 6
  96. local prange_max = def.player_max_range or 20
  97. -- Height of mob. Don't spawn if not enough head-space.
  98. local spawn_height = def.spawn_height or 2
  99. minetest.register_abm({
  100. label = "Mob Spawner",
  101. nodenames = def.nodes,
  102. neighbors = {"air"},
  103. interval = def.interval * default.ABM_TIMER_MULTIPLIER,
  104. chance = def.chance * default.ABM_CHANCE_MULTIPLIER,
  105. catch_up = false,
  106. action = function(pos)
  107. -- Is sending things as arguments instead of a table any faster?
  108. attempt_spawn_mob(pos, moblimit, mobrange, daynight, miny, maxy, name, minl, maxl, prange_min, prange_max, minc, maxc, spawn_height, absolute_mob_limit)
  109. end
  110. })
  111. end