2 local MP
= minetest
.get_modpath(minetest
.get_current_modname())
3 local S
= minetest
.get_translator("mobs")
7 local spawner_default
= "mobs_animal:pumba 10 15 0 0"
9 minetest
.register_node("mobs:spawner", {
10 tiles
= {"mob_spawner.png"},
11 drawtype
= "glasslike",
14 description
= S("Mob Spawner"),
15 groups
= {cracky
= 1},
17 on_construct
= function(pos
)
19 local meta
= minetest
.get_meta(pos
)
21 -- text entry formspec
22 meta
:set_string("formspec",
23 "field[text;" .. minetest
.formspec_escape(S("Mob MinLight MaxLight Amount PlayerDist")) .. ";${command}]")
24 meta
:set_string("infotext", S("Spawner Not Active (enter settings)"))
25 meta
:set_string("command", spawner_default
)
28 on_right_click
= function(pos
, placer
)
30 if minetest
.is_protected(pos
, placer
:get_player_name()) then
35 on_receive_fields
= function(pos
, formname
, fields
, sender
)
37 if not fields
.text
or fields
.text
== "" then
41 local meta
= minetest
.get_meta(pos
)
42 local comm
= fields
.text
:split(" ")
43 local name
= sender
:get_player_name()
45 if minetest
.is_protected(pos
, name
) then
46 minetest
.record_protection_violation(pos
, name
)
50 local mob
= comm
[1] -- mob to spawn
51 local mlig
= tonumber(comm
[2]) -- min light
52 local xlig
= tonumber(comm
[3]) -- max light
53 local num
= tonumber(comm
[4]) -- total mobs in area
54 local pla
= tonumber(comm
[5]) -- player distance (0 to disable)
55 local yof
= tonumber(comm
[6]) or 0 -- Y offset to spawn mob
57 if mob
and mob
~= "" and mobs
.spawning_mobs
[mob
] == true
58 and num
and num
>= 0 and num
<= 10
59 and mlig
and mlig
>= 0 and mlig
<= 15
60 and xlig
and xlig
>= 0 and xlig
<= 15
61 and pla
and pla
>=0 and pla
<= 20
62 and yof
and yof
> -10 and yof
< 10 then
64 meta
:set_string("command", fields
.text
)
65 meta
:set_string("infotext", S("Spawner Active (@1)", mob
))
68 minetest
.chat_send_player(name
, S("Mob Spawner settings failed!"))
69 minetest
.chat_send_player(name
,
70 S("Syntax: “name min_light[0-14] max_light[0-14] max_mobs_in_area[0 to disable] distance[1-20] y_offset[-10 to 10]”"))
76 local max_per_block
= tonumber(minetest
.settings
:get("max_objects_per_block") or 99)
79 minetest
.register_abm({
80 label
= "Mob spawner node",
81 nodenames
= {"mobs:spawner"},
86 action
= function(pos
, node
, active_object_count
, active_object_count_wider
)
88 -- return if too many entities already
89 if active_object_count_wider
>= max_per_block
then
93 -- get meta and command
94 local meta
= minetest
.get_meta(pos
)
95 local comm
= meta
:get_string("command"):split(" ")
97 -- get settings from command
99 local mlig
= tonumber(comm
[2])
100 local xlig
= tonumber(comm
[3])
101 local num
= tonumber(comm
[4])
102 local pla
= tonumber(comm
[5]) or 0
103 local yof
= tonumber(comm
[6]) or 0
105 -- if amount is 0 then do nothing
110 -- are we spawning a registered mob?
111 if not mobs
.spawning_mobs
[mob
] then
112 --print ("--- mob doesn't exist", mob)
116 -- check objects inside 9x9 area around spawner
117 local objs
= minetest
.get_objects_inside_radius(pos
, 9)
121 -- count mob objects of same type in area
122 for k
, obj
in ipairs(objs
) do
124 ent
= obj
:get_luaentity()
126 if ent
and ent
.name
and ent
.name
== mob
then
131 -- is there too many of same type?
136 -- spawn mob if player detected and in range
140 local objs
= minetest
.get_objects_inside_radius(pos
, pla
)
142 for _
,oir
in pairs(objs
) do
144 if oir
:is_player() then
153 if in_range
== 0 then
158 -- find air blocks within 5 nodes of spawner
159 local air
= minetest
.find_nodes_in_area(
160 {x
= pos
.x
- 5, y
= pos
.y
+ yof
, z
= pos
.z
- 5},
161 {x
= pos
.x
+ 5, y
= pos
.y
+ yof
, z
= pos
.z
+ 5},
164 -- spawn in random air block
165 if air
and #air
> 0 then
167 local pos2
= air
[math
.random(#air
)]
168 local lig
= minetest
.get_node_light(pos2
) or 0
170 pos2
.y
= pos2
.y
+ 0.5
172 -- only if light levels are within range
173 if lig
>= mlig
and lig
<= xlig
174 and minetest
.registered_entities
[mob
] then
175 minetest
.add_entity(pos2
, mob
)