344 lines
13 KiB
Lua
344 lines
13 KiB
Lua
|
|
natspawner = {}
|
|
|
|
local spawners = {}
|
|
spawner_count = 0
|
|
|
|
local node_to_spawner_map = {
|
|
["default:stone"] = {name = "stone_spawner", textures = {"default_stone.png^[cracko:1:2", "default_stone.png", {name = "default_stone.png"}}},
|
|
["default:sand"] = {name = "sand_spawner", textures = {"default_sand.png^[cracko:1:2", "default_sand.png", {name = "default_sand.png"}}},
|
|
["default:desert_sand"] = {name = "desert_sand_spawner", textures = {"default_desert_sand.png^[cracko:1:2", "default_desert_sand.png", {name = "default_desert_sand.png"}}},
|
|
["default:ice"] = {name = "ice_spawner", textures = {"default_ice.png^[cracko:1:2", "default_ice.png", {name = "default_ice.png"}}},
|
|
["default:snowblock"] = {name = "snowblock_spawner", textures = {"default_snow.png^[cracko:1:2", "default_snow.png", {name = "default_snow.png"}}},
|
|
["default:dirt_with_grass"] = {name = "dirt_with_grass_spawner", textures = {"default_grass.png^[cracko:1:2", "default_dirt.png", {name = "default_dirt.png^default_grass_side.png"}}},
|
|
["default:dirt_with_dry_grass"] = {name = "dirt_with_dry_grass_spawner", textures = {"default_dry_grass.png^[cracko:1:2", "default_dirt.png", {name = "default_dirt.png^default_dry_grass_side.png"}}},
|
|
["default:dirt_with_snow"] = {name = "dirt_with_snow_spawner", textures = {"default_snow.png^[cracko:1:2", "default_dirt.png", {name = "default_dirt.png^default_snow_side.png"}}},
|
|
["default:dirt_with_rainforest_litter"] = {name = "dirt_with_rainforest_litter_spawner", textures = {"default_coniferous_litter.png^[cracko:1:2", "default_dirt.png", {name = "default_dirt.png^default_rainforest_litter_side.png"}}},
|
|
["default:dirt_with_coniferous_litter"] = {name = "dirt_with_coniferous_litter_spawner", textures = {"default_rainforest_litter.png^[cracko:1:2", "default_dirt.png", {name = "default_dirt.png^default_coniferous_litter_side.png"}}},
|
|
["default:permafrost"] = {name = "permafrost_spawner", textures = {"default_permafrost.png^[cracko:1:2", "default_permafrost.png", {name = "default_permafrost.png"}}},
|
|
["default:permafrost_with_stones"] = {name = "permafrost_with_stones_spawner", textures = {"default_permafrost.png^default_stones.png^[cracko:1:2", "default_permafrost.png", {name = "default_permafrost.png"}}},
|
|
["default:permafrost_with_moss"] = {name = "permafrost_with_moss_spawner", textures = {"default_moss.png^[cracko:1:2", "default_permafrost.png", {name = "default_permafrost.png^default_moss_side.png"}}}
|
|
}
|
|
|
|
mobs:register_mob("natspawner:zombie", {
|
|
type = "monster",
|
|
passive = false,
|
|
attack_type = "dogfight",
|
|
damage = 4,
|
|
reach = 2,
|
|
hp_min = 12,
|
|
hp_max = 35,
|
|
armor = 150,
|
|
collisionbox = {-0.25, -1, -0.3, 0.25, 0.75, 0.3},
|
|
visual = "mesh",
|
|
mesh = "creatures_mob.x",
|
|
textures = {
|
|
{"mobs_zombie.png"},
|
|
},
|
|
visual_size = {x=1, y=1},
|
|
makes_footstep_sound = true,
|
|
sounds = {
|
|
random = "mobs_zombie.1",
|
|
damage = "mobs_zombie_hit",
|
|
attack = "mobs_zombie.3",
|
|
death = "mobs_zombie_death",
|
|
},
|
|
walk_velocity = 0.5,
|
|
run_velocity = 1.75,
|
|
jump = true,
|
|
floats = 0,
|
|
view_range = 12,
|
|
drops = {
|
|
{name = "zombie:rotten_flesh",
|
|
chance = 2, min = 3, max = 5,},
|
|
},
|
|
water_damage = 0,
|
|
lava_damage = 1,
|
|
light_damage = 0,
|
|
animation = {
|
|
speed_normal = 10, speed_run = 15,
|
|
stand_start = 0, stand_end = 79,
|
|
walk_start = 168, walk_end = 188,
|
|
run_start = 168, run_end = 188,
|
|
-- punch_start = 168, punch_end = 188,
|
|
},
|
|
on_rightclick = function(self, clicker)
|
|
minetest.log(dump(self))
|
|
end,
|
|
on_die = function(self, pos)
|
|
if self.spawn and self.spawn.pos then
|
|
local meta = minetest.get_meta(self.spawn.pos)
|
|
meta:set_int("entity_killed_count", meta:get_int("entity_killed_count") + 1)
|
|
if self.variation then meta:set_int("spawned_variation_count", 0) end
|
|
end
|
|
end
|
|
})
|
|
|
|
--name, nodes, neighbours, minlight, maxlight, interval, chance, active_object_count, min_height, max_height
|
|
-- mobs:spawn({
|
|
-- name = "zombie:zombie",
|
|
-- nodes = {"default:dirt_with_grass"},
|
|
-- min_light = 0,
|
|
-- max_light = 7,
|
|
-- chance = 9000,
|
|
-- active_object_count = 2,
|
|
-- min_height = 0,
|
|
-- day_toggle = false,
|
|
-- })
|
|
|
|
local min_player_distance = 5 --20
|
|
local max_mob_count = 5 --15
|
|
local max_spawn_interval = 10 --300
|
|
local min_spawn_interval = 5 --120
|
|
local spawn_radius = 5
|
|
local min_kill_count = 5
|
|
local max_kill_count = 10
|
|
local min_deactivation_time = 5
|
|
local max_deactivation_time = 5
|
|
local spawn_on_dig = true
|
|
|
|
local function spawn(pos, force)
|
|
-- Check for players nearby
|
|
local objects = minetest.get_objects_inside_radius(pos, min_player_distance)
|
|
local timer = minetest.get_node_timer(pos)
|
|
local interval = math.random(min_spawn_interval, max_spawn_interval)
|
|
|
|
local meta = minetest.get_meta(pos)
|
|
local entity_name = meta:get_string("entity_name")
|
|
--local entity_spawn_count = meta:get_int("entity_spawn_count")
|
|
|
|
local entity_count = 0
|
|
for _,object in pairs(objects) do
|
|
if object then
|
|
if object:is_player() and not force then
|
|
minetest.log("Player too close")
|
|
-- Re-schedule
|
|
timer:start(interval)
|
|
minetest.log("Next spawning scheduled in "..interval.." seconds")
|
|
return
|
|
elseif object:get_luaentity()
|
|
and object:get_luaentity().entity_name
|
|
and object:get_luaentity().entity_name == entity_name then
|
|
entity_count = entity_count + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Check for amount nearby
|
|
if force or (entity_count <= max_mob_count) then
|
|
-- Spawn
|
|
local spawn_pos = {x=pos.x + math.random(0, spawn_radius), y=pos.y+3, z=pos.z + math.random(0, spawn_radius)}
|
|
-- Check spawn position - if not air, then spawn just above the spawner
|
|
local spawn_node = minetest.get_node_or_nil(spawn_pos)
|
|
if spawn_node and spawn_node.name ~= "air" then
|
|
spawn_pos = pos
|
|
end
|
|
minetest.log("Spawning "..entity_name.." at pos "..minetest.pos_to_string(spawn_pos))
|
|
local entity = minetest.add_entity(spawn_pos, entity_name)
|
|
if entity then
|
|
entity:get_luaentity().entity_name = entity_name
|
|
entity:get_luaentity().spawn = {
|
|
pos = pos
|
|
}
|
|
-- Spawn a variation with 30% chance
|
|
local variation_chance = math.random(1, 10)
|
|
if variation_chance > 7 and meta:get_int("spawned_variation_count") == 0 then
|
|
entity:get_luaentity().variation = true
|
|
-- Velocity
|
|
entity:get_luaentity().walk_velocity = 1.5
|
|
entity:get_luaentity().run_velocity = 3
|
|
-- View range
|
|
entity:get_luaentity().view_range = 20
|
|
-- HP
|
|
local hp = math.random(215, 315)
|
|
entity:get_luaentity().hp_max = hp
|
|
entity:get_luaentity().health = hp
|
|
entity:get_luaentity().old_health = hp
|
|
-- Damage
|
|
entity:get_luaentity().damage = math.random(10, 20)
|
|
entity:get_luaentity().reach = 4
|
|
-- Armor
|
|
entity:set_armor_groups({immortal = 1, fleshy = math.random(300, 350)})
|
|
entity:get_luaentity().knock_back = false
|
|
-- Other properties
|
|
entity:set_properties({
|
|
visual_size = {x=2.75, y=2.5, z=2.75},
|
|
collisionbox = {-0.63, -2.5, -0.75, 0.63, 1.88, 0.75},
|
|
stepheight = 2
|
|
})
|
|
meta:set_int("spawned_variation_count", 1)
|
|
end
|
|
minetest.log("Next spawning scheduled in "..interval.." seconds")
|
|
end
|
|
else
|
|
minetest.log("Max spawn limit reached")
|
|
-- Re-calulate interval using deactivation times
|
|
interval = math.random(min_deactivation_time, max_deactivation_time)
|
|
minetest.log("Deactivating spawner for "..interval.." seconds")
|
|
end
|
|
|
|
-- Re-schedule
|
|
timer:start(interval)
|
|
end
|
|
|
|
local function register_spawner(spawner_name, entity_name, replacement_nodes)
|
|
|
|
spawners[spawner_name] = replacement_nodes
|
|
spawner_count = spawner_count + 1
|
|
|
|
-- Register all spawners
|
|
for _,val in pairs(replacement_nodes) do
|
|
|
|
minetest.register_node("natspawner:"..spawner_name..val.name, {
|
|
description = "Spawner",
|
|
drop = "natspawner:"..spawner_name.."_"..val.name,
|
|
tiles = val.textures,
|
|
groups = {crumbly=2, soil = 2},
|
|
sounds = default.node_sound_sand_defaults(),
|
|
on_construct = function(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
meta:set_string("entity_name", entity_name)
|
|
meta:set_int("entity_spawn_count", 0)
|
|
meta:set_int("entity_killed_count", 0)
|
|
meta:set_int("spawned_variation_count", 0)
|
|
meta:set_int("next_deactivation_count", math.random(min_kill_count, max_kill_count))
|
|
meta:set_int("next_deactivation_time", math.random(min_deactivation_time, max_deactivation_time))
|
|
|
|
local timer = minetest.get_node_timer(pos)
|
|
timer:start(min_spawn_interval)
|
|
end,
|
|
on_timer = function(pos)
|
|
spawn(pos)
|
|
end,
|
|
on_dig = function(pos, node, digger)
|
|
local meta = minetest.get_meta(pos)
|
|
local entity_killed_count = meta:get_int("entity_killed_count")
|
|
local next_deactivation_count = meta:get_int("next_deactivation_count")
|
|
if (entity_killed_count < next_deactivation_count) then
|
|
if spawn_on_dig then
|
|
spawn(pos, true)
|
|
end
|
|
minetest.chat_send_player(digger:get_player_name(), "You have killed "..entity_killed_count.." enemies!")
|
|
return false
|
|
else
|
|
minetest.node_dig(pos, node, digger)
|
|
end
|
|
end
|
|
})
|
|
|
|
end
|
|
end
|
|
|
|
register_spawner("zombie", "natspawner:zombie", node_to_spawner_map)
|
|
|
|
local perl1 = {SEED1 = 9130, OCTA1 = 3, PERS1 = 0.5, SCAL1 = 250} -- Values should match minetest mapgen V6 desert noise.
|
|
|
|
local function hlp_fnct(pos, name)
|
|
local n = minetest.get_node_or_nil(pos)
|
|
if n and n.name and n.name == name then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
local function ground(pos, old)
|
|
local p2 = pos
|
|
while hlp_fnct(p2, "air") do
|
|
p2.y = p2.y -1
|
|
end
|
|
if p2.y < old.y then
|
|
return p2
|
|
else
|
|
return old
|
|
end
|
|
end
|
|
|
|
minetest.register_on_generated(function(minp, maxp, seed)
|
|
|
|
-- No spawners registered
|
|
if spawner_count == 0 then return end
|
|
|
|
if maxp.y < 0 then return end
|
|
math.randomseed(seed)
|
|
local cnt = 0
|
|
|
|
local perlin1 = minetest.env:get_perlin(perl1.SEED1, perl1.OCTA1, perl1.PERS1, perl1.SCAL1)
|
|
local noise1 = perlin1:get2d({x=minp.x,y=minp.y})--,z=minp.z})
|
|
|
|
if noise1 > 0.25 or noise1 < -0.26 then
|
|
local mpos = {x=math.random(minp.x,maxp.x), y=math.random(minp.y,maxp.y), z=math.random(minp.z,maxp.z)}
|
|
|
|
local p2 = minetest.find_node_near(mpos, 25, {"default:dirt_with_grass", "default:dirt_with_snow"})
|
|
while p2 == nil and cnt < 10 do
|
|
cnt = cnt+1
|
|
mpos = {x=math.random(minp.x,maxp.x), y=math.random(minp.y,maxp.y), z=math.random(minp.z,maxp.z)}
|
|
p2 = minetest.find_node_near(mpos, 25, {"default:dirt_with_grass", "default:dirt_with_snow"})
|
|
end
|
|
if p2 == nil then return end
|
|
if p2.y < 0 then return end
|
|
|
|
local off = 0
|
|
|
|
-- Simpler finding routine - check if node immediately above is air,
|
|
-- and if node 16 blocks above is air
|
|
minetest.log("Checking pos to spawn: "..minetest.pos_to_string(p2))
|
|
local next_node_above = minetest.get_node_or_nil({x=p2.x, y=p2.y+1, z=p2.z})
|
|
minetest.log("FOund next node above: "..dump(next_node_above))
|
|
local next_mapblock_above = minetest.get_node_or_nil({x=p2.x, y=p2.y+16, z=p2.z})
|
|
minetest.log("Found next node above mapblock: "..dump(next_mapblock_above))
|
|
|
|
if next_node_above and next_node_above.name and next_node_above.name == "air" and
|
|
next_mapblock_above and next_mapblock_above.name and next_mapblock_above.name == "air" then
|
|
|
|
-- Choose a spawner
|
|
for i = 1, spawner_count do
|
|
local spawner_name = next(spawners)
|
|
local node_map = spawners[spawner_name]
|
|
minetest.log("Spawner:")
|
|
minetest.log(dump(node_map))
|
|
local chance = math.random(1, spawner_count)
|
|
if chance == i then
|
|
-- Create spawner
|
|
minetest.after(0.8, function(pos)
|
|
minetest.log("Creating advanced spawner at "..minetest.pos_to_string(pos))
|
|
local node_to_replace = minetest.get_node(pos)
|
|
minetest.set_node(pos, {name="natspawner:"..spawner_name..node_map[node_to_replace.name].name})
|
|
end, p2)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- local opos1 = {x=p2.x+22,y=p2.y-1,z=p2.z+22}
|
|
-- local opos2 = {x=p2.x+22,y=p2.y-1,z=p2.z}
|
|
-- local opos3 = {x=p2.x,y=p2.y-1,z=p2.z+22}
|
|
-- local opos1_n = minetest.get_node_or_nil(opos1)
|
|
-- local opos2_n = minetest.get_node_or_nil(opos2)
|
|
-- local opos3_n = minetest.get_node_or_nil(opos3)
|
|
-- if opos1_n and opos1_n.name and opos1_n.name == "air" then
|
|
-- p2 = ground(opos1, p2)
|
|
-- end
|
|
-- if opos2_n and opos2_n.name and opos2_n.name == "air" then
|
|
-- p2 = ground(opos2, p2)
|
|
-- end
|
|
-- if opos3_n and opos3_n.name and opos3_n.name == "air" then
|
|
-- p2 = ground(opos3, p2)
|
|
-- end
|
|
-- p2.y = p2.y - 3
|
|
-- if p2.y < 0 then p2.y = 0 end
|
|
--if minetest.find_node_near(p2, 25, {"default:water_source"}) ~= nil or minetest.find_node_near(p2, 22, {"default:dirt_with_grass"}) ~= nil or minetest.find_node_near(p2, 52, {"default:sandstonebrick"}) ~= nil then return end
|
|
|
|
--minetest.after(0.8,make,p2)
|
|
end
|
|
end)
|
|
|
|
|
|
|
|
|
|
mobs:register_egg("natspawner:zombie", "Zombie", "zombie_head.png", 0)
|
|
|
|
minetest.register_craftitem("natspawner:rotten_flesh", {
|
|
description = "Rotten Flesh",
|
|
inventory_image = "mobs_rotten_flesh.png",
|
|
on_use = minetest.item_eat(-5),
|
|
})
|