Tweak chains selbox
[minetest_hades/hades_revisited.git] / mods / mobs / spawner.lua
blobfacd4a945397a71ee61bb1ac0706c0e4c68a4285
2 local MP = minetest.get_modpath(minetest.get_current_modname())
3 local S = minetest.get_translator("mobs")
5 -- mob spawner
7 local spawner_default = "mobs_hades:mutant 0 15 0 0"
9 minetest.register_node("mobs:spawner", {
10 tiles = {"mob_spawner.png"},
11 drawtype = "glasslike",
12 paramtype = "light",
13 walkable = true,
14 description = S("Mob Spawner"),
15 _tt_help = S("Periodically spawns mobs around it"),
16 groups = {cracky = 1},
18 on_construct = function(pos)
20 local meta = minetest.get_meta(pos)
22 -- text entry formspec
23 meta:set_string("formspec",
24 "field[text;" .. minetest.formspec_escape(S("Mob MinLight MaxLight Amount PlayerDist")) .. ";${command}]")
25 meta:set_string("infotext", S("Spawner Not Active (enter settings)"))
26 meta:set_string("command", spawner_default)
27 end,
29 on_right_click = function(pos, placer)
31 if minetest.is_protected(pos, placer:get_player_name()) then
32 return
33 end
34 end,
36 on_receive_fields = function(pos, formname, fields, sender)
38 if not fields.text or fields.text == "" then
39 return
40 end
42 local meta = minetest.get_meta(pos)
43 local comm = fields.text:split(" ")
44 local name = sender:get_player_name()
46 if minetest.is_protected(pos, name) then
47 minetest.record_protection_violation(pos, name)
48 return
49 end
51 local mob = comm[1] -- mob to spawn
52 local mlig = tonumber(comm[2]) -- min light
53 local xlig = tonumber(comm[3]) -- max light
54 local num = tonumber(comm[4]) -- total mobs in area
55 local pla = tonumber(comm[5]) -- player distance (0 to disable)
56 local yof = tonumber(comm[6]) or 0 -- Y offset to spawn mob
58 if mob and mob ~= "" and mobs.spawning_mobs[mob] == true
59 and num and num >= 0 and num <= 10
60 and mlig and mlig >= 0 and mlig <= 15
61 and xlig and xlig >= 0 and xlig <= 15
62 and pla and pla >=0 and pla <= 20
63 and yof and yof > -10 and yof < 10 then
65 meta:set_string("command", fields.text)
66 meta:set_string("infotext", S("Spawner Active (@1)", mob))
68 else
69 minetest.chat_send_player(name, S("Mob Spawner settings failed!"))
70 minetest.chat_send_player(name,
71 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]”"))
72 end
73 end,
77 local max_per_block = tonumber(minetest.settings:get("max_objects_per_block") or 99)
79 -- spawner abm
80 minetest.register_abm({
81 label = "Mob spawner node",
82 nodenames = {"mobs:spawner"},
83 interval = 10,
84 chance = 4,
85 catch_up = false,
87 action = function(pos, node, active_object_count, active_object_count_wider)
89 -- return if too many entities already
90 if active_object_count_wider >= max_per_block then
91 return
92 end
94 -- get meta and command
95 local meta = minetest.get_meta(pos)
96 local comm = meta:get_string("command"):split(" ")
98 -- get settings from command
99 local mob = comm[1]
100 local mlig = tonumber(comm[2])
101 local xlig = tonumber(comm[3])
102 local num = tonumber(comm[4])
103 local pla = tonumber(comm[5]) or 0
104 local yof = tonumber(comm[6]) or 0
106 -- if amount is 0 then do nothing
107 if num == 0 then
108 return
111 -- are we spawning a registered mob?
112 if not mobs.spawning_mobs[mob] then
113 --print ("--- mob doesn't exist", mob)
114 return
117 -- check objects inside 9x9 area around spawner
118 local objs = minetest.get_objects_inside_radius(pos, 9)
119 local count = 0
120 local ent = nil
122 -- count mob objects of same type in area
123 for k, obj in ipairs(objs) do
125 ent = obj:get_luaentity()
127 if ent and ent.name and ent.name == mob then
128 count = count + 1
132 -- is there too many of same type?
133 if count >= num then
134 return
137 -- spawn mob if player detected and in range
138 if pla > 0 then
140 local in_range = 0
141 local objs = minetest.get_objects_inside_radius(pos, pla)
143 for _,oir in pairs(objs) do
145 if oir:is_player() then
147 in_range = 1
149 break
153 -- player not found
154 if in_range == 0 then
155 return
159 -- find air blocks within 5 nodes of spawner
160 local air = minetest.find_nodes_in_area(
161 {x = pos.x - 5, y = pos.y + yof, z = pos.z - 5},
162 {x = pos.x + 5, y = pos.y + yof, z = pos.z + 5},
163 {"air"})
165 -- spawn in random air block
166 if air and #air > 0 then
168 local pos2 = air[math.random(#air)]
169 local lig = minetest.get_node_light(pos2) or 0
171 pos2.y = pos2.y + 0.5
173 -- only if light levels are within range
174 if lig >= mlig and lig <= xlig
175 and minetest.registered_entities[mob] then
176 minetest.add_entity(pos2, mob)