Add deep water spawner

This commit is contained in:
sapier 2013-11-24 15:37:05 +01:00
parent e058deb494
commit f98020d6b5
3 changed files with 374 additions and 88 deletions

View File

@ -0,0 +1,281 @@
-------------------------------------------------------------------------------
-- Mob Framework Mod by Sapier
--
-- You may copy, use, modify or do nearly anything except removing this
-- copyright notice.
-- And of course you are NOT allow to pretend you have written it.
--
--! @file deep_water.lua
--! @brief spawn algorithm for deep water spawning
--! @copyright Sapier
--! @author Sapier
--! @date 2013-11-24
--
--! @addtogroup spawn_algorithms
--! @{
-- Contact sapier a t gmx net
-------------------------------------------------------------------------------
local DEEP_WATER_MIN_DEPTH = -20
local DEEP_WATER_MAX_DEPTH = -50
local DEEP_WATER_SPAWNER_SUFFIX = "_deep_water"
-------------------------------------------------------------------------------
-- name: mobf_spawner_deep_water_spawner_spawnfunc(spawning_data,pos,self)
--
--! @brief function to spawn a spawner entity
--
--! @param spawning_data spawning configuration
--! @param pos position do spawn
-------------------------------------------------------------------------------
function mobf_spawner_deep_water_spawner_spawnfunc(spawning_data,pos,self)
mobf_assert_backtrace(type(spawning_data.minp) == "number")
mobf_assert_backtrace(type(spawning_data.maxp) == "number")
local min_y = spawning_data.minp
local max_y = spawning_data.maxp
dbg_mobf.spawning_lvl3("spawning data: " .. dump(spawning_data))
--check if we try to spawn in correct area
if max_y < DEEP_WATER_MAX_DEPTH then
dbg_mobf.spawning_lvl3("MOBF: deep water spawner --> to deep: " ..
max_y .. " < " .. DEEP_WATER_MAX_DEPTH)
return false
end
if min_y > DEEP_WATER_MIN_DEPTH then
dbg_mobf.spawning_lvl3("MOBF: deep water spawner --> to high: " ..
max_y .. " < " .. DEEP_WATER_MIN_DEPTH)
return false
end
local waternodes = minetest.find_nodes_in_area({x=pos.x,y=min_y,z=pos.z},
{x=pos.x,y=max_y,z=pos.z},
{ "default:water_flowing",
"default:water_source"} )
--check for water
if #waternodes == 0 then
dbg_mobf.spawning_lvl3("MOBF: deep water spawner no water at position "
.. printpos(pos) ..
" " .. min_y .. "<->" .. max_y .. " found")
return false
end
pos = spawning.spawner_get_water_pos( pos,
DEEP_WATER_MIN_DEPTH,
DEEP_WATER_MIN_DEPTH,
min_y,max_y)
if pos == nil then
dbg_mobf.spawning_lvl3(
"MOBF: deep water spawnerunable to find a suitable depth at position "
.. printpos(pos))
return false
end
--only place a spawner if there's enough water around
local found_nodes = minetest.find_nodes_in_area({x=pos.x-2,y=pos.y-2,z=pos.z-2},
{x=pos.x+2,y=pos.y+2,z=pos.z+2},
{ "default:water_flowing",
"default:water_source"} )
--maximum number of water nodes is 64 if less than half is water don't spawn here
if #found_nodes < 32 then
dbg_mobf.spawning_lvl3("MOBF: deep water spawner " .. printpos(pos) ..
" not enough water around: " .. #found_nodes)
return false
end
local spawner = spawning.spawn_and_check(
spawning_data.name .. "_spawner" ..
DEEP_WATER_SPAWNER_SUFFIX,
pos,
"deep_water")
if spawner == nil then
return false
else
dbg_mobf.spawning_lvl3("MOBF: deep water spawner spawned at " ..
printpos(pos))
spawner.spawner_miny = min_y
spawner.spawner_maxy = max_y
return true
end
end
-------------------------------------------------------------------------------
-- name: mobf_spawner_deep_water_spawnfunc(spawning_data,pos)
--
--! @brief function to spawn a mob entity
--
--! @param spawning_data spawning configuration
--! @param pos position do spawn
-------------------------------------------------------------------------------
function mobf_spawner_deep_water_spawnfunc(spawning_data,pos)
local node = minetest.get_node(pos)
--first find a new water pos
pos = spawning.spawner_get_water_pos(pos,
DEEP_WATER_MIN_DEPTH,
DEEP_WATER_MAX_DEPTH,
pos.y+DEEP_WATER_MAX_DEPTH,
MIN(0,pos.y-DEEP_WATER_MAX_DEPTH))
if pos == nil then
dbg_mobf.spawning_lvl2("MOBF: didn't find a pos in water")
return false
end
--only place a spawner if it's within water
local found_nodes = minetest.find_nodes_in_area(
{x=pos.x-2,y=pos.y-2,z=pos.z-2},
{x=pos.x+2,y=pos.y+2,z=pos.z+2},
{ "default:water_flowing","default:water_source"} )
--maximum number of water nodes is 64 if less than half is water don't spawn here
if #found_nodes < 32 then
dbg_mobf.spawning_lvl2("MOBF: spawner " .. printpos(pos) .. " not enough water around: " .. #found_nodes)
return false
end
--check if there is a mob right there
if spawning.position_in_use(pos,spawning_data) then
dbg_mobf.spawning_lvl2("MOBF: spawner " .. printpos(pos) .. " is in use")
return false
end
--check popualation density limit
if spawning.population_density_limit(pos,spawning_data) then
dbg_mobf.spawning_lvl2("MOBF: spawner " .. printpos(pos) .. " to many mobs around")
return false
end
local pos_above = { x=pos.x,y=pos.y+1,z=pos.z }
local spawner = spawning.spawn_and_check(spawning_data.name,pos_above,"deep_water")
if spawner == nil then
return false
end
end
-------------------------------------------------------------------------------
-- name: mobf_spawn_initialize_deep_water_abm(spawning_data)
--
--! @brief find a place in water to spawn mob
--
--! @param spawning_data spawning configuration
-------------------------------------------------------------------------------
function mobf_spawn_initialize_deep_water_abm(spawning_data)
minetest.log(LOGLEVEL_INFO,
"MOBF: \tregistering deep water spawn abm callback for mob "..
spawning_data.name)
local media = nil
if environment ~= nil and
environment.media ~= nil then
media = environment.media
end
minetest.register_abm({
nodenames = { "default:water_source" },
neighbors = media,
interval = 60,
chance = math.floor(1/spawning_data.rate),
action = function(pos, node, active_object_count, active_object_count_wider)
local starttime = mobf_get_time_ms()
local pos_above = {
x = pos.x,
y = pos.y + 1,
z = pos.z
}
--never try to spawn an mob at pos (0,0,0) it's initial entity spawnpos and
--used to find bugs in initial spawnpoint setting code
if mobf_pos_is_zero(pos) then
mobf_warn_long_fct(starttime,"mobf_spawn_deep_water")
return
end
--check if pos is ok
if not environment.evaluate_state(
spawning.pos_quality(spawning_data,pos_above),
LT_SAFE_POS) then
mobf_warn_long_fct(starttime,"mobf_spawn_deep_water")
return
end
--check population density
if mobf_mob_around(spawning_data.name,
spawning_data.name_secondary,
pos_above,spawning_data.density,true) > 0 then
mobf_warn_long_fct(starttime,"mobf_spawn_deep_water")
return
end
mobf_spawner_deep_water_spawnfunc(spawning_data,pos)
mobf_warn_long_fct(starttime,"mobf_spawn_deep_water")
end,
})
end
-------------------------------------------------------------------------------
-- name: mobf_spawn_initialize_deep_water_mapgen(spawning_data)
--
--! @brief find a place in deep water
--
--! @param spawning_data spawning configuration
-------------------------------------------------------------------------------
function mobf_spawn_initialize_deep_water_mapgen(spawning_data)
minetest.log(LOGLEVEL_INFO,
"MOBF:\tregistering in deep water mapgen spawn mapgen callback for mob "..
spawning_data.name)
--disable spawner entity y position check
spawning_data.relaxed_y_check = true
spawning.register_spawner_entity(spawning_data,
mobf_spawner_deep_water_spawnfunc,
nil, --TODO
DEEP_WATER_SPAWNER_SUFFIX)
if minetest.world_setting_get("mobf_delayed_spawning") then
minetest.register_on_generated(function(minp, maxp, seed)
local job = {
callback = spawning.divide_mapgen_entity_jobfunc,
data = {
minp = minp,
maxp = maxp,
spawning_data = spawning_data,
spawnfunc = mobf_spawner_deep_water_spawner_spawnfunc,
maxtries = 15,
func = spawning.divide_mapgen_entity_jobfunc,
}
}
mobf_job_queue.add_job(job)
end)
else
--add mob spawner on map generation
minetest.register_on_generated(function(minp, maxp, seed)
local starttime = mobf_get_time_ms()
spawning.divide_mapgen_entity(minp,maxp,
spawning_data,
mobf_spawner_deep_water_spawner_spawnfunc,
15)
mobf_warn_long_fct(starttime,"on_mapgen " .. spawning_data.name,"mapgen")
end) --register mapgen
end
end --end spawn algo
--!@}
spawning.register_spawn_algorithm("deep_water", mobf_spawn_deep_water)
spawning.register_spawn_algorithm("deep_water_spawner",
mobf_spawn_initialize_deep_water_mapgen,
spawning.register_cleanup_spawner)

View File

@ -19,89 +19,6 @@
local SHALLOW_WATER_MAX_DEPTH = -10
local SHALLOW_WATER_SPAWNER_SUFFIX = "_shallow_water"
-------------------------------------------------------------------------------
-- name: mobf_spawner_get_water_pos(pos,max_depth,min_y,max_y)
--
--! @brief find a position at x/z within some y limitations
--
--! @param pos position do spawn
--! @param max_depth may depth to spawn
--! @param min_y minimum y value of generated chunk
--! @param max_y maximum y value of generated chunk
-------------------------------------------------------------------------------
function mobf_spawner_get_water_pos(pos,max_depth,min_y,max_y)
--get information about current position
local upper_pos = {x=pos.x,y=max_y,z=pos.z}
if max_depth == nil then
max_depth = SHALLOW_WATER_MAX_DEPTH
end
--TODO add min depth
local ground_distance = mobf_ground_distance(upper_pos,
{ "default:water_flowing",
"default:water_source",
"air" },max_y - min_y)
local ground_level = max_y - ground_distance +1
local ground_pos = {x=pos.x,y=ground_level,z=pos.z }
local water_depth = mobf_air_distance(ground_pos)
local surfacenode = minetest.get_node(ground_pos)
if surfacenode == nil then
dbg_mobf.spawning_lvl3("MOBF: invalid ground node")
return nil
end
if surfacenode.name ~= "default:water_flowing" and
surfacenode.name ~= "default:water_source" then
--mobf_print("MOBF: WD:" .. water_depth .. " GD: " .. ground_distance)
--mobf_print("MOBF: MAXD:" .. max_depth .. " " .. min_y .. "<->" .. max_y)
dbg_mobf.spawning_lvl3("MOBF: " .. surfacenode.name .. " isn't open water: " .. printpos(ground_pos))
--if ground_pos.y > 0 then
-- for i=min_y,max_y,1 do
-- local node = minetest.get_node({x=pos.x,y=i,z=pos.z})
-- print("i=" .. i .. " : " .. node.name)
-- end
--end
return nil
end
if water_depth <= 0 then
dbg_mobf.spawning_lvl3("MOBF: water not found! GP: " .. ground_level .. " WD: " .. water_depth)
--TODO spawn in caves?
return nil
end
local water_surface_pos = {x=pos.x,y=ground_level + water_depth,z=pos.z}
--dbg_mobf.spawning_lvl2
dbg_mobf.spawning_lvl3("MOBF: mobf_spawner_get_water_pos GL: " ..
ground_level ..
" WDPT: " .. water_depth ..
" WSP: " .. printpos(water_surface_pos))
if MAX(ground_level,max_depth) > water_surface_pos.y then
mobf_print("MOBF: WD:" .. water_depth .. " GD: " .. ground_distance)
mobf_print("MOBF: MAXD:" .. max_depth .. " " .. min_y .. "<->" .. max_y)
mobf_print("MOBF: mobf_spawner_get_water_pos GL: " ..
ground_level ..
" WDPT: " .. water_depth ..
" WSP: " .. printpos(water_surface_pos))
mobf_assert_backtrace(MAX(ground_level,max_depth) < water_surface_pos.y)
return nil
end
--
pos.y = math.floor(
math.random(
MAX(ground_level,max_depth),
water_surface_pos.y
)
+ 0.5)
return pos
end
-------------------------------------------------------------------------------
-- name: mobf_spawner_in_shallow_water_spawner_spawnfunc(spawning_data,pos,self)
--
@ -136,7 +53,7 @@ function mobf_spawner_in_shallow_water_spawner_spawnfunc(spawning_data,pos,self)
return false
end
pos = mobf_spawner_get_water_pos(pos,SHALLOW_WATER_MAX_DEPTH,min_y,max_y)
pos = spawning.spawner_get_water_pos(pos,0,SHALLOW_WATER_MAX_DEPTH,min_y,max_y)
if pos == nil then
dbg_mobf.spawning_lvl3("MOBF: unable to find a suitable depth at position " .. printpos(pos))
@ -183,7 +100,8 @@ function mobf_spawner_in_shallow_water_spawnfunc(spawning_data,pos)
--first find a new water pos
pos = mobf_spawner_get_water_pos(pos,
pos = spawning.spawner_get_water_pos(pos,
0,
SHALLOW_WATER_MAX_DEPTH,
pos.y+SHALLOW_WATER_MAX_DEPTH,
MIN(0,pos.y-SHALLOW_WATER_MAX_DEPTH))

View File

@ -616,11 +616,11 @@ function spawning.divide_mapgen(minp,maxp,spawning_data,spawnfunc,surfacefunc,ma
if not continue and
spawning_data.height ~= nil and
mobf_air_above(pos,spawning_data.height) ~= true then
mobf_print("MOBF: not enough room to spawn: " .. spawning_data.height)
dbg_mobf.spawning_lvl3("MOBF: not enough room to spawn: " .. spawning_data.height)
local mypos = pos
for i=1,spawning_data.height,1 do
local nodeatpos = minetest.get_node(mypos)
mobf_print("\t" .. printpos(mypos) .. ": " .. nodeatpos.name)
dbg_mobf.spawning_lvl3("\t" .. printpos(mypos) .. ": " .. nodeatpos.name)
mypos.y = mypos.y +1
end
continue = true
@ -1214,6 +1214,92 @@ function spawning.population_density_limit(pos,spawndata)
return false
end
-------------------------------------------------------------------------------
-- name: spawner_get_water_pos(pos,max_depth,min_y,max_y)
--
--! @brief find a position at x/z within some y limitations
--
--! @param pos position do spawn
--! @param min_depth min-y depth to spawn
--! @param max_depth max-y depth to spawn
--! @param min_y minimum y value of generated chunk
--! @param max_y maximum y value of generated chunk
-------------------------------------------------------------------------------
function spawning.spawner_get_water_pos(pos,min_depth,max_depth,min_y,max_y)
--get information about current position
local upper_pos = {x=pos.x,y=max_y,z=pos.z}
mobf_assert_backtrace(type(min_depth) == "number")
mobf_assert_backtrace(type(max_depth) == "number")
local ground_distance = mobf_ground_distance(upper_pos,
{ "default:water_flowing",
"default:water_source",
"air" },max_y - min_y)
local ground_level = max_y - ground_distance +1
local ground_pos = {x=pos.x,y=ground_level,z=pos.z }
local water_depth = mobf_air_distance(ground_pos)
local surfacenode = minetest.get_node(ground_pos)
if surfacenode == nil then
dbg_mobf.spawning_lvl3("MOBF: invalid ground node")
return nil
end
if surfacenode.name ~= "default:water_flowing" and
surfacenode.name ~= "default:water_source" then
--mobf_print("MOBF: WD:" .. water_depth .. " GD: " .. ground_distance)
--mobf_print("MOBF: MAXD:" .. max_depth .. " " .. min_y .. "<->" .. max_y)
dbg_mobf.spawning_lvl3("MOBF: " .. surfacenode.name .. " isn't open water: " .. printpos(ground_pos))
--if ground_pos.y > 0 then
-- for i=min_y,max_y,1 do
-- local node = minetest.get_node({x=pos.x,y=i,z=pos.z})
-- print("i=" .. i .. " : " .. node.name)
-- end
--end
return nil
end
if water_depth <= 0 then
dbg_mobf.spawning_lvl3("MOBF: water not found! GP: " .. ground_level .. " WD: " .. water_depth)
--TODO spawn in caves?
return nil
end
local water_surface_pos = {x=pos.x,y=ground_level + water_depth,z=pos.z}
--dbg_mobf.spawning_lvl2
dbg_mobf.spawning_lvl3("MOBF: mobf_spawner_get_water_pos GL: " ..
ground_level ..
" WDPT: " .. water_depth ..
" WSP: " .. printpos(water_surface_pos))
if MAX(ground_level,max_depth) > water_surface_pos.y then
mobf_print("MOBF: WD:" .. water_depth .. " GD: " .. ground_distance)
mobf_print("MOBF: MAXD:" .. max_depth .. " " .. min_y .. "<->" .. max_y)
mobf_print("MOBF: mobf_spawner_get_water_pos GL: " ..
ground_level ..
" WDPT: " .. water_depth ..
" WSP: " .. printpos(water_surface_pos))
mobf_assert_backtrace(MAX(ground_level,max_depth) < water_surface_pos.y)
return nil
end
--check if there is any chance to find a suitable pos
if MAX(ground_level,max_depth) >= MIN(water_surface_pos.y,min_depth) then
return nil
end
pos.y = math.floor(
math.random(
MAX(ground_level,max_depth),
MIN(water_surface_pos.y,min_depth)
)
+ 0.5)
return pos
end
--include spawn algorithms
dofile (mobf_modpath .. "/spawn_algorithms/at_night.lua")
dofile (mobf_modpath .. "/spawn_algorithms/forrest.lua")
@ -1224,3 +1310,4 @@ dofile (mobf_modpath .. "/spawn_algorithms/big_willow.lua")
dofile (mobf_modpath .. "/spawn_algorithms/in_air1.lua")
dofile (mobf_modpath .. "/spawn_algorithms/none.lua")
dofile (mobf_modpath .. "/spawn_algorithms/deep_large_caves.lua")
dofile (mobf_modpath .. "/spawn_algorithms/deep_water.lua")