Add creatura.register_spawn_item

This commit is contained in:
ElCeejo 2022-05-26 15:27:26 -07:00 committed by GitHub
parent 962ea68104
commit a7af111180
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -7,13 +7,13 @@ creatura.registered_mob_spawns = {}
local walkable_nodes = {} local walkable_nodes = {}
minetest.register_on_mods_loaded(function() minetest.register_on_mods_loaded(function()
for name in pairs(minetest.registered_nodes) do for name in pairs(minetest.registered_nodes) do
if name ~= "air" and name ~= "ignore" then if name ~= "air" and name ~= "ignore" then
if minetest.registered_nodes[name].walkable then if minetest.registered_nodes[name].walkable then
table.insert(walkable_nodes, name) table.insert(walkable_nodes, name)
end end
end end
end end
end) end)
-- Math -- -- Math --
@ -21,117 +21,150 @@ end)
local random = math.random local random = math.random
local function vec_raise(v, n) local function vec_raise(v, n)
return {x = v.x, y = v.y + n, z = v.z} return {x = v.x, y = v.y + n, z = v.z}
end end
-- Registration -- -- Registration --
local creative = minetest.settings:get_bool("creative_mode")
local function format_name(str) local function format_name(str)
if str then if str then
if str:match(":") then str = str:split(":")[2] end if str:match(":") then str = str:split(":")[2] end
return (string.gsub(" " .. str, "%W%l", string.upper):sub(2):gsub("_", " ")) return (string.gsub(" " .. str, "%W%l", string.upper):sub(2):gsub("_", " "))
end end
end end
function creatura.register_spawn_egg(name, col1, col2, inventory_image) function creatura.register_spawn_egg(name, col1, col2, inventory_image) -- deprecated
if col1 and col2 then if col1 and col2 then
local base = "(creatura_spawning_crystal.png^[multiply:#" .. col1 .. ")" local base = "(creatura_spawning_crystal.png^[multiply:#" .. col1 .. ")"
local spots = "(creatura_spawning_crystal_overlay.png^[multiply:#" .. col2 .. ")" local spots = "(creatura_spawning_crystal_overlay.png^[multiply:#" .. col2 .. ")"
inventory_image = base .. "^" .. spots inventory_image = base .. "^" .. spots
end end
local mod_name = name:split(":")[1] local mod_name = name:split(":")[1]
local mob_name = name:split(":")[2] local mob_name = name:split(":")[2]
minetest.register_craftitem(mod_name .. ":spawn_" .. mob_name, { minetest.register_craftitem(mod_name .. ":spawn_" .. mob_name, {
description = "Spawn " .. format_name(name), description = "Spawn " .. format_name(name),
inventory_image = inventory_image, inventory_image = inventory_image,
stack_max = 99, stack_max = 99,
on_place = function(itemstack, _, pointed_thing) on_place = function(itemstack, _, pointed_thing)
local mobdef = minetest.registered_entities[name] local mobdef = minetest.registered_entities[name]
local spawn_offset = math.abs(mobdef.collisionbox[2]) local spawn_offset = math.abs(mobdef.collisionbox[2])
local pos = minetest.get_pointed_thing_position(pointed_thing, true) local pos = minetest.get_pointed_thing_position(pointed_thing, true)
pos.y = (pos.y - 0.49) + spawn_offset pos.y = (pos.y - 0.49) + spawn_offset
local object = minetest.add_entity(pos, name) local object = minetest.add_entity(pos, name)
if object then if object then
object:set_yaw(math.random(1, 6)) object:set_yaw(math.random(1, 6))
object:get_luaentity().last_yaw = object:get_yaw() object:get_luaentity().last_yaw = object:get_yaw()
end end
if not creative then if not creative then
itemstack:take_item() itemstack:take_item()
return itemstack return itemstack
end end
end end
}) })
end
function creatura.register_spawn_item(name, def)
if not def.inventory_image
and def.col1 and def.col2 then
local base = "(creatura_spawning_crystal.png^[multiply:#" .. def.col1 .. ")"
local spots = "(creatura_spawning_crystal_overlay.png^[multiply:#" .. def.col2 .. ")"
inventory_image = base .. "^" .. spots
end
local mod_name = name:split(":")[1]
local mob_name = name:split(":")[2]
minetest.register_craftitem(mod_name .. ":spawn_" .. mob_name, {
description = def.description or "Spawn " .. format_name(name),
inventory_image = def.inventory_image or inventory_image,
stack_max = 99,
on_place = function(itemstack, _, pointed_thing)
local mobdef = minetest.registered_entities[name]
local spawn_offset = math.abs(mobdef.collisionbox[2])
local pos = minetest.get_pointed_thing_position(pointed_thing, true)
pos.y = (pos.y - 0.49) + spawn_offset
local object = minetest.add_entity(pos, name)
if object then
object:set_yaw(math.random(1, 6))
object:get_luaentity().last_yaw = object:get_yaw()
end
if not creative then
itemstack:take_item()
return itemstack
end
end
})
end end
function creatura.register_mob_spawn(name, def) function creatura.register_mob_spawn(name, def)
local spawn = { local spawn = {
chance = def.chance or 5, chance = def.chance or 5,
min_height = def.min_height or 0, min_height = def.min_height or 0,
max_height = def.max_height or 128, max_height = def.max_height or 128,
min_light = def.min_light or 6, min_light = def.min_light or 6,
max_light = def.max_light or 15, max_light = def.max_light or 15,
min_group = def.min_group or 1, min_group = def.min_group or 1,
max_group = def.max_group or 4, max_group = def.max_group or 4,
nodes = def.nodes or nil, nodes = def.nodes or nil,
biomes = def.biomes or nil, biomes = def.biomes or nil,
spawn_cluster = def.spawn_cluster or false, spawn_cluster = def.spawn_cluster or false,
spawn_in_nodes = def.spawn_in_nodes or false, spawn_in_nodes = def.spawn_in_nodes or false,
spawn_cap = def.spawn_cap or 5, spawn_cap = def.spawn_cap or 5,
send_debug = def.send_debug or false send_debug = def.send_debug or false
} }
creatura.registered_mob_spawns[name] = spawn creatura.registered_mob_spawns[name] = spawn
end end
creatura.registered_on_spawns = {} creatura.registered_on_spawns = {}
function creatura.register_on_spawn(name, func) function creatura.register_on_spawn(name, func)
if not creatura.registered_on_spawns[name] then if not creatura.registered_on_spawns[name] then
creatura.registered_on_spawns[name] = {} creatura.registered_on_spawns[name] = {}
end end
table.insert(creatura.registered_on_spawns[name], func) table.insert(creatura.registered_on_spawns[name], func)
end end
-- Utility Functions -- -- Utility Functions --
function is_value_in_table(tbl, val) function is_value_in_table(tbl, val)
for _, v in pairs(tbl) do for _, v in pairs(tbl) do
if v == val then if v == val then
return true return true
end end
end end
return false return false
end end
function get_biome_name(pos) function get_biome_name(pos)
if not pos then return end if not pos then return end
return minetest.get_biome_name(minetest.get_biome_data(pos).biome) return minetest.get_biome_name(minetest.get_biome_data(pos).biome)
end end
function get_ground_level(pos) function get_ground_level(pos)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
local node_def = minetest.registered_nodes[node.name] local node_def = minetest.registered_nodes[node.name]
local height = 0 local height = 0
while node_def.walkable while node_def.walkable
and height < 4 do and height < 4 do
height = height + 1 height = height + 1
node = minetest.get_node(vec_raise(pos, height)) node = minetest.get_node(vec_raise(pos, height))
node_def = minetest.registered_nodes[node.name] node_def = minetest.registered_nodes[node.name]
end end
return vec_raise(pos, height) return vec_raise(pos, height)
end end
local function get_spawnable_mobs(pos) local function get_spawnable_mobs(pos)
local biome = get_biome_name(pos) local biome = get_biome_name(pos)
if not biome then biome = "_nil" end if not biome then biome = "_nil" end
local spawnable = {} local spawnable = {}
for k, v in pairs(creatura.registered_mob_spawns) do for k, v in pairs(creatura.registered_mob_spawns) do
if not v.biomes if not v.biomes
or is_value_in_table(v.biomes, biome) then or is_value_in_table(v.biomes, biome) then
table.insert(spawnable, k) table.insert(spawnable, k)
end end
end end
return spawnable return spawnable
end end
-- Spawning Function -- -- Spawning Function --
@ -142,96 +175,96 @@ local min_spawn_radius = 32
local max_spawn_radius = 128 local max_spawn_radius = 128
function execute_spawns(player) function execute_spawns(player)
if not player:get_pos() then return end if not player:get_pos() then return end
local pos = player:get_pos() local pos = player:get_pos()
local spawn_pos_center = { local spawn_pos_center = {
x = pos.x + random(-max_spawn_radius, max_spawn_radius), x = pos.x + random(-max_spawn_radius, max_spawn_radius),
y = pos.y, y = pos.y,
z = pos.z + random(-max_spawn_radius, max_spawn_radius) z = pos.z + random(-max_spawn_radius, max_spawn_radius)
} }
local spawnable_mobs = get_spawnable_mobs(spawn_pos_center) local spawnable_mobs = get_spawnable_mobs(spawn_pos_center)
if spawnable_mobs if spawnable_mobs
and #spawnable_mobs > 0 then and #spawnable_mobs > 0 then
local mob = spawnable_mobs[random(#spawnable_mobs)] local mob = spawnable_mobs[random(#spawnable_mobs)]
local spawn = creatura.registered_mob_spawns[mob] local spawn = creatura.registered_mob_spawns[mob]
if not spawn if not spawn
or random(spawn.chance) > 1 then return end or random(spawn.chance) > 1 then return end
-- Spawn cap check -- Spawn cap check
local objects = minetest.get_objects_inside_radius(pos, max_spawn_radius) local objects = minetest.get_objects_inside_radius(pos, max_spawn_radius)
local object_count = 0 local object_count = 0
for _, object in ipairs(objects) do for _, object in ipairs(objects) do
if creatura.is_alive(object) if creatura.is_alive(object)
and not object:is_player() and not object:is_player()
and object:get_luaentity().name == mob then and object:get_luaentity().name == mob then
object_count = object_count + 1 object_count = object_count + 1
end end
end end
if object_count >= spawn.spawn_cap then if object_count >= spawn.spawn_cap then
return return
end end
local index_func local index_func
if spawn.spawn_in_nodes then if spawn.spawn_in_nodes then
index_func = minetest.find_nodes_in_area index_func = minetest.find_nodes_in_area
else else
index_func = minetest.find_nodes_in_area_under_air index_func = minetest.find_nodes_in_area_under_air
end end
local spawn_on = spawn.nodes or walkable_nodes local spawn_on = spawn.nodes or walkable_nodes
if type(spawn_on) == "string" then if type(spawn_on) == "string" then
spawn_on = {spawn_on} spawn_on = {spawn_on}
end end
local spawn_y_array = index_func(vec_raise(spawn_pos_center, -max_spawn_radius), vec_raise(spawn_pos_center, max_spawn_radius), spawn_on) local spawn_y_array = index_func(vec_raise(spawn_pos_center, -max_spawn_radius), vec_raise(spawn_pos_center, max_spawn_radius), spawn_on)
if spawn_y_array[1] then if spawn_y_array[1] then
local spawn_pos = spawn_y_array[1] local spawn_pos = spawn_y_array[1]
local dist = vector.distance(pos, spawn_pos) local dist = vector.distance(pos, spawn_pos)
if dist < min_spawn_radius or dist > max_spawn_radius then if dist < min_spawn_radius or dist > max_spawn_radius then
return return
end end
if spawn_pos.y > spawn.max_height if spawn_pos.y > spawn.max_height
or spawn_pos.y < spawn.min_height then or spawn_pos.y < spawn.min_height then
return return
end end
if not spawn.spawn_in_nodes then if not spawn.spawn_in_nodes then
spawn_pos = vec_raise(spawn_pos, 1) spawn_pos = vec_raise(spawn_pos, 1)
end end
local light = minetest.get_node_light(spawn_pos) or 7 local light = minetest.get_node_light(spawn_pos) or 7
if light > spawn.max_light if light > spawn.max_light
or light < spawn.min_light then or light < spawn.min_light then
return return
end end
local group_size = random(spawn.min_group, spawn.max_group) local group_size = random(spawn.min_group, spawn.max_group)
if spawn.spawn_cluster then if spawn.spawn_cluster then
minetest.add_node(spawn_pos, {name = "creatura:spawn_node"}) minetest.add_node(spawn_pos, {name = "creatura:spawn_node"})
local meta = minetest.get_meta(spawn_pos) local meta = minetest.get_meta(spawn_pos)
meta:set_string("mob", mob) meta:set_string("mob", mob)
meta:set_int("cluster", group_size) meta:set_int("cluster", group_size)
else else
for _ = 1, group_size do for _ = 1, group_size do
spawn_pos = { spawn_pos = {
x = spawn_pos.x + random(-3, 3), x = spawn_pos.x + random(-3, 3),
y = spawn_pos.y, y = spawn_pos.y,
z = spawn_pos.z + random(-3, 3) z = spawn_pos.z + random(-3, 3)
} }
spawn_pos = get_ground_level(spawn_pos) spawn_pos = get_ground_level(spawn_pos)
minetest.add_node(spawn_pos, {name = "creatura:spawn_node"}) minetest.add_node(spawn_pos, {name = "creatura:spawn_node"})
local meta = minetest.get_meta(spawn_pos) local meta = minetest.get_meta(spawn_pos)
meta:set_string("mob", mob) meta:set_string("mob", mob)
end end
end end
if spawn.send_debug then if spawn.send_debug then
minetest.chat_send_all(mob .. " spawned at " .. minetest.pos_to_string(spawn_pos)) minetest.chat_send_all(mob .. " spawned at " .. minetest.pos_to_string(spawn_pos))
end end
end end
end end
end end
local spawn_step = tonumber(minetest.settings:get("creatura_spawn_step")) or 15 local spawn_step = tonumber(minetest.settings:get("creatura_spawn_step")) or 15
@ -239,77 +272,77 @@ local spawn_step = tonumber(minetest.settings:get("creatura_spawn_step")) or 15
local spawn_tick = 0 local spawn_tick = 0
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
spawn_tick = spawn_tick - dtime spawn_tick = spawn_tick - dtime
if spawn_tick <= 0 then if spawn_tick <= 0 then
for _, player in ipairs(minetest.get_connected_players()) do for _, player in ipairs(minetest.get_connected_players()) do
execute_spawns(player) execute_spawns(player)
end end
spawn_tick = spawn_step spawn_tick = spawn_step
end end
end) end)
-- Node -- -- Node --
minetest.register_node("creatura:spawn_node", { minetest.register_node("creatura:spawn_node", {
drawtype = "airlike", drawtype = "airlike",
groups = {not_in_creative_inventory = 1} groups = {not_in_creative_inventory = 1}
}) })
local spawn_interval = tonumber(minetest.settings:get("creatura_spawn_interval")) or 10 local spawn_interval = tonumber(minetest.settings:get("creatura_spawn_interval")) or 10
minetest.register_abm({ minetest.register_abm({
label = "Creatura Spawning", label = "Creatura Spawning",
nodenames = {"creatura:spawn_node"}, nodenames = {"creatura:spawn_node"},
interval = spawn_interval, interval = spawn_interval,
chance = 1, chance = 1,
action = function(pos) action = function(pos)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local name = meta:get_string("mob") local name = meta:get_string("mob")
local amount = meta:get_int("cluster") local amount = meta:get_int("cluster")
local obj local obj
if amount > 0 then if amount > 0 then
for i = 1, amount do for i = 1, amount do
obj = minetest.add_entity(pos, name) obj = minetest.add_entity(pos, name)
end end
else else
obj = minetest.add_entity(pos, name) obj = minetest.add_entity(pos, name)
end end
minetest.remove_node(pos) minetest.remove_node(pos)
if obj if obj
and creatura.registered_on_spawns[name] and creatura.registered_on_spawns[name]
and #creatura.registered_on_spawns[name] > 0 then and #creatura.registered_on_spawns[name] > 0 then
for i = 1, #creatura.registered_on_spawns[name] do for i = 1, #creatura.registered_on_spawns[name] do
local func = creatura.registered_on_spawns[name][i] local func = creatura.registered_on_spawns[name][i]
func(obj:get_luaentity(), pos) func(obj:get_luaentity(), pos)
end end
end end
end, end,
}) })
--[[minetest.register_lbm({ --[[minetest.register_lbm({
name = "creatura:spawning", name = "creatura:spawning",
nodenames = {"creatura:spawn_node"}, nodenames = {"creatura:spawn_node"},
run_at_every_load = true, run_at_every_load = true,
action = function(pos) action = function(pos)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local name = meta:get_string("mob") local name = meta:get_string("mob")
local amount = meta:get_int("cluster") local amount = meta:get_int("cluster")
local obj local obj
if amount > 0 then if amount > 0 then
for i = 1, amount do for i = 1, amount do
obj = minetest.add_entity(pos, name) obj = minetest.add_entity(pos, name)
end end
else else
obj = minetest.add_entity(pos, name) obj = minetest.add_entity(pos, name)
end end
minetest.remove_node(pos) minetest.remove_node(pos)
if obj if obj
and creatura.registered_on_spawns[name] and creatura.registered_on_spawns[name]
and #creatura.registered_on_spawns[name] > 0 then and #creatura.registered_on_spawns[name] > 0 then
for i = 1, #creatura.registered_on_spawns[name] do for i = 1, #creatura.registered_on_spawns[name] do
local func = creatura.registered_on_spawns[name][i] local func = creatura.registered_on_spawns[name][i]
func(obj:get_luaentity(), pos) func(obj:get_luaentity(), pos)
end end
end end
end, end,
})]] })]]