commit 74adc847b65c7b79a875839a7d0b5db8ba382d40 Author: Juraj Vajda Date: Thu Jan 7 20:22:12 2016 +0100 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..ac12497 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +*Mob Spawners* + +This mod for minetest lets the player configure and craft a Spawners blocks for mobs. diff --git a/depends.txt b/depends.txt new file mode 100644 index 0000000..4339400 --- /dev/null +++ b/depends.txt @@ -0,0 +1,5 @@ +default +mobs? +fake_fire? +xpanes? +creatures? diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..88499cb --- /dev/null +++ b/init.lua @@ -0,0 +1,389 @@ +local max_obj_per_mapblock = tonumber(minetest.setting_get("max_objects_per_block")) + +-- main table +spawners = {} +-- list of mods +spawners.mob_mods = {"mobs", "testmod"} +-- table holding all mobs info +spawners.mob_tables = {} + +-- check if mods exists and build tables +for k, v in ipairs(spawners.mob_mods) do + + local modpath = minetest.get_modpath(v) + + if (modpath) then + -- list of mobs and their info + table.insert(spawners.mob_tables, {name="sheep_white", mod_prefix_default=v, mod_prefix_custom="", dummy_size={x=0.52,y=0.52}, dummy_offset=0.2, dummy_mesh="mobs_sheep.b3d", dummy_texture={"mobs_sheep_white.png"}, night_only=false}) + + table.insert(spawners.mob_tables, {name="cow", mod_prefix_default=v, mod_prefix_custom="", dummy_size={x=0.3,y=0.3}, dummy_offset=-0.3, dummy_mesh="mobs_cow.x", dummy_texture={"mobs_cow.png"}, night_only=false}) + + table.insert(spawners.mob_tables, {name="chicken", mod_prefix_default=v, mod_prefix_custom="", dummy_size={x=0.9,y=0.9}, dummy_offset=0.2, dummy_mesh="mobs_chicken.x", dummy_texture={"mobs_chicken.png", "mobs_chicken.png", "mobs_chicken.png", "mobs_chicken.png", "mobs_chicken.png", "mobs_chicken.png", "mobs_chicken.png", "mobs_chicken.png", "mobs_chicken.png"}, night_only=false}) + + table.insert(spawners.mob_tables, {name="warthog", mod_prefix_default=v, mod_prefix_custom="", dummy_size={x=0.62,y=0.62}, dummy_offset=-0.3, dummy_mesh="mobs_warthog.x", dummy_texture={"mobs_warthog.png"}, night_only=true}) + + table.insert(spawners.mob_tables, {name="bunny", mod_prefix_default=v, mod_prefix_custom="", dummy_size={x=1,y=1}, dummy_offset=0.2, dummy_mesh="mobs_bunny.b3d", dummy_texture={"mobs_bunny_brown.png"}, night_only=false}) + + table.insert(spawners.mob_tables, {name="kitten", mod_prefix_default=v, mod_prefix_custom="", dummy_size={x=0.32,y=0.32}, dummy_offset=0, dummy_mesh="mobs_kitten.b3d", dummy_texture={"mobs_kitten_ginger.png"}, night_only=false}) + else + print("[Spawners] MOD: "..v.." not found.") + end +end + +-- start spawning mobs +function spawners.start_spawning(pos, how_many, mob_name, mod_prefix) + if not pos or not how_many or not mob_name then return end + + local sound_name + -- remove 'spawners:' from the string + local mob_name = string.sub(mob_name,10) + + -- fix some namings + if mob_name == "sheep_white" then + sound_name = "sheep" + elseif mob_name == "warthog" then + sound_name = "pig" + else + sound_name = mob_name + end + + for i=1,how_many do + + -- local x = 1/math.random(1,3) + -- local z = 1/math.random(1,3) + -- local p = {x=pos.x+x,y=pos.y,z=pos.z+z} + + local obj = minetest.add_entity(pos, mod_prefix..":"..mob_name) + + if obj then + + if sound_name then + minetest.sound_play(mod_prefix.."_"..sound_name, { + pos = pos, + max_hear_distance = 32, + gain = 10, + }) + end + + minetest.log("action", "Spawners: spawned "..mob_name.." at ("..pos.x..","..pos.y..","..pos.z..")") + end + + end +end + +function spawners.check_around_radius(pos) + local player_near = false + local radius = 21 + + for _,obj in ipairs(minetest.get_objects_inside_radius(pos, radius)) do + if obj:is_player() then + player_near = true + end + end + + return player_near +end + +function check_node_status(pos, mob, night_only) + local player_near = spawners.check_around_radius(pos) + local random_pos = false + + if player_near then + local min_node_light = 10 + local tod = minetest.get_timeofday() * 24000 + local node_light = minetest.get_node_light(pos) + local spawn_positions = {} + local front = minetest.get_node({x=pos.x+1, y=pos.y, z=pos.z}) + local right = minetest.get_node({x=pos.x, y=pos.y, z=pos.z+1}) + local back = minetest.get_node({x=pos.x-1, y=pos.y, z=pos.z}) + local left = minetest.get_node({x=pos.x, y=pos.y, z=pos.z-1}) + local top = minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}) + local bottom = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}) + + if not node_light then return end + + -- make sure that at least one side of the spawner is open + if front.name == "air" then + table.insert(spawn_positions, {x=pos.x+1.5, y=pos.y, z=pos.z}) + end + if right.name == "air" then + table.insert(spawn_positions, {x=pos.x, y=pos.y, z=pos.z+1.5}) + end + if back.name == "air" then + table.insert(spawn_positions, {x=pos.x-1.5, y=pos.y, z=pos.z}) + end + if left.name == "air" then + table.insert(spawn_positions, {x=pos.x, y=pos.y, z=pos.z-1.5}) + end + if top.name == "air" then + table.insert(spawn_positions, {x=pos.x, y=pos.y+1.5, z=pos.z}) + end + if bottom.name == "air" then + table.insert(spawn_positions, {x=pos.x, y=pos.y-1.5, z=pos.z}) + end + + -- spawner is closed from all sides + if not (front or right or back or left or top or bottom) then + minetest.log("action","spawner is closed") + return false + end + + local pick_random = math.random(1,#spawn_positions) + + -- pick random from the open sides + for k, v in pairs (spawn_positions) do + if k == pick_random then + random_pos = v + end + end + + if not random_pos then return end + + print("#spawn_positions: "..#spawn_positions) + print("pick_random: "..pick_random) + print("node_light: "..node_light) + -- print("node_pos"..minetest.pos_to_string(pos)) + -- print("random_pos"..minetest.pos_to_string(random_pos)) + + -- check the node above the found air node + local node_above = minetest.get_node({x=random_pos.x, y=random_pos.y+1, z=random_pos.z}).name + local node_below = minetest.get_node({x=random_pos.x, y=random_pos.y-1, z=random_pos.z}).name + + print("node_above: "..node_above) + print("node_below: "..node_below) + + if not (node_above == "air" or node_below == "air") then + print("node below or above is not air") + return false + end + + if not night_only and node_light < min_node_light then + print("not enough light") + return false + end + + -- At 0 time of day (tod) the day begins; it is midnight and the moon is exactly at the zenith (1). + -- At 4500 tod, the first sun rays emit from the horizon, it gets brighter (2). + -- At 4750 tod, the sun rises and it gets brighter (3). + -- At 5001 tod, it gets brighter again (4). + -- At 5200 tod, the sun becomes fully visible (4). + -- At 5250 tod, it gets brighter again (5). + -- At 5500 tod, it gets brighter again (6). + -- At 5751 tod, maximum brightness is reached (7). + -- At 12000 tod is midday; the sun is exactly at the zenith (7). + -- At 18250 tod, the day is going to end, it gets a bit darker (6). + -- At 18502 tod, it gets a bit darker again (5). + -- At 18600 tod, the sun begins to set (5). + -- At 18752 tod, it gets a bit darker yet again (4). + -- At 19000 tod, the sky gets even darker (3). + -- At 19252 tod, the sun is almost gone and the sky gets even darker (2). + -- At 19359 tod, the sun square is gone and the last sun rays emit from the horizon (2). + -- At 19500 tod, the sun rays stop from being visible (2). + -- At 19502 tod, the sky has the lowest brightness (1). + -- At 24000 tod, the day ends and the next one starts; it is midnight again (1). + + if night_only then + print("tod: "..tod) + if not (19359 > tod and tod > 5200) or node_light < min_node_light then + print("it's night") + if random_pos then + return random_pos + else + return false + end + else + return false + end + end + + return random_pos + else + return false + end +end + +function spawners.create(mob_name, mod_prefix, size, offset, mesh, texture, night_only) + local dummy_definition = { + hp_max = 1, + physical = true, + collisionbox = {0,0,0,0,0,0}, + visual = "mesh", + visual_size = size, + mesh = mesh, + textures = texture, + makes_footstep_sound = false, + timer = 0, + automatic_rotate = math.pi * -3, + m_name = "dummy" + } + + dummy_definition.on_activate = function(self) + self.object:setvelocity({x=0, y=0, z=0}) + self.object:setacceleration({x=0, y=0, z=0}) + self.object:set_armor_groups({immortal=1}) + end + + -- remove dummy after dug up the spawner + dummy_definition.on_step = function(self, dtime) + self.timer = self.timer + dtime + local n = minetest.get_node_or_nil(self.object:getpos()) + if self.timer > 2 then + if n and n.name and n.name ~= "spawners:"..mob_name.."_spawner_active" then + self.object:remove() + end + end + end + + minetest.register_entity("spawners:dummy_"..mob_name, dummy_definition) + + -- node spawner active + minetest.register_node("spawners:"..mob_name.."_spawner_active", { + description = mob_name.." spawner active", + paramtype = "light", + light_source = 4, + drawtype = "allfaces", + walkable = true, + damage_per_second = 4, + sunlight_propagates = true, + tiles = { + { + name = "spawners_spawner_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 2.0 + }, + } + }, + is_ground_content = true, + groups = {cracky=1,level=2,igniter=1,not_in_creative_inventory=1}, + drop = "spawners:"..mob_name.."_spawner", + on_construct = function(pos) + pos.y = pos.y + offset + minetest.add_entity(pos,"spawners:dummy_"..mob_name) + end, + }) + + -- node spawner inactive + minetest.register_node("spawners:"..mob_name.."_spawner", { + description = mob_name.." spawner", + paramtype = "light", + drawtype = "allfaces", + walkable = true, + sunlight_propagates = true, + tiles = {"spawners_spawner.png"}, + is_ground_content = true, + groups = {cracky=1,level=2}, + on_construct = function(pos) + local random_pos = check_node_status(pos, mob_name, night_only) + + if random_pos then + minetest.set_node(pos, {name="spawners:"..mob_name.."_spawner_active"}) + else + minetest.log("action","no random_pos found") + end + end, + }) + + -- node spawner overheated + minetest.register_node("spawners:"..mob_name.."_spawner_overheat", { + description = mob_name.." spawner overheated", + paramtype = "light", + light_source = 2, + drawtype = "allfaces", + walkable = true, + damage_per_second = 4, + sunlight_propagates = true, + tiles = {"spawners_spawner.png^[colorize:#FF000030"}, + is_ground_content = true, + groups = {cracky=1,level=2,igniter=1,not_in_creative_inventory=1}, + drop = "spawners:"..mob_name.."_spawner", + on_construct = function(pos) + minetest.get_node_timer(pos):start(60) + end, + on_timer = function(pos, elapsed) + minetest.log("action", "============= timer elapsed: "..elapsed) + minetest.set_node(pos, {name="spawners:"..mob_name.."_spawner"}) + end, + }) + + -- abm + minetest.register_abm({ + nodenames = {"spawners:"..mob_name.."_spawner", "spawners:"..mob_name.."_spawner_active", "spawners:"..mob_name.."_spawner_overheat"}, + neighbors = {"air"}, + interval = 2.0, + chance = 20, + action = function(pos, node, active_object_count, active_object_count_wider) + + minetest.log("action", "active_object_count: "..active_object_count) + minetest.log("action", "active_object_count_wider: "..active_object_count_wider) + + local random_pos = check_node_status(pos, mob_name, night_only) + + if random_pos then + -- random_pos found + + -- do not spawn if too many active entities in map block + -- call cooldown + if active_object_count_wider > max_obj_per_mapblock then + minetest.log("action", "************** too many mobs in area") + + if node.name ~= "spawners:"..mob_name.."_spawner_overheat" then + minetest.set_node(pos, {name="spawners:"..mob_name.."_spawner_overheat"}) + end + + -- extend the timeout if still too many entities in map block + if node.name == "spawners:"..mob_name.."_spawner_overheat" then + minetest.log("action", "++++++++++++++ extending timeout") + minetest.get_node_timer(pos):stop() + minetest.get_node_timer(pos):start(60) + end + + return + end + + if node.name ~= "spawners:"..mob_name.."_spawner_active" then + minetest.set_node(pos, {name="spawners:"..mob_name.."_spawner_active"}) + end + + spawners.start_spawning(random_pos, 1, "spawners:"..mob_name, mod_prefix) + else + -- no random_pos found + if minetest.get_node_timer(pos):is_started() then + minetest.get_node_timer(pos):stop() + minetest.log("action", "timer stopped") + end + + if node.name ~= "spawners:"..mob_name.."_spawner" then + minetest.set_node(pos, {name="spawners:"..mob_name.."_spawner"}) + end + end + + end + }) + +end + +-- create all spawners and crafting recipes +for i, mob_table in ipairs(spawners.mob_tables) do + if mob_table then + + local mod_prefix + if mob_table.mod_prefix_custom == "" then mod_prefix = mob_table.mod_prefix_default end + + -- spawners + spawners.create(mob_table.name, mod_prefix, mob_table.dummy_size, mob_table.dummy_offset, mob_table.dummy_mesh, mob_table.dummy_texture, mob_table.night_only) + -- recipes + minetest.register_craft({ + output = "spawners:"..mob_table.name.."_spawner", + recipe = { + {"default:diamondblock", "fake_fire:flint_and_steel", "default:diamondblock"}, + {"xpanes:bar", "spawners:"..mob_table.name, "xpanes:bar"}, + {"default:diamondblock", "xpanes:bar", "default:diamondblock"}, + } + }) + end +end + +print ("[MOD] Spawners loaded") \ No newline at end of file diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..5c93f45 --- /dev/null +++ b/license.txt @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/textures/spawners_spawner.png b/textures/spawners_spawner.png new file mode 100644 index 0000000..06037b4 Binary files /dev/null and b/textures/spawners_spawner.png differ diff --git a/textures/spawners_spawner_animated.png b/textures/spawners_spawner_animated.png new file mode 100644 index 0000000..1f7e27a Binary files /dev/null and b/textures/spawners_spawner_animated.png differ diff --git a/textures/spawners_spawner_off_animated.png b/textures/spawners_spawner_off_animated.png new file mode 100644 index 0000000..9df39a7 Binary files /dev/null and b/textures/spawners_spawner_off_animated.png differ