spawner.lua 4.1 KB

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