natural-spawner/init.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),
})