mirror of
https://github.com/ElCeejo/creatura.git
synced 2025-04-30 05:41:46 -04:00
Add Mapgen Spawning, Add ABM Spawning
This commit is contained in:
parent
78d16d485b
commit
6a0b35532c
3 changed files with 247 additions and 24 deletions
|
@ -795,7 +795,8 @@ function mob:activate(staticdata, dtime)
|
||||||
self._despawn = self:recall("_despawn") or false
|
self._despawn = self:recall("_despawn") or false
|
||||||
|
|
||||||
if self._despawn
|
if self._despawn
|
||||||
and self.despawn_after then
|
and self.despawn_after
|
||||||
|
and self.object then
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -986,6 +987,7 @@ end
|
||||||
local function water_physics(self, pos, node)
|
local function water_physics(self, pos, node)
|
||||||
-- Props
|
-- Props
|
||||||
local gravity = self._movement_data.gravity
|
local gravity = self._movement_data.gravity
|
||||||
|
local height = self.height
|
||||||
-- Vectors
|
-- Vectors
|
||||||
pos.y = pos.y + 0.01
|
pos.y = pos.y + 0.01
|
||||||
if minetest.get_item_group(node.name, "liquid") < 1 then
|
if minetest.get_item_group(node.name, "liquid") < 1 then
|
||||||
|
@ -1007,7 +1009,7 @@ local function water_physics(self, pos, node)
|
||||||
})
|
})
|
||||||
local center = {
|
local center = {
|
||||||
x = pos.x,
|
x = pos.x,
|
||||||
y = pos.y + self.height * 0.5,
|
y = pos.y + height * 0.5,
|
||||||
z = pos.z
|
z = pos.z
|
||||||
}
|
}
|
||||||
if minetest.get_item_group(minetest.get_node(center).name, "liquid") < 1 then
|
if minetest.get_item_group(minetest.get_node(center).name, "liquid") < 1 then
|
||||||
|
@ -1016,7 +1018,7 @@ local function water_physics(self, pos, node)
|
||||||
-- Calculate Physics
|
-- Calculate Physics
|
||||||
local vel = self.object:get_velocity()
|
local vel = self.object:get_velocity()
|
||||||
local bouyancy_x = self.bouyancy_multiplier or 1
|
local bouyancy_x = self.bouyancy_multiplier or 1
|
||||||
local bouyancy = (abs(gravity * 0.5) / self.height) * bouyancy_x
|
local bouyancy = (abs(gravity * 0.5) / height) * bouyancy_x
|
||||||
if bouyancy > 0 then
|
if bouyancy > 0 then
|
||||||
if bouyancy > 4.9 then bouyancy = 4.9 end
|
if bouyancy > 4.9 then bouyancy = 4.9 end
|
||||||
self.object:set_acceleration({
|
self.object:set_acceleration({
|
||||||
|
|
|
@ -5,13 +5,19 @@
|
||||||
creatura_step_type (Step Type) enum simple simple,fancy
|
creatura_step_type (Step Type) enum simple simple,fancy
|
||||||
|
|
||||||
# How often (in seconds) the spawn ABM is called
|
# How often (in seconds) the spawn ABM is called
|
||||||
creatura_spawn_interval (Spawn ABM Interval) float 10
|
creatura_spawn_interval (Spawn ABM Interval) int 10
|
||||||
|
|
||||||
# Time (in seconds) between spawn steps
|
# Time (in seconds) between spawn steps
|
||||||
creatura_spawn_step (Spawn Step Interval) float 15
|
creatura_spawn_step (Spawn Step Interval) int 15
|
||||||
|
|
||||||
|
# Allows Mobs to spawn during chunk generation (If dependent mods use spawn_on_gen)
|
||||||
|
creatura_mapgen_spawning (Mapgen Spawning) bool true
|
||||||
|
|
||||||
|
# How many chunks are generated before a Mob can spawn
|
||||||
|
creatura_mapgen_spawn_interval (Mapgen Spawning Interval) int 5
|
||||||
|
|
||||||
# Allotted time (in μs) per step for A* pathfinding (lower means less lag but slower pathfinding)
|
# Allotted time (in μs) per step for A* pathfinding (lower means less lag but slower pathfinding)
|
||||||
creatura_a_star_alloted_time (A* Pathfinding Alloted time per step) float 500
|
creatura_a_star_alloted_time (A* Pathfinding Alloted time per step) int 500
|
||||||
|
|
||||||
# Allotted time (in μs) per step for Theta* pathfinding (lower means less lag but slower pathfinding)
|
# Allotted time (in μs) per step for Theta* pathfinding (lower means less lag but slower pathfinding)
|
||||||
creatura_theta_star_alloted_time (Theta* Pathfinding Alloted time per step) float 700
|
creatura_theta_star_alloted_time (Theta* Pathfinding Alloted time per step) int 700
|
249
spawning.lua
249
spawning.lua
|
@ -125,6 +125,7 @@ function creatura.register_mob_spawn(name, def)
|
||||||
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_on_gen = def.spawn_on_gen 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
|
||||||
|
@ -141,10 +142,9 @@ function creatura.register_on_spawn(name, func)
|
||||||
table.insert(creatura.registered_on_spawns[name], func)
|
table.insert(creatura.registered_on_spawns[name], func)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Utility Functions --
|
-- Utility Functions --
|
||||||
|
|
||||||
local function is_value_in_table(tbl, val)
|
local function table_contains(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
|
||||||
|
@ -153,22 +153,35 @@ local function is_value_in_table(tbl, val)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_biome_name(pos)
|
local function get_spawnable_mobs(pos, mapgen)
|
||||||
if not pos then return end
|
local biome = minetest.get_biome_name(minetest.get_biome_data(pos).biome)
|
||||||
return minetest.get_biome_name(minetest.get_biome_data(pos).biome)
|
if not biome then return end
|
||||||
end
|
local mobs = {}
|
||||||
|
for mob, data in pairs(creatura.registered_mob_spawns) do
|
||||||
local function get_spawnable_mobs(pos)
|
local biome_valid = data.biomes and table_contains(data.biomes, biome)
|
||||||
local biome = get_biome_name(pos)
|
if (biome_valid
|
||||||
if not biome then biome = "_nil" end
|
or data.nodes)
|
||||||
local spawnable = {}
|
and (not mapgen
|
||||||
for k, v in pairs(creatura.registered_mob_spawns) do
|
or data.spawn_on_gen)
|
||||||
if not v.biomes
|
and not data.spawn_in_nodes then
|
||||||
or is_value_in_table(v.biomes, biome) then
|
table.insert(mobs, mob)
|
||||||
table.insert(spawnable, k)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return spawnable
|
return mobs
|
||||||
|
end
|
||||||
|
|
||||||
|
local function is_spawn_node(name, spawn_nodes)
|
||||||
|
for _, val in ipairs(spawn_nodes) do
|
||||||
|
if val:match("^group:") then
|
||||||
|
local group = val:split(":")[2]
|
||||||
|
if minetest.get_item_group(name, group) > 0 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
elseif val == name then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Spawning Function --
|
-- Spawning Function --
|
||||||
|
@ -294,6 +307,80 @@ minetest.register_globalstep(function(dtime)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- Mapgen Spawning --
|
||||||
|
|
||||||
|
local mapgen_spawning = minetest.settings:get_bool("creatura_mapgen_spawning", true)
|
||||||
|
|
||||||
|
local mapgen_spawning_int = tonumber(minetest.settings:get("creatura_mapgen_spawn_interval")) or 5
|
||||||
|
|
||||||
|
local spawn_cooldown = 1
|
||||||
|
|
||||||
|
minetest.register_on_generated(function(minp, maxp)
|
||||||
|
if not mapgen_spawning then return end
|
||||||
|
spawn_cooldown = spawn_cooldown - 1
|
||||||
|
if spawn_cooldown <= 0 then
|
||||||
|
local min_x, max_x = minp.x, maxp.x
|
||||||
|
local min_y, max_y = minp.y, maxp.y
|
||||||
|
local min_z, max_z = minp.z, maxp.z
|
||||||
|
local mobs = get_spawnable_mobs({
|
||||||
|
x = min_x + (max_x - min_x) * 0.5,
|
||||||
|
y = min_y + (max_y - min_y) * 0.5,
|
||||||
|
z = min_z + (max_z - min_z) * 0.5
|
||||||
|
}, true)
|
||||||
|
if not mobs then spawn_cooldown = mapgen_spawning_int return end
|
||||||
|
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||||
|
local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax}
|
||||||
|
local data = vm:get_data()
|
||||||
|
for z = min_z + 8, max_z - 7, 8 do
|
||||||
|
for x = min_x + 8, max_x - 7, 8 do
|
||||||
|
local mob = #mobs > 0 and mobs[random(#mobs)]
|
||||||
|
if mob then
|
||||||
|
local spawn = creatura.registered_mob_spawns[mob]
|
||||||
|
for y = max_y, min_y, -1 do
|
||||||
|
if y > spawn.max_height
|
||||||
|
or y < spawn.min_height then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
local vi = area:index(x, y, z)
|
||||||
|
local vi_name = minetest.get_name_from_content_id(data[vi])
|
||||||
|
if spawn.spawn_in_nodes
|
||||||
|
and is_spawn_node(vi_name, spawn.nodes) then
|
||||||
|
-- Add Spawn Node to Map
|
||||||
|
data[vi] = minetest.get_content_id("creatura:spawn_node")
|
||||||
|
vm:set_data(data)
|
||||||
|
vm:write_to_map()
|
||||||
|
-- Apply Meta
|
||||||
|
local group_size = random(spawn.min_group or 1, spawn.max_group or 1)
|
||||||
|
local meta = minetest.get_meta({x = x, y = y, z = z})
|
||||||
|
meta:set_string("mob", mob)
|
||||||
|
meta:set_int("cluster", group_size)
|
||||||
|
spawn_cooldown = mapgen_spawning_int
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local vi_n = area:index(x, y - 1, z)
|
||||||
|
local vi_n_name = minetest.get_name_from_content_id(data[vi_n])
|
||||||
|
if not creatura.get_node_def(vi_name).walkable
|
||||||
|
and ((spawn.nodes and is_spawn_node(vi_n_name, spawn.nodes))
|
||||||
|
or (not spawn.nodes and creatura.get_node_def(vi_n_name).walkable)) then
|
||||||
|
-- Add Spawn Node to Map
|
||||||
|
data[vi] = minetest.get_content_id("creatura:spawn_node")
|
||||||
|
vm:set_data(data)
|
||||||
|
vm:write_to_map()
|
||||||
|
-- Apply Meta
|
||||||
|
local group_size = random(spawn.min_group or 1, spawn.max_group or 1)
|
||||||
|
local meta = minetest.get_meta({x = x, y = y, z = z})
|
||||||
|
meta:set_string("mob", mob)
|
||||||
|
meta:set_int("cluster", group_size)
|
||||||
|
spawn_cooldown = mapgen_spawning_int
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
-- Node --
|
-- Node --
|
||||||
|
|
||||||
minetest.register_node("creatura:spawn_node", {
|
minetest.register_node("creatura:spawn_node", {
|
||||||
|
@ -319,8 +406,12 @@ minetest.register_abm({
|
||||||
for _ = 1, amount do
|
for _ = 1, amount do
|
||||||
obj = minetest.add_entity(pos, name)
|
obj = minetest.add_entity(pos, name)
|
||||||
end
|
end
|
||||||
|
minetest.log("action",
|
||||||
|
"[Creatura] Spawned " .. amount .. " " .. name .. " at " .. minetest.pos_to_string(pos))
|
||||||
else
|
else
|
||||||
obj = minetest.add_entity(pos, name)
|
obj = minetest.add_entity(pos, name)
|
||||||
|
minetest.log("action",
|
||||||
|
"[Creatura] Spawned a " .. name .. " at " .. minetest.pos_to_string(pos))
|
||||||
end
|
end
|
||||||
minetest.remove_node(pos)
|
minetest.remove_node(pos)
|
||||||
if obj
|
if obj
|
||||||
|
@ -360,4 +451,128 @@ minetest.register_abm({
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})]]
|
})]]
|
||||||
|
|
||||||
|
------------------
|
||||||
|
-- ABM Spawning --
|
||||||
|
------------------
|
||||||
|
|
||||||
|
--[[creatura.register_abm_spawn("mymod:mymob", {
|
||||||
|
chance = 3000,
|
||||||
|
interval = 30,
|
||||||
|
min_height = 0,
|
||||||
|
max_height = 128,
|
||||||
|
min_light = 1,
|
||||||
|
max_light = 15,
|
||||||
|
min_group = 1,
|
||||||
|
max_group = 4,
|
||||||
|
nodes = {"group:soil", "group:stone"},
|
||||||
|
neighbors = {"air"},
|
||||||
|
spawn_on_load = false,
|
||||||
|
spawn_in_nodes = false,
|
||||||
|
spawn_cap = 5
|
||||||
|
})]]
|
||||||
|
|
||||||
|
function creatura.register_abm_spawn(mob, def)
|
||||||
|
local chance = def.chance or 3000
|
||||||
|
local interval = def.interval or 30
|
||||||
|
local min_height = def.min_height or 0
|
||||||
|
local max_height = def.max_height or 128
|
||||||
|
local min_light = def.min_light or 1
|
||||||
|
local max_light = def.max_light or 15
|
||||||
|
local min_group = def.min_group or 1
|
||||||
|
local max_group = def.max_group or 4
|
||||||
|
local nodes = def.nodes or {"group:soil", "group:stone"}
|
||||||
|
local neighbors = def.neighbors or {"air"}
|
||||||
|
local spawn_on_load = def.spawn_on_load or false
|
||||||
|
local spawn_in_nodes = def.spawn_in_nodes or false
|
||||||
|
local spawn_cap = def.spawn_cap or 5
|
||||||
|
|
||||||
|
local function spawn_func(pos, _, _, aocw)
|
||||||
|
|
||||||
|
if spawn_on_load
|
||||||
|
and random(chance) > 1 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if spawn_on_load
|
||||||
|
and not minetest.find_node_near(pos, 1, neighbors) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if pos.y > max_height
|
||||||
|
or pos.y < min_height then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not spawn_in_nodes then
|
||||||
|
pos = vec_raise(pos, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local light = minetest.get_node_light(pos) or 7
|
||||||
|
|
||||||
|
if light > max_light
|
||||||
|
or light < min_light then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if aocw
|
||||||
|
and aocw >= spawn_cap then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local mob_def = minetest.registered_entities[mob]
|
||||||
|
local mob_width = mob_def.collisionbox[4]
|
||||||
|
local mob_height = math.max(0, mob_def.collisionbox[5] - mob_def.collisionbox[2])
|
||||||
|
|
||||||
|
pos.y = pos.y - 0.49
|
||||||
|
|
||||||
|
if not creatura.is_pos_moveable(pos, mob_width, mob_height) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local group_size = random(min_group or 1, max_group or 1)
|
||||||
|
|
||||||
|
local obj
|
||||||
|
|
||||||
|
for _ = 1, group_size do
|
||||||
|
obj = minetest.add_entity(pos, mob)
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.log("action",
|
||||||
|
"[Creatura] [ABM Spawning] Spawned " .. group_size .. " " .. mob .. " at " .. minetest.pos_to_string(pos))
|
||||||
|
|
||||||
|
if obj
|
||||||
|
and creatura.registered_on_spawns[mob]
|
||||||
|
and #creatura.registered_on_spawns[mob] > 0 then
|
||||||
|
for i = 1, #creatura.registered_on_spawns[mob] do
|
||||||
|
local func = creatura.registered_on_spawns[mob][i]
|
||||||
|
func(obj:get_luaentity(), pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if spawn_on_load then
|
||||||
|
minetest.register_lbm({
|
||||||
|
name = mob .. "_spawning",
|
||||||
|
label = mob .. " spawning",
|
||||||
|
nodenames = nodes,
|
||||||
|
run_at_every_load = false,
|
||||||
|
action = function(pos)
|
||||||
|
spawn_func(pos)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
else
|
||||||
|
minetest.register_abm({
|
||||||
|
label = mob .. " spawning",
|
||||||
|
nodenames = nodes,
|
||||||
|
neighbors = neighbors,
|
||||||
|
interval = interval,
|
||||||
|
chance = chance,
|
||||||
|
catch_up = false,
|
||||||
|
action = function(pos, ...)
|
||||||
|
spawn_func(pos, ...)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Reference in a new issue