Add ice zombie and sand zombie (WIP)

master
Hector Franqui 2019-05-24 15:17:01 -04:00
parent eddaeda1f5
commit 0f2157f5f5
9 changed files with 884 additions and 519 deletions

500
api.lua Normal file
View File

@ -0,0 +1,500 @@
local spawners = {}
spawner_count = 0
natspawner.on_mob_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", meta:get_int("spawned_variation_count") - 1)
end
end
end
local function spawn(pos, force)
local meta = minetest.get_meta(pos)
local spawner_name = meta:get_string("spawner_name")
if spawner_name then
local spawner = spawners[spawner_name]
local replacement_node_name = meta:get_string("replaced_node_name")
local timer = minetest.get_node_timer(pos)
local interval = math.random(spawner.min_spawn_interval, spawner.max_spawn_interval)
if replacement_node_name and replacement_node_name ~= "" then
-- Check if variations are forced
local force_variation = false
--minetest.log("Spawner data: "..dump(spawners[spawner_name].replacement_nodes[replacement_node_name]))
if spawners[spawner_name].replacement_nodes[replacement_node_name].variations_only == true then
force_variation = true
end
-- Entity names for which we are going to search
local search_names = {}
local variation_names = {}
local raw_var_names = spawners[spawner_name].replacement_nodes[replacement_node_name].variations
if raw_var_names then
for name,_ in pairs(raw_var_names) do
variation_names[#variation_names + 1] = name
end
end
-- If variations are forced, only take the variation names
if force_variation == true then
search_names = variation_names
else
search_names = spawners[spawner_name].entities.all_entity_names
end
-- Search for nearby players and entities
local objects = minetest.get_objects_inside_radius(pos, 10)
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 then
-- Check if the found entity has the name of one the entities
-- that this spawner cares about
for i = 1, #search_names do
if object:get_luaentity().entity_name == search_names[i] then
entity_count = entity_count + 1
break
end
end
end
end
end
-- Create a list of names we are to spawn
local spawn_names = {}
if force_variation then
spawn_names = variation_names
elseif #variation_names > 0 then
spawn_names[#spawn_names + 1] = spawners[spawner_name].entities.default
for i = 1, #variation_names do
spawn_names[#spawn_names + 1] = variation_names[i]
end
else
spawn_names[#spawn_names + 1] = spawners[spawner_name].entities.default
end
-- Choose an entity name.
local is_variation = false
if force_variation == true then
entity_name = spawn_names[math.random(1, #spawn_names)]
--minetest.log("New entity name: "..dump(entity_name))
is_variation = true
minetest.log("Spawning variation "..entity_name.." (forced)")
else
local variation_chance = math.random(1, 10)
if variation_chance > 7 then
entity_name = spawn_names[math.random(1, #spawn_names)]
-- Increase variation count
meta:set_int("spawned_variation_count", meta:get_int("spawned_variation_count") + 1)
is_variation = true
minetest.log("Spawned variation count: "..meta:get_int("spawned_variation_count"))
minetest.log("Spawning variation "..entity_name.." (not forced)")
else
entity_name = spawners[spawner_name].entities.default
end
end
-- Validation: enforce entity max spawn count
local max_mob_count = spawner.max_mob_count
if force_variation then
--minetest.log("Entity name: "..dump(entity_name))
--minetest.log("Mob data: "..dump(spawners[spawner_name]
-- .replacement_nodes[replacement_node_name]
-- .variations[entity_name]))
max_mob_count = spawners[spawner_name]
.replacement_nodes[replacement_node_name]
.variations[entity_name]
.max_count or spawner.max_mob_count
entity_count = meta:get_int("spawned_variation_count")
end
minetest.log("Entity count: "..dump(entity_count))
minetest.log("Max mob count: "..dump(max_mob_count))
--minetest.log("Force: "..dump(force))
if force or (entity_count <= max_mob_count) then
-- Spawn
local spawn_pos = {x=pos.x + math.random(0, spawner.spawn_radius), y=pos.y+3, z=pos.z + math.random(0, spawner.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
}
if is_variation == true then
entity:get_luaentity().variation = true
end
end
minetest.log("Next spawning scheduled in "..interval.." seconds")
else
minetest.log("Max spawn limit reached")
-- Re-calulate interval using deactivation times
interval = math.random(spawner.min_deactivation_time, spawner.max_deactivation_time)
minetest.log("Deactivating spawner for "..interval.." seconds")
end
end
-- Re-schedule
timer:start(interval)
end
end
natspawner.register_spawner = function(spawner_name, def)
spawners[spawner_name] = {
entities = def.entities,
replacement_nodes = def.node_replacement_map,
min_player_distance = def.min_player_distance or 10,
max_spawn_interval = def.max_spawn_interval or 300, --300
min_spawn_interval = def.min_spawn_interval or 120, --120
spawn_radius = def.spawn_radius or 15,
min_kill_count = def.min_kill_count or 20,
max_kill_count = def.max_kill_count or 35,
min_deactivation_time = def.min_deactivation_time or 60,
max_deactivation_time = def.max_deactivation_time or 120,
max_mob_count = def.max_mob_count or 15,
spawn_on_dig = def.spawn_on_dig
}
-- Process all names
local all_names = {}
all_names[#all_names + 1] = def.entities.default
for i = 1, #def.entities.others do
all_names[#all_names + 1] = def.entities.others[i]
end
spawners[spawner_name].entities.all_entity_names = all_names
spawner_count = spawner_count + 1
-- Register all spawners
for _,val in pairs(def.node_replacement_map) do
minetest.register_node("natspawner:"..spawner_name..val.name, {
description = "Spawner",
drop = "natspawner:"..spawner_name.."_"..val.name,
tiles = val.tiles,
groups = {crumbly=2, soil = 2},
sounds = default.node_sound_sand_defaults(),
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("spawner_name", spawner_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("max_variation_count",
math.random(def.min_variation_count or 0, def.max_variation_count or 0))
meta:set_int("next_deactivation_count",
math.random(def.min_kill_count, def.max_kill_count))
meta:set_int("next_deactivation_time",
math.random(def.min_deactivation_time, def.max_deactivation_time))
local timer = minetest.get_node_timer(pos)
timer:start(def.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 def.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
natspawner.register_spawner("zombie", {
entities = {
default = "natspawner:zombie",
others = {
"natspawner:giant_zombie",
"natspawner:ice_zombie",
"natspawner:sand_zombie",
"natspawner:sand_zombie_small"
},
},
node_replacement_map = {
["default:stone"] = {
name = "stone_spawner",
tiles = {"default_stone.png^[cracko:1:2", "default_stone.png", {name = "default_stone.png"}}
},
["default:sand"] = {
name = "sand_spawner",
tiles = {"default_sand.png^[cracko:1:2", "default_sand.png", {name = "default_sand.png"}},
variations = {
["natspawner:sand_zombie"] = {},
["natspawner:sand_zombie_small"] = {
max_count = 5
}
},
variations_only = true
},
["default:desert_sand"] = {
name = "desert_sand_spawner",
tiles = {"default_desert_sand.png^[cracko:1:2", "default_desert_sand.png", {name = "default_desert_sand.png"}},
variations = {
["natspawner:sand_zombie"] = {},
["natspawner:sand_zombie_small"] = {
max_count = 5
}
},
variations_only = true
},
["default:ice"] = {
name = "ice_spawner",
tiles = {"default_ice.png^[cracko:1:2", "default_ice.png", {name = "default_ice.png"}},
variations = {
["natspawner:ice_zombie"] = {
max_count = 15,
min_count = 10
}
},
variations_only = true
},
["default:snowblock"] = {
name = "snowblock_spawner",
tiles = {"default_snow.png^[cracko:1:2", "default_snow.png", {name = "default_snow.png"}},
variations = {
["natspawner:ice_zombie"] = {
max_count = 15,
min_count = 10
}
},
variations_only = true
},
["default:dirt_with_grass"] = {
name = "dirt_with_grass_spawner",
tiles = {"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",
tiles = {"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",
tiles = {"default_snow.png^[cracko:1:2", "default_dirt.png", {name = "default_dirt.png^default_snow_side.png"}},
variations = {
["natspawner:ice_zombie"] = {
max_count = 15,
min_count = 10
}
},
variations_only = true
},
["default:dirt_with_rainforest_litter"] = {
name = "dirt_with_rainforest_litter_spawner",
tiles = {"default_rainforest_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",
tiles = {"default_coniferous_litter.png^[cracko:1:2", "default_dirt.png", {name = "default_dirt.png^default_coniferous_litter_side.png"}}
},
["default:permafrost"] = {
name = "permafrost_spawner",
tiles = {"default_permafrost.png^[cracko:1:2", "default_permafrost.png", {name = "default_permafrost.png"}},
variations = {
["natspawner:ice_zombie"] = {}
}
},
["default:permafrost_with_stones"] = {
name = "permafrost_with_stones_spawner",
tiles = {"default_permafrost.png^default_stones.png^[cracko:1:2", "default_permafrost.png", {name = "default_permafrost.png"}},
variations = {
["natspawner:ice_zombie"] = {}
}
},
["default:permafrost_with_moss"] = {
name = "permafrost_with_moss_spawner",
tiles = {"default_moss.png^[cracko:1:2", "default_permafrost.png", {name = "default_permafrost.png^default_moss_side.png"}},
variations = {
["natspawner:ice_zombie"] = {}
}
}
},
min_player_distance = 5, --20
max_mob_count = 5, --15
max_spawn_interval = 10, --300
min_spawn_interval = 5, --120
spawn_radius = 5,
min_kill_count = 5,
max_kill_count = 10,
min_deactivation_time = 5,
max_deactivation_time = 5,
spawn_on_dig = true
})
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
local function is_air_or_buildable(node)
return node
and node.name
and (node.name == "air"
or minetest.registered_nodes[node.name].buildable_to == true)
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",
"default:dirt_with_coniferous_litter",
"default:permafrost",
"default:permafrost_with_moss",
"default:permafrost_with_stones",
"default:sand",
"default:desert_sand"
})
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",
"default:dirt_with_coniferous_litter",
"default:permafrost",
"default:permafrost_with_moss",
"default:permafrost_with_stones",
"default:sand",
"default:desert_sand"
})
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 is_air_or_buildable(next_node_above) and is_air_or_buildable(next_mapblock_above) then
-- Choose a spawner
for i = 1, spawner_count do
local spawner_name = next(spawners)
local chance = math.random(1, spawner_count)
if chance == i then
-- Create spawner
minetest.after(0.8, function(spawner_name, pos)
local node_map = spawners[spawner_name].replacement_nodes
local node_to_replace = minetest.get_node(pos)
if node_map[node_to_replace.name] then
minetest.log("Replacing "..node_to_replace.name.." with "..spawner_name)
minetest.log("Creating advanced spawner at "..minetest.pos_to_string(pos))
minetest.set_node(pos, {name="natspawner:"..spawner_name..node_map[node_to_replace.name].name})
local meta = minetest.get_meta(pos)
meta:set_string("replaced_node_name", node_to_replace.name)
else
minetest.log("Unable to find replacement for node '"..dump(node_to_replace.name).."'")
end
end, spawner_name, 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),
})

522
init.lua
View File

@ -1,523 +1,7 @@
natspawner = {}
local spawners = {}
spawner_count = 0
local path = minetest.get_modpath("natspawner")
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", meta:get_int("spawned_variation_count") - 1)
end
end
end
})
local function spawn(pos, force)
local meta = minetest.get_meta(pos)
local spawner_name = meta:get_string("spawner_name")
if spawner_name then
local spawner = spawners[spawner_name]
local replacement_node_name = meta:get_string("replaced_node_name")
local timer = minetest.get_node_timer(pos)
local interval = math.random(spawner.min_spawn_interval, spawner.max_spawn_interval)
-- Check for players nearby
local objects = minetest.get_objects_inside_radius(pos, 25)
--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 == spawner.entity_name then
entity_count = entity_count + 1
end
end
end
if replacement_node_name and replacement_node_name ~= "" then
local max_mob_count = spawner.max_mob_count
-- Force variations only
local force_variation = false
minetest.log("Spawner data: "..dump(spawners[spawner_name].replacement_nodes[replacement_node_name]))
if spawners[spawner_name].replacement_nodes[replacement_node_name].variations_only == true then
force_variation = true
end
if force_variation
and spawners[spawner_name].replacement_nodes[replacement_node_name].max_count then
max_mob_count = spawners[spawner_name].replacement_nodes[replacement_node_name].max_count
minetest.log("The max count: "..dump(max_mob_count))
entity_count = meta:get_int("spawned_variation_count")
end
minetest.log("Entity count: "..dump(entity_count))
minetest.log("Max mob count: "..dump(max_mob_count))
minetest.log("Force: "..dump(force))
-- Check for amount nearby
if force or (entity_count <= max_mob_count) then
-- Spawn
local spawn_pos = {x=pos.x + math.random(0, spawner.spawn_radius), y=pos.y+3, z=pos.z + math.random(0, spawner.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 "..spawner.entity_name.." at pos "..minetest.pos_to_string(spawn_pos))
local entity = minetest.add_entity(spawn_pos, spawner.entity_name)
if entity then
entity:get_luaentity().entity_name = spawner.entity_name
entity:get_luaentity().spawn = {
pos = pos
}
local max_variation_count = meta:get_int("max_variation_count")
local spawned_variation_count = meta:get_int("spawned_variation_count")
-- Spawn a variation with 30% chance
local variation_chance = math.random(1, 10)
local variations = spawners[spawner_name].replacement_nodes[replacement_node_name].variations
minetest.log("")
if (variations
and spawned_variation_count < max_variation_count
and variation_chance > 7) or force_variation == true then
-- Choose a variation
local index = math.random(1, #variations)
if spawners[spawner_name].variations.data[variations[index]] ~= nil then
local registered_variation = spawners[spawner_name].variations.data[variations[index]]
minetest.log("Spawning variation "..dump(variations[index]))
entity:get_luaentity().variation = true
-- Velocity
if registered_variation.walk_velocity then
entity:get_luaentity().walk_velocity =
registered_variation.walk_velocity
end
if registered_variation.run_velocity then
entity:get_luaentity().run_velocity =
registered_variation.run_velocity
end
-- View range
if registered_variation.view_range then
entity:get_luaentity().view_range =
registered_variation.view_range
end
-- HP
if registered_variation.hp_min and registered_variation.hp_max then
local hp =
math.random(registered_variation.hp_min, registered_variation.hp_max)
entity:get_luaentity().hp_max = hp
entity:get_luaentity().health = hp
entity:get_luaentity().old_health = hp
end
-- Damage
if registered_variation.damage then
entity:get_luaentity().damage = registered_variation.damage
end
if registered_variation.reach then
entity:get_luaentity().reach = registered_variation.reach
end
-- Armor
if registered_variation.armor then
entity:set_armor_groups({immortal = 1, fleshy = registered_variation.armor})
end
if registered_variation.knock_back then
entity:get_luaentity().knock_back = registered_variation.knock_back
end
if registered_variation.visual_size then
-- Size properties
entity:set_properties({
visual_size = registered_variation.visual_size,
collisionbox = registered_variation.collisionbox,
stepheight = registered_variation.stepheight
})
end
-- Textures
if registered_variation.textures then
entity:set_properties({
textures = registered_variation.textures
})
end
-- Increase variation count
meta:set_int("spawned_variation_count", meta:get_int("spawned_variation_count") + 1)
end
end
end
minetest.log("Spawned variation count: "..meta:get_int("spawned_variation_count"))
minetest.log("Next spawning scheduled in "..interval.." seconds")
else
minetest.log("Max spawn limit reached")
-- Re-calulate interval using deactivation times
interval = math.random(spawner.min_deactivation_time, spawner.max_deactivation_time)
minetest.log("Deactivating spawner for "..interval.." seconds")
end
end
-- Re-schedule
timer:start(interval)
end
end
natspawner.register_spawner = function(spawner_name, def)
spawners[spawner_name] = {
entity_name = def.entity_name,
variations = {
data = def.entity_variations
},
replacement_nodes = def.node_replacement_map,
min_player_distance = def.min_player_distance or 10,
max_spawn_interval = def.max_spawn_interval or 300, --300
min_spawn_interval = def.min_spawn_interval or 120, --120
spawn_radius = def.spawn_radius or 15,
min_kill_count = def.min_kill_count or 20,
max_kill_count = def.max_kill_count or 35,
min_deactivation_time = def.min_deactivation_time or 60,
max_deactivation_time = def.max_deactivation_time or 120,
max_mob_count = def.max_mob_count or 15,
spawn_on_dig = def.spawn_on_dig
}
spawner_count = spawner_count + 1
-- Register all spawners
for _,val in pairs(def.node_replacement_map) do
minetest.register_node("natspawner:"..spawner_name..val.name, {
description = "Spawner",
drop = "natspawner:"..spawner_name.."_"..val.name,
tiles = val.tiles,
groups = {crumbly=2, soil = 2},
sounds = default.node_sound_sand_defaults(),
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("spawner_name", spawner_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("max_variation_count",
math.random(def.min_variation_count or 0, def.max_variation_count or 0))
meta:set_int("next_deactivation_count",
math.random(def.min_kill_count, def.max_kill_count))
meta:set_int("next_deactivation_time",
math.random(def.min_deactivation_time, def.max_deactivation_time))
local timer = minetest.get_node_timer(pos)
timer:start(def.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 def.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
natspawner.register_spawner("zombie", {
entity_name = "natspawner:zombie",
entity_variations = {
["giant_zombie"] =
{
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,
walk_velocity = 1.5,
run_velocity = 3,
view_range = 20,
hp_min = 215,
hp_max = 315,
damage = 12,
reach = 4,
armor = 325,
knock_back = false,
},
["ice_zombie"] = {
textures = {"mobs_zombie_ice.png"}
},
["sand_zombie_small"] = {
textures = {"mobs_zombie_sand.png"},
visual_size = {x=0.5, y=0.5, z=0.5},
}
},
node_replacement_map = {
["default:stone"] = {
name = "stone_spawner",
tiles = {"default_stone.png^[cracko:1:2", "default_stone.png", {name = "default_stone.png"}}
},
["default:sand"] = {
name = "sand_spawner",
tiles = {"default_sand.png^[cracko:1:2", "default_sand.png", {name = "default_sand.png"}},
variations = {"sand_zombie_small"}
},
["default:desert_sand"] = {
name = "desert_sand_spawner",
tiles = {"default_desert_sand.png^[cracko:1:2", "default_desert_sand.png", {name = "default_desert_sand.png"}}
},
["default:ice"] = {
name = "ice_spawner",
tiles = {"default_ice.png^[cracko:1:2", "default_ice.png", {name = "default_ice.png"}},
variations = {"ice_zombie"},
variations_only = true,
max_count = 15,
min_count = 10
},
["default:snowblock"] = {
name = "snowblock_spawner",
tiles = {"default_snow.png^[cracko:1:2", "default_snow.png", {name = "default_snow.png"}},
variations = {"ice_zombie"},
variations_only = true,
max_count = 15,
min_count = 10
},
["default:dirt_with_grass"] = {name = "dirt_with_grass_spawner", tiles = {"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", tiles = {"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",
tiles = {"default_snow.png^[cracko:1:2", "default_dirt.png", {name = "default_dirt.png^default_snow_side.png"}},
variations = {"ice_zombie"},
variations_only = true,
max_count = 15,
min_count = 10
},
["default:dirt_with_rainforest_litter"] = {name = "dirt_with_rainforest_litter_spawner", tiles = {"default_rainforest_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", tiles = {"default_coniferous_litter.png^[cracko:1:2", "default_dirt.png", {name = "default_dirt.png^default_coniferous_litter_side.png"}}},
["default:permafrost"] = {name = "permafrost_spawner", tiles = {"default_permafrost.png^[cracko:1:2", "default_permafrost.png", {name = "default_permafrost.png"}}},
["default:permafrost_with_stones"] = {name = "permafrost_with_stones_spawner", tiles = {"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", tiles = {"default_moss.png^[cracko:1:2", "default_permafrost.png", {name = "default_permafrost.png^default_moss_side.png"}}}
},
min_player_distance = 5, --20
max_mob_count = 5, --15
max_spawn_interval = 10, --300
min_spawn_interval = 5, --120
spawn_radius = 5,
min_kill_count = 5,
max_kill_count = 10,
min_deactivation_time = 5,
max_deactivation_time = 5,
spawn_on_dig = true
})
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
local function is_air_or_buildable(node)
return node
and node.name
and (node.name == "air"
or minetest.registered_nodes[node.name].buildable_to == true)
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",
"default:dirt_with_coniferous_litter",
"default:permafrost",
"default:permafrost_with_moss",
"default:permafrost_with_stones",
"default:sand",
"default:desert_sand"
})
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",
"default:dirt_with_coniferous_litter",
"default:permafrost",
"default:permafrost_with_moss",
"default:permafrost_with_stones",
"default:sand",
"default:desert_sand"
})
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 is_air_or_buildable(next_node_above) and is_air_or_buildable(next_mapblock_above) then
-- Choose a spawner
for i = 1, spawner_count do
local spawner_name = next(spawners)
local chance = math.random(1, spawner_count)
if chance == i then
-- Create spawner
minetest.after(0.8, function(spawner_name, pos)
local node_map = spawners[spawner_name].replacement_nodes
minetest.log("Creating advanced spawner at "..minetest.pos_to_string(pos))
local node_to_replace = minetest.get_node(pos)
minetest.log("Replacing "..node_to_replace.name.." with "..spawner_name)
minetest.set_node(pos, {name="natspawner:"..spawner_name..node_map[node_to_replace.name].name})
local meta = minetest.get_meta(pos)
meta:set_string("replaced_node_name", node_to_replace.name)
end, spawner_name, 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),
})
dofile(path .. "/api.lua")
dofile(path .. "/mobs.lua")

381
mobs.lua Normal file
View File

@ -0,0 +1,381 @@
-- Entity registrations
local function normal_attack(self, to_attack)
--set_animation(self, "punch")
-- local p2 = to_attack
-- local s2 = self.object:get_pos()
-- p2.y = p2.y + .5
-- s2.y = s2.y + .5
--local line = minetest.line_of_sight(p2, s2)
--minetest.log(dump(line))
--r, pos = minetest.line_of_sight(p2, s2, stepsize)
--if line_of_sight(self, p2, s2) == true then
-- play attack sound
--mob_sound(self, self.sounds.attack)
-- punch player (or what player is attached to)
local attached = self.attack:get_attach()
if attached then
self.attack = attached
end
self.attack:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = self.damage}
}, nil)
--end
end
-- Default zombie
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 = natspawner.on_mob_die
})
mobs:register_mob("natspawner:giant_zombie", {
type = "monster",
passive = false,
attack_type = "dogfight",
damage = 4,
reach = 2,
hp_min = 12,
hp_max = 35,
armor = 150,
collisionbox = {-0.625, -2.5, -2.8, 0.625, 1.875, 2.8},
visual = "mesh",
mesh = "creatures_mob.x",
textures = {
{"mobs_zombie.png"},
},
visual_size = {x=2.5, y=2.5, z=2.5},
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 = natspawner.on_mob_die
})
mobs:register_mob("natspawner:ice_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_ice.png"},
},
visual_size = {x=1, y=1},
makes_footstep_sound = true,
sounds = {
random = "mobs_zombie.1",
damage = "mobs_zombie_ice_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,
},
blood_amount = 4,
blood_texture = "default_ice.png",
after_activate = function(self)
self.ice_attack_timer = 0
end,
on_rightclick = function(self, clicker)
minetest.log(dump(self))
end,
on_die = natspawner.on_mob_die,
custom_attack = function(self, to_attack)
self.ice_attack_timer = self.ice_attack_timer + 1
if self.ice_attack_timer >= 5 then
self.ice_attack_timer = 0
local chance = math.random(1, 5)
if chance > 3 then
-- TODO: Add particle effects
minetest.log("Ice")
minetest.set_node(to_attack, {name="natspawner:freezing_ice"})
minetest.set_node({x=to_attack.x, y=to_attack.y+1, z=to_attack.z}, {name="natspawner:freezing_ice"})
-- Remove node
minetest.after(math.random(1,2), function(pos)
minetest.sound_play("default_break_glass")
minetest.set_node(to_attack, {name="air"})
minetest.set_node({x=to_attack.x, y=to_attack.y+1, z=to_attack.z}, {name="air"})
end, to_attack)
end
end
normal_attack(self, to_attack)
end
})
mobs:register_mob("natspawner:sand_zombie_small", {
type = "monster",
passive = false,
attack_type = "dogfight",
damage = 6,
reach = 2,
hp_min = 12,
hp_max = 35,
armor = 100,
collisionbox = {-0.1625, -0.65, -0.195, 0.1625, 0.4875, 0.195},
visual = "mesh",
mesh = "creatures_mob.x",
textures = {
{"mobs_zombie_sand.png"},
},
visual_size = {x=0.675, y=0.65, z=0.675},
makes_footstep_sound = true,
sounds = {
random = "mobs_zombie",
damage = "mobs_zombie_sand_hit",
attack = "mobs_zombie",
death = "mobs_zombie_death",
},
walk_velocity = 1.5,
run_velocity = 3,
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,
},
blood_amount = 7,
blood_texture = "default_sand.png",
on_rightclick = function(self, clicker)
minetest.log(dump(self))
end,
on_die = natspawner.on_mob_die
})
mobs:register_mob("natspawner:sand_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_sand.png"},
},
visual_size = {x=1, y=1},
makes_footstep_sound = true,
sounds = {
random = "mobs_zombie",
damage = "mobs_zombie_sand_hit",--"mobs_zombie_hit",
attack = "mobs_zombie",
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,
},
blood_amount = 7,
blood_texture = "default_sand.png",
on_rightclick = function(self, clicker)
minetest.log(dump(self))
end,
on_die = function(self, pos)
-- TODO: Add particle effects
--minetest.add_particle_spawner()
local positions = {}
for x = -1, 1 do
for z = -1, 1 do
local chance = math.random(1, 2)
if (chance > 1) then
minetest.set_node({x=pos.x + x, y=pos.y-1, z=pos.z + z}, {name="natspawner:evil_sand"})
positions[#positions + 1] = {x=pos.x + x, y = pos.y-1, z=pos.z + z}
end
end
end
minetest.after(1, function(positions)
for i = 1, #positions do
local chance = math.random(1, 10)
if (chance > 5) then
minetest.add_entity({x=positions[i].x, y=positions[i].y+1, z=positions[i].z}, "natspawner:sand_zombie_small")
end
end
--minetest.add_entity({x=pos.x - 1, y=pos.y, z=pos.z}, "natspawner:sand_zombie_small")
end, positions)
-- Spawner callback
natspawner.on_mob_die(self, pos)
end
})
-- Nodes
minetest.register_node("natspawner:freezing_ice", {
description = "Freezing Ice",
drawtype = "glasslike",
tiles = {"freezing_ice.png"},
paramtype = "light",
walkable = false,
pointable = true,
diggable = true,
buildable_to = false,
drop = "",
drowning = 1,
liquid_renewable = false,
liquidtype = "source",
use_textrure_alpha = true,
liquid_range= 0,
liquid_alternative_flowing = "natspawner:freezing_ice",
liquid_alternative_source = "natspawner:freezing_ice",
liquid_viscosity = 30,
post_effect_color = {a = 103, r = 30, g = 60, b = 90},
groups = {cracky = 3, cools_lava = 1, slippery = 3, flammable=2, liquid=1, not_in_creative_inventory=1},
})
minetest.register_node("natspawner:evil_sand", {
description = "Evil Sand",
tiles = {"default_sand.png"},
inventory_image = "default_snowball.png",
wield_image = "default_snowball.png",
paramtype = "light",
buildable_to = true,
floodable = true,
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, -0.25, 0.5},
},
},
collision_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, -7 / 16, 0.5},
},
},
groups = {crumbly = 3, falling_node = 1, sand = 1},
sounds = default.node_sound_sand_defaults(),
damage_per_second = 2
})

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
textures/freezing_ice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB