From 401284e05eab1e69db50fff2cece778ecb1520e1 Mon Sep 17 00:00:00 2001 From: Juraj Vajda Date: Sat, 8 Oct 2016 20:54:26 +0200 Subject: [PATCH] initial commit - create a modpack --- .gitignore | 1 + config.example.lua | 241 +++++++++++++ depends.txt | 2 - modpack.txt | 0 spawners_env/chests_gen.lua | 34 ++ spawners_env/init.lua | 42 +++ spawners_env/pyramids.lua | 260 ++++++++++++++ spawners_env/pyramids_nodes.lua | 50 +++ spawners_env/pyramids_room.lua | 78 ++++ spawners_env/spawners_gen.lua | 40 +++ spawners_mobs/api.lua | 185 ++++++++++ spawners_mobs/config.example.lua | 204 +++++++++++ spawners_mobs/depends.txt | 5 + spawners_mobs/init.lua | 18 + spawners_mobs/mob_mummy.lua | 65 ++++ .../models/spawners_mobs_mummy.b3d | Bin spawners_mobs/nodes_additional.lua | 11 + .../sounds/spawners_mobs_bunny.ogg | Bin .../sounds/spawners_mobs_mummy.1.ogg | Bin .../sounds/spawners_mobs_mummy.2.ogg | Bin .../sounds/spawners_mobs_mummy_death.1.ogg | Bin .../sounds/spawners_mobs_mummy_hit.1.ogg | Bin spawners_mobs/spawners_mobs.lua | 243 +++++++++++++ .../textures/spawners_mobs_crack.png | Bin .../textures/spawners_mobs_eye.png | Bin .../textures/spawners_mobs_men.png | Bin .../textures/spawners_mobs_mummy.png | Bin .../textures/spawners_mobs_smoke_particle.png | Bin .../textures/spawners_mobs_spawner.png | Bin .../spawners_mobs_spawner_animated.png | Bin .../textures/spawners_mobs_spawner_normal.png | Bin ...spawners_mobs_spawner_waiting_animated.png | Bin .../textures/spawners_mobs_sun.png | Bin spawners_ores/api.lua | 93 +++++ spawners_ores/depends.txt | 1 + spawners_ores/init.lua | 42 +++ {sounds => spawners_ores/sounds}/strike.ogg | Bin spawners_ores/spawners_ores.lua | 335 ++++++++++++++++++ .../textures/spawners_smoke_particle.png | Bin 0 -> 233 bytes spawners_ores/textures/spawners_spawner.png | Bin 0 -> 535 bytes .../textures/spawners_spawner_animated.png | Bin 0 -> 18168 bytes .../textures/spawners_spawner_normal.png | Bin 0 -> 7938 bytes .../spawners_spawner_waiting_animated.png | Bin 0 -> 4735 bytes 43 files changed, 1948 insertions(+), 2 deletions(-) create mode 100644 config.example.lua create mode 100644 modpack.txt create mode 100644 spawners_env/chests_gen.lua create mode 100644 spawners_env/init.lua create mode 100644 spawners_env/pyramids.lua create mode 100644 spawners_env/pyramids_nodes.lua create mode 100644 spawners_env/pyramids_room.lua create mode 100644 spawners_env/spawners_gen.lua create mode 100644 spawners_mobs/api.lua create mode 100644 spawners_mobs/config.example.lua create mode 100644 spawners_mobs/depends.txt create mode 100644 spawners_mobs/init.lua create mode 100644 spawners_mobs/mob_mummy.lua rename models/spawners_mob_mummy.b3d => spawners_mobs/models/spawners_mobs_mummy.b3d (100%) create mode 100644 spawners_mobs/nodes_additional.lua rename sounds/spawners_bunny.ogg => spawners_mobs/sounds/spawners_mobs_bunny.ogg (100%) rename sounds/spawners_mob_mummy.1.ogg => spawners_mobs/sounds/spawners_mobs_mummy.1.ogg (100%) rename sounds/spawners_mob_mummy.2.ogg => spawners_mobs/sounds/spawners_mobs_mummy.2.ogg (100%) rename sounds/spawners_mob_mummy_death.1.ogg => spawners_mobs/sounds/spawners_mobs_mummy_death.1.ogg (100%) rename sounds/spawners_mob_mummy_hit.1.ogg => spawners_mobs/sounds/spawners_mobs_mummy_hit.1.ogg (100%) create mode 100644 spawners_mobs/spawners_mobs.lua rename textures/pyramids_crack.png => spawners_mobs/textures/spawners_mobs_crack.png (100%) rename textures/pyramids_eye.png => spawners_mobs/textures/spawners_mobs_eye.png (100%) rename textures/pyramids_men.png => spawners_mobs/textures/spawners_mobs_men.png (100%) rename textures/spawners_mob_mummy.png => spawners_mobs/textures/spawners_mobs_mummy.png (100%) rename textures/spawners_smoke_particle.png => spawners_mobs/textures/spawners_mobs_smoke_particle.png (100%) rename textures/spawners_spawner.png => spawners_mobs/textures/spawners_mobs_spawner.png (100%) rename textures/spawners_spawner_animated.png => spawners_mobs/textures/spawners_mobs_spawner_animated.png (100%) rename textures/spawners_spawner_normal.png => spawners_mobs/textures/spawners_mobs_spawner_normal.png (100%) rename textures/spawners_spawner_waiting_animated.png => spawners_mobs/textures/spawners_mobs_spawner_waiting_animated.png (100%) rename textures/pyramids_sun.png => spawners_mobs/textures/spawners_mobs_sun.png (100%) create mode 100644 spawners_ores/api.lua create mode 100644 spawners_ores/depends.txt create mode 100644 spawners_ores/init.lua rename {sounds => spawners_ores/sounds}/strike.ogg (100%) create mode 100644 spawners_ores/spawners_ores.lua create mode 100644 spawners_ores/textures/spawners_smoke_particle.png create mode 100644 spawners_ores/textures/spawners_spawner.png create mode 100644 spawners_ores/textures/spawners_spawner_animated.png create mode 100644 spawners_ores/textures/spawners_spawner_normal.png create mode 100644 spawners_ores/textures/spawners_spawner_waiting_animated.png diff --git a/.gitignore b/.gitignore index 20df4d7..9a754c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ settings.txt +config.lua diff --git a/config.example.lua b/config.example.lua new file mode 100644 index 0000000..782cc56 --- /dev/null +++ b/config.example.lua @@ -0,0 +1,241 @@ +-- * [name : string] - Name of the mob used in the mod. + +-- [egg_name_custom : string] - Custom name for the egg item. If empty default name will be used i.e. 'mobs:chicken'. + +-- * [dummy_size : table] - Size of the rotating dummy inside the node. + +-- * [dummy_offset : integer] - Offset on Y axis of the dummy inside the node. + +-- * [dummy_mesh : string] - Filename of the model used fot he mob. + +-- * [dummy_texture : table] - Textures used for the mob. + +-- * [night_only : boolean : string] - If true mobs will spawn only during the night or in dark areas, default:true. Writing "disable" will disable light check and it will spawn in both states (night and day) + +-- [sound_custom : string] - Custom name for the sound file name if differ from default: i.e 'mobs_cow'. + +-- [env : boolean] - This spawner will become environmental spawner. Environmental spawners have different properties/behaviour (used for map gen) and cannot be crafted. + +-- [*] -> MANDATORY - has to be filled in! + +-- mods what should be enabled and loded, remove/add the one you want to load +ENABLED_MODS = {"mobs", "pyramids", "creatures"} + +-- mobs properties - setup all you mobs here +MOBS_PROPS = { + + ["mobs"] = { -- MOBS REDO CONFIG + { + name="sheep_white", + egg_name_custom="", + dummy_size={x=0.52,y=0.52}, + dummy_offset=0.2, + dummy_mesh="mobs_sheep.b3d", + dummy_texture={"mobs_sheep_wool.png^mobs_sheep_base.png"}, + night_only=false, + sound_custom="mobs_sheep" + }, + { + name="cow", + egg_name_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, + sound_custom="" + }, + { + name="chicken", + egg_name_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, + sound_custom="" + }, + { + name="pumba", + egg_name_custom="", + dummy_size={x=0.62,y=0.62}, + dummy_offset=-0.3, + dummy_mesh="mobs_pumba.x", + dummy_texture={"mobs_pumba.png"}, + night_only=false, + sound_custom="mobs_pig" + }, + { + name="bunny", + egg_name_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, + sound_custom="spawners_bunny" + }, + { + name="kitten", + egg_name_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, + sound_custom="" + }, + { + name="spider", + egg_name_custom="", + dummy_size={x=2,y=2}, + dummy_offset=-0.2, + dummy_mesh="mobs_spider.x", + dummy_texture={"mobs_spider.png"}, + night_only=false, + sound_custom="" + }, + { + name="spider", + egg_name_custom="", + dummy_size={x=2,y=2}, + dummy_offset=-0.2, + dummy_mesh="mobs_spider.x", + dummy_texture={"mobs_spider.png"}, + night_only="disable", + sound_custom="", + env = true + }, + { + name="stone_monster", + egg_name_custom="", + dummy_size={x=0.5,y=0.5}, + dummy_offset=0.05, + dummy_mesh="mobs_stone_monster.b3d", + dummy_texture={"mobs_stone_monster.png"}, + night_only=false, + sound_custom="mobs_stonemonster" + }, + { + name="oerkki", + egg_name_custom="", + dummy_size={x=0.5,y=0.5}, + dummy_offset=0.05, + dummy_mesh="mobs_oerkki.b3d", + dummy_texture={"mobs_oerkki.png"}, + night_only=true, + sound_custom="" + }, + { + name="tree_monster", + egg_name_custom="", + dummy_size={x=0.4,y=0.4}, + dummy_offset=0.05, + dummy_mesh="mobs_tree_monster.b3d", + dummy_texture={"mobs_tree_monster.png"}, + night_only=true, + sound_custom="mobs_treemonster" + } + }, + + ["pyramids"] = { -- PYRAMIDS MOD CONFIG + { + name="mummy", + egg_name_custom="pyramids:spawn_egg", + dummy_size={x=3.3,y=3.3}, + dummy_offset=-0.3, + dummy_mesh="pyramids_mummy.x", + dummy_texture={"pyramids_mummy.png"}, + night_only=false, + sound_custom="mummy" + } + }, + + ["creatures"] = { -- CREATURES MOD CONFIG + { + name="chicken", + egg_name_custom="creatures:chicken_spawn_egg", + dummy_size={x=0.9,y=0.9}, + dummy_offset=-0.3, + dummy_mesh="creatures_chicken.b3d", + dummy_texture={"creatures_chicken.png"}, + night_only=false, + sound_custom="" + }, + { + name="ghost", + egg_name_custom="creatures:ghost_spawn_egg", + dummy_size={x=0.7,y=0.7}, + dummy_offset=-0.5, + dummy_mesh="creatures_ghost.b3d", + dummy_texture={"creatures_ghost.png"}, + night_only=true, + sound_custom="" + }, + { + name="sheep", + egg_name_custom="creatures:sheep_spawn_egg", + dummy_size={x=0.6,y=0.6}, + dummy_offset=-0.3, + dummy_mesh="creatures_sheep.b3d", + dummy_texture={"creatures_sheep.png^creatures_sheep_white.png"}, + night_only=false, + sound_custom="" + }, + { + name="zombie", + egg_name_custom="creatures:zombie_spawn_egg", + dummy_size={x=0.5,y=0.5}, + dummy_offset=-0.5, + dummy_mesh="creatures_zombie.b3d", + dummy_texture={"creatures_zombie.png"}, + night_only=false, + sound_custom="" + }, + { + name="oerrki", + egg_name_custom="creatures:oerrki_spawn_egg", + dummy_size={x=0.4,y=0.4}, + dummy_offset=-0.5, + dummy_mesh="creatures_oerrki.b3d", + dummy_texture={"creatures_oerrki.png"}, + night_only=false, + sound_custom="creatures_oerrki_idle" + } + } +} + +-- +-- check for 3rd party dependencies +-- + +-- include mummy mobs redo addon (spawner) +if minetest.get_modpath("mobs") ~= nil then + -- enable spawner + table.insert(ENABLED_MODS, "spawners") + + -- configure spawner + MOBS_PROPS["spawners"] = { + { + name="mummy", + egg_name_custom="", + dummy_size={x=0.4,y=0.4}, + dummy_offset=0, + dummy_mesh="spawners_mob_mummy.b3d", + dummy_texture={"spawners_mob_mummy.png"}, + night_only="disable", + sound_custom="spawners_mob_mummy" + }, + { + name="mummy", + egg_name_custom="", + dummy_size={x=0.4,y=0.4}, + dummy_offset=0, + dummy_mesh="spawners_mob_mummy.b3d", + dummy_texture={"spawners_mob_mummy.png"}, + night_only="disable", + sound_custom="spawners_mob_mummy", + env=true + } + } +end \ No newline at end of file diff --git a/depends.txt b/depends.txt index 0cd0935..2581ad6 100644 --- a/depends.txt +++ b/depends.txt @@ -1,5 +1,3 @@ default mobs? creatures? -fake_fire? -xpanes? diff --git a/modpack.txt b/modpack.txt new file mode 100644 index 0000000..e69de29 diff --git a/spawners_env/chests_gen.lua b/spawners_env/chests_gen.lua new file mode 100644 index 0000000..fff5d72 --- /dev/null +++ b/spawners_env/chests_gen.lua @@ -0,0 +1,34 @@ +-- Place chests in dungeons and temples +local function place_chest(param) + local tab = param + + local pos = tab[math.random(1, (#tab or 4))] + pos.y = pos.y - 1 + + local n = minetest.get_node_or_nil(pos) + + if n and n.name ~= "air" then + pos.y = pos.y + 1 + + minetest.log("action", "[Mod][Spawners] Chest placed at: "..minetest.pos_to_string(pos)) + + minetest.set_node(pos, {name = "default:chest"}) + + pyramids.fill_chest(pos) + end +end + +minetest.set_gen_notify("dungeon") +minetest.set_gen_notify("temple") + +minetest.register_on_generated(function(minp, maxp, blockseed) + local ntf = minetest.get_mapgen_object("gennotify") + + if ntf and ntf.dungeon then + minetest.after(3, place_chest, table.copy(ntf.dungeon)) + end + + if ntf and ntf.temple then + minetest.after(3, place_chest, table.copy(ntf.temple)) + end +end) \ No newline at end of file diff --git a/spawners_env/init.lua b/spawners_env/init.lua new file mode 100644 index 0000000..12a768a --- /dev/null +++ b/spawners_env/init.lua @@ -0,0 +1,42 @@ +-- Main settings +dofile(minetest.get_modpath("spawners").."/settings.txt") + +-- Spawners configurations +dofile(minetest.get_modpath("spawners").."/config.lua") + +-- API +dofile(minetest.get_modpath("spawners").."/API.lua") + +-- Spawners for mobs +dofile(minetest.get_modpath("spawners").."/spawners_mobs.lua") + +-- Spawners for ores +dofile(minetest.get_modpath("spawners").."/spawners_ores.lua") + +-- include mummy mobs redo addon (mob) +if minetest.get_modpath("mobs") then + dofile(minetest.get_modpath("spawners").."/mob_mummy.lua") +end + +-- Spawners Pyramids +if SPAWN_PYRAMIDS then + dofile(minetest.get_modpath("spawners").."/pyramids.lua") + + print("[Mod][spawners] Pyramids enabled") +end + +-- Add Spawners to dungeons, temples.. +if SPAWNERS_GENERATE then + dofile(minetest.get_modpath("spawners").."/spawners_gen.lua") + + print("[Mod][spawners] Spawners generate enabled") +end + +-- Add Chests to dungeons, temples.. +if CHESTS_GENERATE then + dofile(minetest.get_modpath("spawners").."/chests_gen.lua") + + print("[Mod][spawners] Chests generate enabled") +end + +print ("[Mod] Spawners 0.6 Loaded.") \ No newline at end of file diff --git a/spawners_env/pyramids.lua b/spawners_env/pyramids.lua new file mode 100644 index 0000000..beabee5 --- /dev/null +++ b/spawners_env/pyramids.lua @@ -0,0 +1,260 @@ +-- Pyramids by BlockMen + +pyramids = {} + +dofile(minetest.get_modpath("spawners").."/pyramids_nodes.lua") +dofile(minetest.get_modpath("spawners").."/pyramids_room.lua") + +local chest_stuff = { + {name="default:apple", max = 3}, + {name="default:torch", max = 10}, + {name="default:aspen_sapling", max = 5}, + {name="farming:bread", max = 3}, + {name="default:steel_ingot", max = 2}, + {name="default:gold_ingot", max = 2}, + {name="default:bronze_ingot", max = 2}, + {name="default:copper_ingot", max = 2}, + {name="default:diamond", max = 1}, + {name="default:pick_steel", max = 1}, + {name="default:pick_diamond", max = 1}, + {name="default:pick_bronze", max = 1}, + {name="default:pick_mese", max = 1}, + {name="default:pick_stone", max = 1}, + {name="default:pick_wood", max = 1}, + {name="default:sword_bronze", max = 1}, + {name="default:sword_diamond", max = 1}, + {name="default:sword_mese", max = 1}, + {name="default:sword_steel", max = 1}, + {name="default:sword_stone", max = 1}, + {name="default:sword_wood", max = 1}, + {name="default:shovel_bronze", max = 1}, + {name="default:shovel_diamond", max = 1}, + {name="default:shovel_mese", max = 1}, + {name="default:shovel_steel", max = 1}, + {name="default:shovel_stone", max = 1}, + {name="default:shovel_wood", max = 1}, + {name="default:axe_bronze", max = 1}, + {name="default:axe_diamond", max = 1}, + {name="default:axe_mese", max = 1}, + {name="default:axe_steel", max = 1}, + {name="default:axe_stone", max = 1}, + {name="default:axe_wood", max = 1}, + {name="diamonds:diamond_apple", max = 1}, +} + +function pyramids.fill_chest(pos) + minetest.after(2, function() + local n = minetest.get_node(pos) + + if n and n.name and n.name == "default:chest" then + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + + inv:set_size("main", 8*4) + + -- if math.random(1,10) < 5 then return end + + for i=0,2,1 do + local stuff = chest_stuff[math.random(1,#chest_stuff)] + + if stuff.name == "farming:bread" and not minetest.get_modpath("farming") then + stuff = chest_stuff[1] + end + + if stuff.name == "diamonds:diamond_apple" and not minetest.get_modpath("diamonds") then + stuff = chest_stuff[1] + end + + local stack = {name=stuff.name, count = math.random(1,stuff.max)} + + if not inv:contains_item("main", stack) then + inv:set_stack("main", math.random(1,32), stack) + end + end + end + end) +end + +function pyramids.spawn_mummy(pos, number) + -- needs mobs redo + if minetest.get_modpath("mobs") ~= nil then + for i=0,number do + minetest.add_entity(pos,"spawners:mummy") + end + end +end + +local function add_spawner(pos) + -- needs mobs redo + if minetest.get_modpath("mobs") ~= nil then + minetest.set_node(pos, {name="spawners:spawners_mummy_spawner_env"}) + + if not minetest.setting_getbool("only_peaceful_mobs") then pyramids.spawn_mummy({x=pos.x,y=pos.y,z=pos.z-2},2) + end + end +end + +local function can_replace(pos) + local n = minetest.get_node_or_nil(pos) + if n and n.name and minetest.registered_nodes[n.name] and not minetest.registered_nodes[n.name].walkable then + return true + elseif not n then + return true + else + return false + end +end + +local function underground(pos) + local p2 = pos + local cnt = 0 + local mat = "desert_sand" + p2.y = p2.y-1 + while can_replace(p2)==true do + cnt = cnt+1 + if cnt > 25 then break end + if cnt>math.random(2,4) then mat = "desert_stone"end + minetest.set_node(p2, {name="default:"..mat}) + p2.y = p2.y-1 + end +end + +local function make_entrance(pos) + local gang = {x=pos.x+10,y=pos.y, z=pos.z} + for iy=2,3,1 do + for iz=0,6,1 do + minetest.remove_node({x=gang.x+1,y=gang.y+iy,z=gang.z+iz}) + if iz >=3 and iy == 3 then + minetest.set_node({x=gang.x,y=gang.y+iy+1,z=gang.z+iz}, {name="default:sandstonebrick"}) + minetest.set_node({x=gang.x+1,y=gang.y+iy+1,z=gang.z+iz}, {name="default:sandstonebrick"}) + minetest.set_node({x=gang.x+2,y=gang.y+iy+1,z=gang.z+iz}, {name="default:sandstonebrick"}) + end + end + end +end + +local function make(pos) + minetest.log("action", "Created pyramid at ("..pos.x..","..pos.y..","..pos.z..")") + for iy=0,10,1 do + for ix=iy,22-iy,1 do + for iz=iy,22-iy,1 do + if iy <1 then underground({x=pos.x+ix,y=pos.y,z=pos.z+iz}) end + minetest.set_node({x=pos.x+ix,y=pos.y+iy,z=pos.z+iz}, {name="default:sandstonebrick"}) + for yy=1,10-iy,1 do + local n = minetest.get_node({x=pos.x+ix,y=pos.y+iy+yy,z=pos.z+iz}) + if n and n.name and n.name == "default:desert_stone" then minetest.set_node({x=pos.x+ix,y=pos.y+iy+yy,z=pos.z+iz},{name="default:desert_sand"}) end + end + end + end + end + + pyramids.make_room(pos) + minetest.after(2, pyramids.make_traps, pos) + + -- needs mobs redo + if minetest.get_modpath("mobs") ~= nil then + add_spawner({x=pos.x+11,y=pos.y+2, z=pos.z+16}) + end + + make_entrance({x=pos.x,y=pos.y, z=pos.z}) +end + +local perl1 = {SEED1 = 9130, OCTA1 = 3, PERS1 = 0.5, SCAL1 = 250} -- Values should match minetest mapgen V6 desert noise + +if minetest.get_modpath("simplev7") ~= nil then + perl1 = {SEED1 = 5349, OCTA1 = 3, PERS1 = 0.7, SCAL1 = 500} +end + +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) + if maxp.y < 0 then return end + math.randomseed(seed) + local cnt = 0 + + local perlin1 = minetest.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:desert_sand"}) + while p2 == nil and cnt < 5 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:desert_sand"}) + end + if p2 == nil then return end + if p2.y < 0 then return end + + local off = 0 + 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 + + if math.random(0,10) > 7 then return end + minetest.after(0.8,make,p2) + end +end) + +-- +-- backwards compatibility +-- + +-- spawner mummy +minetest.register_alias("pyramids:spawner_mummy", "spawners:spawners_mummy_spawner_env") +-- minetest.register_alias("pyramids:mummy_spawner", "spawners:spawners_mummy_spawner_env") + +-- spawn egg +minetest.register_alias("pyramids:spawn_egg", "spawners:mummy") + +-- mummy entity +minetest.register_alias("pyramids:mummy", "spawners:mummy") + +-- deco stone 1 +minetest.register_alias("pyramids:deco_stone1", "spawners:deco_stone1") + +-- deco stone 2 +minetest.register_alias("pyramids:deco_stone2", "spawners:deco_stone2") + +-- deco stone 3 +minetest.register_alias("pyramids:deco_stone3", "spawners:deco_stone3") + +-- deco trap +minetest.register_alias("pyramids:trap", "spawners:trap") + +-- deco trap 2 +minetest.register_alias("pyramids:trap_2", "spawners:trap_2") diff --git a/spawners_env/pyramids_nodes.lua b/spawners_env/pyramids_nodes.lua new file mode 100644 index 0000000..1f95507 --- /dev/null +++ b/spawners_env/pyramids_nodes.lua @@ -0,0 +1,50 @@ +local img = {"eye", "men", "sun"} + +for i=1,3 do + minetest.register_node("spawners:deco_stone"..i, { + description = "Sandstone with "..img[i], + tiles = {"default_sandstone.png^pyramids_"..img[i]..".png"}, + is_ground_content = true, + groups = {crumbly=2,cracky=3}, + sounds = default.node_sound_stone_defaults(), + }) +end + +trap_on_timer = function (pos, elapsed) + local objs = minetest.get_objects_inside_radius(pos, 2) + for i, obj in pairs(objs) do + if obj:is_player() then + local n = minetest.get_node(pos) + if n and n.name then + if minetest.registered_nodes[n.name].crack and minetest.registered_nodes[n.name].crack < 2 then + minetest.set_node(pos, {name="spawners:trap_2"}) + nodeupdate(pos) + end + end + end + end + return true +end + +minetest.register_node("spawners:trap", { + description = "Cracked sandstone brick", + tiles = {"default_sandstone_brick.png^pyramids_crack.png"}, + is_ground_content = true, + groups = {crumbly=2,cracky=3}, + sounds = default.node_sound_stone_defaults(), + on_construct = function(pos) + minetest.get_node_timer(pos):start(0.1) + end, + crack = 1, + on_timer = trap_on_timer, + drop = "", +}) + +minetest.register_node("spawners:trap_2", { + description = "trapstone", + tiles = {"default_sandstone_brick.png^pyramids_crack.png^[transformR90"}, + is_ground_content = true, + groups = {crumbly=2,cracky=3,falling_node=1,not_in_creative_inventory=1}, + sounds = default.node_sound_stone_defaults(), + drop = "", +}) diff --git a/spawners_env/pyramids_room.lua b/spawners_env/pyramids_room.lua new file mode 100644 index 0000000..cec8c4c --- /dev/null +++ b/spawners_env/pyramids_room.lua @@ -0,0 +1,78 @@ +local room = {"a","a","a","a","a","a","a","a","a", + "a","c","a","c","a","c","a","c","a", + "a","s","a","s","a","s","a","s","a", + "a","a","a","a","a","a","a","a","a", + "a","a","a","a","a","a","a","a","a", + "a","a","a","a","a","a","a","a","a", + "a","s","a","s","a","s","a","s","a", + "a","c","a","c","a","c","a","c","a", + "a","a","a","a","a","a","a","a","a"} + +local trap = {"b","b","b","b","b","b","b","b","b", + "l","b","l","b","l","b","l","b","b", + "l","b","l","b","l","b","l","b","b", + "l","b","l","l","l","b","l","l","b", + "l","l","b","l","b","l","l","b","b", + "l","b","l","l","l","l","l","l","b", + "l","b","l","b","l","b","l","b","b", + "l","b","l","b","l","b","l","b","b", + "b","b","b","b","b","b","b","b","b"} + +local code = {} +code["s"] = "sandstone" +code["eye"] = "deco_stone1" +code["men"] = "deco_stone2" +code["sun"] = "deco_stone3" +code["c"] = "chest" +code["b"] = "sandstonebrick" +code["a"] = "air" +code["l"] = "lava_source" +code["t"] = "trap" + +local function replace(str,iy) + local out = "default:" + if iy < 4 and str == "c" then str = "a" end + if iy == 0 and str == "s" then out = "spawners:" str = "sun" end + if iy == 3 and str == "s" then out = "spawners:" str = "men" end + if str == "a" then out = "" end + return out..code[str] +end + +local function replace2(str,iy) + local out = "default:" + if iy == 0 and str == "l" then out = "spawners:" str = "t" + elseif iy < 3 and str == "l" then str = "a" end + + if str == "a" then out = "" end + return out..code[str] +end + +function pyramids.make_room(pos) + local loch = {x=pos.x+7,y=pos.y+5, z=pos.z+7} + for iy=0,4,1 do + for ix=0,8,1 do + for iz=0,8,1 do + local n_str = room[tonumber(ix*9+iz+1)] + local p2 = 0 + if n_str == "c" then + if ix < 3 then p2 = 1 else p2 = 3 end + pyramids.fill_chest({x=loch.x+ix,y=loch.y-iy,z=loch.z+iz}) + end + minetest.set_node({x=loch.x+ix,y=loch.y-iy,z=loch.z+iz}, {name=replace(n_str,iy), param2=p2}) + end + end + end +end + +function pyramids.make_traps(pos) + local loch = {x=pos.x+7,y=pos.y, z=pos.z+7} + for iy=0,4,1 do + for ix=0,8,1 do + for iz=0,8,1 do + local n_str = trap[tonumber(ix*9+iz+1)] + local p2 = 0 + minetest.set_node({x=loch.x+ix,y=loch.y-iy,z=loch.z+iz}, {name=replace2(n_str,iy), param2=p2}) + end + end + end +end diff --git a/spawners_env/spawners_gen.lua b/spawners_env/spawners_gen.lua new file mode 100644 index 0000000..620f7bb --- /dev/null +++ b/spawners_env/spawners_gen.lua @@ -0,0 +1,40 @@ +-- Place spawners in dungeons +local function place_spawner(param) + local tab = param[1] + local gen_obj = param[2] + + local pos = tab[math.random(1, (#tab or 3))] + pos.y = pos.y - 1 + + local n = minetest.get_node_or_nil(pos) + + if n and n.name ~= "air" then + pos.y = pos.y + 1 + + if gen_obj == "dungeon" then + minetest.log("action", "[Mod][Spawners] dungeon spawner placed at: "..minetest.pos_to_string(pos)) + + minetest.set_node(pos, {name = "spawners:spawners_mummy_spawner_env"}) + else + minetest.log("action", "[Mod][Spawners] temple spawner placed at: "..minetest.pos_to_string(pos)) + + minetest.set_node(pos, {name = "spawners:mobs_spider_spawner_env"}) + end + + end +end + +minetest.set_gen_notify("dungeon") +minetest.set_gen_notify("temple") + +minetest.register_on_generated(function(minp, maxp, blockseed) + local ntf = minetest.get_mapgen_object("gennotify") + + if ntf and ntf.dungeon then + minetest.after(3, place_spawner, {table.copy(ntf.dungeon), "dungeon"}) + end + + if ntf and ntf.temple then + minetest.after(3, place_spawner, {table.copy(ntf.temple), "temple"}) + end +end) \ No newline at end of file diff --git a/spawners_mobs/api.lua b/spawners_mobs/api.lua new file mode 100644 index 0000000..d456adb --- /dev/null +++ b/spawners_mobs/api.lua @@ -0,0 +1,185 @@ +-- main tables +spawners = {} +spawners.mob_tables = {} + +-- check if mods exists and build tables +for k, mob_mod in ipairs(ENABLED_MODS) do + local modpath = minetest.get_modpath(mob_mod) + -- list of mobs and their info + if (modpath) then + for j, mob in ipairs(MOBS_PROPS[mob_mod]) do + local mob_egg = nil + + -- disabled extra check for mobs redo due to incompatibility with Lua 5.1, this method is available from Lua 5.2 + -- if mob_mod == "mobs" and not (mobs.mod == "redo") then goto continue end + + table.insert(spawners.mob_tables, {name=mob.name, mod_prefix=mob_mod, egg_name_custom=mob.egg_name_custom, dummy_size=mob.dummy_size, dummy_offset=mob.dummy_offset, dummy_mesh=mob.dummy_mesh, dummy_texture=mob.dummy_texture, night_only=mob.night_only, sound_custom=mob.sound_custom}) + + -- use custom egg or create a default egg + if mob.egg_name_custom ~= "" then + mob_egg = mob.egg_name_custom + else + mob_egg = mob_mod..":"..mob.name + end + + -- recipes + minetest.register_craft({ + output = "spawners_mobs:"..mob_mod.."_"..mob.name.."_spawner", + recipe = { + {"default:diamondblock", "fire:flint_and_steel", "default:diamondblock"}, + {"xpanes:bar_flat", mob_egg, "xpanes:bar_flat"}, + {"default:diamondblock", "xpanes:bar_flat", "default:diamondblock"}, + } + }) + + -- ::continue:: + end + else + -- print something ? + end +end + +-- start spawning mobs +function spawners.start_spawning(pos, how_many, mob_name, mod_prefix, sound_custom) + if not (pos or how_many or mob_name) then return end + + local sound_name + -- remove 'spawners_mobs:' from the string + local mob_name = string.sub(mob_name,15) + + -- use custom sounds + if sound_custom ~= "" then + sound_name = sound_custom + else + sound_name = mod_prefix.."_"..mob_name + end + + -- use random colours for sheeps + if mob_name == "sheep_white" then + local mob_name1 = "" + local sheep_colours = {"black", "blue", "brown", "cyan", "dark_green", "dark_grey", "green", "grey", "magenta", "orange", "pink", "red", "violet", "white", "yellow"} + local random_colour = math.random(1, #sheep_colours) + mob_name1 = string.split(mob_name, "_") + mob_name1 = mob_name1[1] + mob_name = mob_name1.."_"..sheep_colours[random_colour] + end + + for i=1,how_many do + pos.y = pos.y+1 + local obj = minetest.add_entity(pos, mod_prefix..":"..mob_name) + + if obj then + if sound_name then + minetest.sound_play(sound_name, { + pos = pos, + max_hear_distance = 32, + gain = 5, + }) + end + 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 spawners.check_node_status(pos, mob, night_only) + local player_near = spawners.check_around_radius(pos) + + if player_near then + local random_pos = false + local min_node_light = 10 + local tod = minetest.get_timeofday() * 24000 + local node_light = minetest.get_node_light(pos) + + if not node_light then + return false + end + + local spawn_positions = {} + local right = minetest.get_node({x=pos.x+1, y=pos.y, z=pos.z}) + local front = minetest.get_node({x=pos.x, y=pos.y, z=pos.z+1}) + local left = minetest.get_node({x=pos.x-1, y=pos.y, z=pos.z}) + local back = 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}) + + -- make sure that at least one side of the spawner is open + if right.name == "air" then + table.insert(spawn_positions, {x=pos.x+1.5, y=pos.y, z=pos.z}) + end + if front.name == "air" then + table.insert(spawn_positions, {x=pos.x, y=pos.y, z=pos.z+1.5}) + end + if left.name == "air" then + table.insert(spawn_positions, {x=pos.x-1.5, y=pos.y, z=pos.z}) + end + if back.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 + + if #spawn_positions < 1 then + -- spawner is cloed from all sides + return false + else + -- pick random from the open sides + local pick_random + + if #spawn_positions == 1 then + pick_random = #spawn_positions + else + pick_random = math.random(1,#spawn_positions) + end + + for k, v in pairs (spawn_positions) do + if k == pick_random then + random_pos = v + end + end + end + + -- check the node above and below 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 + + if not (node_above == "air" or node_below == "air") then + return false + end + + if night_only ~= "disable" then + -- spawn only at day + if not night_only and node_light < min_node_light then + return false, true + end + + -- spawn only at night + if night_only then + if not (19359 > tod and tod > 5200) or node_light < min_node_light then + return random_pos + else + return false, true + end + end + end + + return random_pos, false + else + return false, true + end +end diff --git a/spawners_mobs/config.example.lua b/spawners_mobs/config.example.lua new file mode 100644 index 0000000..65acce7 --- /dev/null +++ b/spawners_mobs/config.example.lua @@ -0,0 +1,204 @@ +-- * [name : string] - Name of the mob used in the mod. + +-- [egg_name_custom : string] - Custom name for the egg item. If empty default name will be used i.e. 'mobs:chicken'. + +-- * [dummy_size : table] - Size of the rotating dummy inside the node. + +-- * [dummy_offset : integer] - Offset on Y axis of the dummy inside the node. + +-- * [dummy_mesh : string] - Filename of the model used fot he mob. + +-- * [dummy_texture : table] - Textures used for the mob. + +-- * [night_only : boolean : string] - If true mobs will spawn only during the night or in dark areas, default:true. Writing "disable" will disable light check and it will spawn in both states (night and day) + +-- [sound_custom : string] - Custom name for the sound file name if differ from default: i.e 'mobs_cow'. + +-- [*] -> MANDATORY - has to be filled in! + +-- mods what should be enabled and loded, remove/add the one you want to load +ENABLED_MODS = {"mobs", "creatures"} + +-- mobs properties - setup all you mobs here +MOBS_PROPS = { + + ["mobs"] = { -- MOBS REDO CONFIG + { + name="sheep_white", + egg_name_custom="", + dummy_size={x=0.52,y=0.52}, + dummy_offset=0.2, + dummy_mesh="mobs_sheep.b3d", + dummy_texture={"mobs_sheep_wool.png^mobs_sheep_base.png"}, + night_only=false, + sound_custom="mobs_sheep" + }, + { + name="cow", + egg_name_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, + sound_custom="" + }, + { + name="chicken", + egg_name_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, + sound_custom="" + }, + { + name="pumba", + egg_name_custom="", + dummy_size={x=0.62,y=0.62}, + dummy_offset=-0.3, + dummy_mesh="mobs_pumba.x", + dummy_texture={"mobs_pumba.png"}, + night_only=false, + sound_custom="mobs_pig" + }, + { + name="bunny", + egg_name_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, + sound_custom="spawners_mobs_bunny" + }, + { + name="kitten", + egg_name_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, + sound_custom="" + }, + { + name="spider", + egg_name_custom="", + dummy_size={x=2,y=2}, + dummy_offset=-0.2, + dummy_mesh="mobs_spider.x", + dummy_texture={"mobs_spider.png"}, + night_only=false, + sound_custom="" + }, + { + name="stone_monster", + egg_name_custom="", + dummy_size={x=0.5,y=0.5}, + dummy_offset=0.05, + dummy_mesh="mobs_stone_monster.b3d", + dummy_texture={"mobs_stone_monster.png"}, + night_only=false, + sound_custom="mobs_stonemonster" + }, + { + name="oerkki", + egg_name_custom="", + dummy_size={x=0.5,y=0.5}, + dummy_offset=0.05, + dummy_mesh="mobs_oerkki.b3d", + dummy_texture={"mobs_oerkki.png"}, + night_only=true, + sound_custom="" + }, + { + name="tree_monster", + egg_name_custom="", + dummy_size={x=0.4,y=0.4}, + dummy_offset=0.05, + dummy_mesh="mobs_tree_monster.b3d", + dummy_texture={"mobs_tree_monster.png"}, + night_only=true, + sound_custom="mobs_treemonster" + } + }, + + ["creatures"] = { -- CREATURES MOD CONFIG + { + name="chicken", + egg_name_custom="creatures:chicken_spawn_egg", + dummy_size={x=0.9,y=0.9}, + dummy_offset=-0.3, + dummy_mesh="creatures_chicken.b3d", + dummy_texture={"creatures_chicken.png"}, + night_only=false, + sound_custom="" + }, + { + name="ghost", + egg_name_custom="creatures:ghost_spawn_egg", + dummy_size={x=0.7,y=0.7}, + dummy_offset=-0.5, + dummy_mesh="creatures_ghost.b3d", + dummy_texture={"creatures_ghost.png"}, + night_only=true, + sound_custom="" + }, + { + name="sheep", + egg_name_custom="creatures:sheep_spawn_egg", + dummy_size={x=0.6,y=0.6}, + dummy_offset=-0.3, + dummy_mesh="creatures_sheep.b3d", + dummy_texture={"creatures_sheep.png^creatures_sheep_white.png"}, + night_only=false, + sound_custom="" + }, + { + name="zombie", + egg_name_custom="creatures:zombie_spawn_egg", + dummy_size={x=0.5,y=0.5}, + dummy_offset=-0.5, + dummy_mesh="creatures_zombie.b3d", + dummy_texture={"creatures_zombie.png"}, + night_only=false, + sound_custom="" + }, + { + name="oerrki", + egg_name_custom="creatures:oerrki_spawn_egg", + dummy_size={x=0.4,y=0.4}, + dummy_offset=-0.5, + dummy_mesh="creatures_oerrki.b3d", + dummy_texture={"creatures_oerrki.png"}, + night_only=false, + sound_custom="creatures_oerrki_idle" + } + } +} + +-- +-- check for 3rd party dependencies +-- + +-- include mummy mobs redo addon (spawner) +if minetest.get_modpath("mobs") ~= nil then + -- enable spawner + table.insert(ENABLED_MODS, "spawners") + + -- configure spawner + MOBS_PROPS["spawners"] = { + { + name="mummy", + egg_name_custom="", + dummy_size={x=0.4,y=0.4}, + dummy_offset=0, + dummy_mesh="spawners_mobs_mummy.b3d", + dummy_texture={"spawners_mobs_mummy.png"}, + night_only="disable", + sound_custom="spawners_mobs_mummy" + } + } +end \ No newline at end of file diff --git a/spawners_mobs/depends.txt b/spawners_mobs/depends.txt new file mode 100644 index 0000000..16022f5 --- /dev/null +++ b/spawners_mobs/depends.txt @@ -0,0 +1,5 @@ +default +xpanes? +fire? +mobs? +creatures? diff --git a/spawners_mobs/init.lua b/spawners_mobs/init.lua new file mode 100644 index 0000000..e0d9009 --- /dev/null +++ b/spawners_mobs/init.lua @@ -0,0 +1,18 @@ +MOD_NAME = minetest.get_current_modname() + +-- Spawners configurations +dofile(minetest.get_modpath(MOD_NAME).."/config.lua") + +-- API +dofile(minetest.get_modpath(MOD_NAME).."/api.lua") + +-- Spawners for mobs +dofile(minetest.get_modpath(MOD_NAME).."/spawners_mobs.lua") + +-- include mummy mobs redo addon (mob) +if minetest.get_modpath("mobs") then + dofile(minetest.get_modpath(MOD_NAME).."/mob_mummy.lua") + dofile(minetest.get_modpath(MOD_NAME).."/nodes_additional.lua") +end + +print ("[Mod] Spawners Mobs 0.6 Loaded.") \ No newline at end of file diff --git a/spawners_mobs/mob_mummy.lua b/spawners_mobs/mob_mummy.lua new file mode 100644 index 0000000..487b08a --- /dev/null +++ b/spawners_mobs/mob_mummy.lua @@ -0,0 +1,65 @@ +-- modified Sand Monster by PilzAdam with Mummy by BlockMen + +local mummy_def = { + type = "monster", + passive = false, + attack_type = "dogfight", + pathfinding = true, + reach = 2, + damage = 4, + hp_min = 25, + hp_max = 35, + armor = 100, + collisionbox = {-0.4, -1, -0.4, 0.4, 0.8, 0.4}, + visual = "mesh", + mesh = "spawners_mobs_mummy.b3d", + textures = { + {"spawners_mobs_mummy.png"}, + }, + makes_footstep_sound = true, + sounds = { + random = "spawners_mobs_mummy", + damage = "spawners_mobs_mummy_hit", + }, + walk_velocity = .75, + run_velocity = 1.5, + view_range = 8, + jump = true, + floats = 0, + drops = { + {name = "default:sandstone", chance = 1, min = 1, max = 3}, + {name = "default:sandstonebrick", chance = 2, min = 1, max = 2}, + {name = "spawners_mobs:deco_stone_eye", chance = 15, min = 1, max = 1}, + {name = "spawners_mobs:deco_stone_men", chance = 15, min = 1, max = 1}, + {name = "spawners_mobs:deco_stone_sun", chance = 15, min = 1, max = 1}, + }, + water_damage = 4, + lava_damage = 8, + light_damage = 0, + fear_height = 4, + animation = { + speed_normal = 15, + speed_run = 15, + stand_start = 0, + stand_end = 39, + walk_start = 41, + walk_end = 72, + run_start = 74, + run_end = 105, + punch_start = 74, + punch_end = 105, + }, + on_die = function(self, pos) + minetest.sound_play("spawners_mobs_mummy_death", { + object = self.object, + pos = pos, + max_hear_distance = 10 + }) + end, +} + +mobs:register_mob("spawners_mobs:mummy", mummy_def) + +mobs:register_spawn("spawners_mobs:mummy", {"default:desert_sand", "default:desert_stone"}, 20, 0, 14000, 2, 31000) + +mobs:register_egg("spawners_mobs:mummy", "Mummy Monster", "default_sandstone_brick.png", 1) diff --git a/models/spawners_mob_mummy.b3d b/spawners_mobs/models/spawners_mobs_mummy.b3d similarity index 100% rename from models/spawners_mob_mummy.b3d rename to spawners_mobs/models/spawners_mobs_mummy.b3d diff --git a/spawners_mobs/nodes_additional.lua b/spawners_mobs/nodes_additional.lua new file mode 100644 index 0000000..8f35164 --- /dev/null +++ b/spawners_mobs/nodes_additional.lua @@ -0,0 +1,11 @@ +local img = {"eye", "men", "sun"} + +for i=1,3 do + minetest.register_node("spawners_mobs:deco_stone_"..img[i], { + description = "Sandstone with "..img[i], + tiles = {"default_sandstone.png^spawners_mobs_"..img[i]..".png"}, + is_ground_content = true, + groups = {crumbly=2,cracky=3}, + sounds = default.node_sound_stone_defaults(), + }) +end \ No newline at end of file diff --git a/sounds/spawners_bunny.ogg b/spawners_mobs/sounds/spawners_mobs_bunny.ogg similarity index 100% rename from sounds/spawners_bunny.ogg rename to spawners_mobs/sounds/spawners_mobs_bunny.ogg diff --git a/sounds/spawners_mob_mummy.1.ogg b/spawners_mobs/sounds/spawners_mobs_mummy.1.ogg similarity index 100% rename from sounds/spawners_mob_mummy.1.ogg rename to spawners_mobs/sounds/spawners_mobs_mummy.1.ogg diff --git a/sounds/spawners_mob_mummy.2.ogg b/spawners_mobs/sounds/spawners_mobs_mummy.2.ogg similarity index 100% rename from sounds/spawners_mob_mummy.2.ogg rename to spawners_mobs/sounds/spawners_mobs_mummy.2.ogg diff --git a/sounds/spawners_mob_mummy_death.1.ogg b/spawners_mobs/sounds/spawners_mobs_mummy_death.1.ogg similarity index 100% rename from sounds/spawners_mob_mummy_death.1.ogg rename to spawners_mobs/sounds/spawners_mobs_mummy_death.1.ogg diff --git a/sounds/spawners_mob_mummy_hit.1.ogg b/spawners_mobs/sounds/spawners_mobs_mummy_hit.1.ogg similarity index 100% rename from sounds/spawners_mob_mummy_hit.1.ogg rename to spawners_mobs/sounds/spawners_mobs_mummy_hit.1.ogg diff --git a/spawners_mobs/spawners_mobs.lua b/spawners_mobs/spawners_mobs.lua new file mode 100644 index 0000000..521ecf7 --- /dev/null +++ b/spawners_mobs/spawners_mobs.lua @@ -0,0 +1,243 @@ +local max_obj_per_mapblock = tonumber(minetest.setting_get("max_objects_per_block")) + +-- +-- * CREATE ALL SPAWNERS NODES * +-- + +function spawners.create(mob_name, mod_prefix, size, offset, mesh, texture, night_only, sound_custom) + + -- + -- DUMMY INSIDE THE SPAWNER + -- + + 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_mobs:"..mod_prefix.."_"..mob_name.."_spawner_active" then + self.object:remove() + end + end + end + + minetest.register_entity("spawners_mobs:dummy_"..mod_prefix.."_"..mob_name, dummy_definition) + + -- + -- * CRAFTING SPAWNERS * + -- + + -- print("[Mod][Spawners] Registering Crafting Spawner.") + + -- + -- ACTIVE SPAWNER + -- + + minetest.register_node("spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_active", { + description = mod_prefix.."_"..mob_name.." spawner active", + paramtype = "light", + light_source = 4, + drawtype = "allfaces", + walkable = true, + sounds = default.node_sound_stone_defaults(), + damage_per_second = 4, + sunlight_propagates = true, + tiles = { + { + name = "spawners_mobs_spawner_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 2.0 + }, + } + }, + is_ground_content = true, + groups = {cracky=1,level=2,igniter=1,not_in_creative_inventory=1}, + drop = "spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner", + on_construct = function(pos) + pos.y = pos.y + offset + minetest.add_entity(pos,"spawners_mobs:dummy_"..mod_prefix.."_"..mob_name) + end, + }) + + -- + -- WAITING SPAWNER + -- + + -- waiting for light - everything is ok but too much light or not enough light + minetest.register_node("spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_waiting", { + description = mod_prefix.."_"..mob_name.." spawner waiting", + paramtype = "light", + light_source = 2, + drawtype = "allfaces", + walkable = true, + sounds = default.node_sound_stone_defaults(), + sunlight_propagates = true, + tiles = { + { + name = "spawners_mobs_spawner_waiting_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 2.0 + }, + } + }, + is_ground_content = true, + groups = {cracky=1,level=2,not_in_creative_inventory=1}, + drop = "spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner", + }) + + -- + -- INACTIVE SPAWNER (DEFAULT) + -- + + minetest.register_node("spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner", { + description = mod_prefix.."_"..mob_name.." spawner", + paramtype = "light", + drawtype = "allfaces", + walkable = true, + sounds = default.node_sound_stone_defaults(), + sunlight_propagates = true, + tiles = {"spawners_mobs_spawner.png"}, + is_ground_content = true, + groups = {cracky=1,level=2}, + stack_max = 1, + on_construct = function(pos) + local random_pos, waiting = spawners.check_node_status(pos, mob_name, night_only) + + if random_pos then + minetest.set_node(pos, {name="spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_active"}) + elseif waiting then + minetest.set_node(pos, {name="spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_waiting"}) + else + end + end, + }) + + -- + -- OVERHEATED SPAWNER + -- + + minetest.register_node("spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_overheat", { + description = mod_prefix.."_"..mob_name.." spawner overheated", + paramtype = "light", + light_source = 2, + drawtype = "allfaces", + walkable = true, + sounds = default.node_sound_stone_defaults(), + damage_per_second = 4, + sunlight_propagates = true, + tiles = {"spawners_mobs_spawner.png^[colorize:#FF000030"}, + is_ground_content = true, + groups = {cracky=1,level=2,igniter=1,not_in_creative_inventory=1}, + drop = "spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner", + on_construct = function(pos) + minetest.get_node_timer(pos):start(60) + end, + on_timer = function(pos, elapsed) + minetest.set_node(pos, {name="spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner"}) + end, + }) + + -- + -- * ABM * + -- + + minetest.register_abm({ + nodenames = { + "spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner", + "spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_active", + "spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_overheat", + "spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_waiting" + }, + neighbors = {"air"}, + interval = 10.0, + chance = 6, + catch_up = false, + action = function(pos, node, active_object_count, active_object_count_wider) + + local random_pos, waiting = spawners.check_node_status(pos, mob_name, night_only) + + -- minetest.log("action", "[Mod][Spawners] checking for: "..mob_name.." at "..minetest.pos_to_string(pos)) + + if random_pos then + + -- do not spawn if too many active entities in map block and call cooldown + if active_object_count_wider > max_obj_per_mapblock then + + -- make sure the right node status is shown + if node.name ~= "spawners_mobs:"..mob_name.."_spawner_overheat" then + minetest.set_node(pos, {name="spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_overheat"}) + end + + -- extend the timeout if still too many entities in map block + if node.name == "spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_overheat" then + minetest.get_node_timer(pos):stop() + minetest.get_node_timer(pos):start(60) + end + + return + end + -- make sure the right node status is shown + if node.name ~= "spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_active" then + minetest.set_node(pos, {name="spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_active"}) + end + + -- enough place to spawn more mobs + spawners.start_spawning(random_pos, 1, "spawners_mobs:"..mob_name, mod_prefix, sound_custom) + + elseif waiting then + -- waiting status + if node.name ~= "spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_waiting" then + minetest.set_node(pos, {name="spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner_waiting"}) + end + else + -- no random_pos found + if minetest.get_node_timer(pos):is_started() then + minetest.get_node_timer(pos):stop() + end + + if node.name ~= "spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner" then + minetest.set_node(pos, {name="spawners_mobs:"..mod_prefix.."_"..mob_name.."_spawner"}) + end + end + + end + }) + +end + +-- +-- CALL 'CREATE' FOR ALL SPAWNERS +-- + +for i, mob_table in ipairs(spawners.mob_tables) do + if mob_table then + + spawners.create(mob_table.name, mob_table.mod_prefix, mob_table.dummy_size, mob_table.dummy_offset, mob_table.dummy_mesh, mob_table.dummy_texture, mob_table.night_only, mob_table.sound_custom) + end +end \ No newline at end of file diff --git a/textures/pyramids_crack.png b/spawners_mobs/textures/spawners_mobs_crack.png similarity index 100% rename from textures/pyramids_crack.png rename to spawners_mobs/textures/spawners_mobs_crack.png diff --git a/textures/pyramids_eye.png b/spawners_mobs/textures/spawners_mobs_eye.png similarity index 100% rename from textures/pyramids_eye.png rename to spawners_mobs/textures/spawners_mobs_eye.png diff --git a/textures/pyramids_men.png b/spawners_mobs/textures/spawners_mobs_men.png similarity index 100% rename from textures/pyramids_men.png rename to spawners_mobs/textures/spawners_mobs_men.png diff --git a/textures/spawners_mob_mummy.png b/spawners_mobs/textures/spawners_mobs_mummy.png similarity index 100% rename from textures/spawners_mob_mummy.png rename to spawners_mobs/textures/spawners_mobs_mummy.png diff --git a/textures/spawners_smoke_particle.png b/spawners_mobs/textures/spawners_mobs_smoke_particle.png similarity index 100% rename from textures/spawners_smoke_particle.png rename to spawners_mobs/textures/spawners_mobs_smoke_particle.png diff --git a/textures/spawners_spawner.png b/spawners_mobs/textures/spawners_mobs_spawner.png similarity index 100% rename from textures/spawners_spawner.png rename to spawners_mobs/textures/spawners_mobs_spawner.png diff --git a/textures/spawners_spawner_animated.png b/spawners_mobs/textures/spawners_mobs_spawner_animated.png similarity index 100% rename from textures/spawners_spawner_animated.png rename to spawners_mobs/textures/spawners_mobs_spawner_animated.png diff --git a/textures/spawners_spawner_normal.png b/spawners_mobs/textures/spawners_mobs_spawner_normal.png similarity index 100% rename from textures/spawners_spawner_normal.png rename to spawners_mobs/textures/spawners_mobs_spawner_normal.png diff --git a/textures/spawners_spawner_waiting_animated.png b/spawners_mobs/textures/spawners_mobs_spawner_waiting_animated.png similarity index 100% rename from textures/spawners_spawner_waiting_animated.png rename to spawners_mobs/textures/spawners_mobs_spawner_waiting_animated.png diff --git a/textures/pyramids_sun.png b/spawners_mobs/textures/spawners_mobs_sun.png similarity index 100% rename from textures/pyramids_sun.png rename to spawners_mobs/textures/spawners_mobs_sun.png diff --git a/spawners_ores/api.lua b/spawners_ores/api.lua new file mode 100644 index 0000000..41453d0 --- /dev/null +++ b/spawners_ores/api.lua @@ -0,0 +1,93 @@ +-- main tables +spawners = {} + +function spawners.add_effects(pos, radius) + minetest.add_particlespawner({ + amount = 32, + time = 2, + minpos = vector.subtract({x=pos.x, y=pos.y+1, z=pos.z}, radius / 2), + maxpos = vector.add({x=pos.x, y=pos.y+1, z=pos.z}, radius / 2), + minvel = {x=-0.5, y=3, z=-0.5}, + maxvel = {x=0.5, y=10, z=0.5}, + minacc = vector.new(), + maxacc = vector.new(), + minexptime = .5, + maxexptime = 2, + minsize = .5, + maxsize = 8, + texture = "spawners_smoke_particle.png", + }) +end + +-- start spawning ores +function spawners.start_spawning_ores(pos, ore_name, sound_custom, spawners_pos) + if not pos or not ore_name then return end + local sound_name + local player_near = false + + -- use custom sounds + if sound_custom ~= "" then + sound_name = sound_custom + else + sound_name = false + end + + local how_many = math.random(1,2) + -- how_many = how_many+1 + + for i=1, how_many do + + if i > 1 then + player_near, pos = spawners.check_around_radius_ores(pos, "default:stone") + + if not pos then return end + + minetest.sound_play(sound_name, { + pos = pos, + max_hear_distance = 32, + gain = 20, + }) + + minetest.set_node(pos, {name=ore_name}) + spawners.add_effects(pos, 1) + else + minetest.sound_play(sound_name, { + pos = pos, + max_hear_distance = 32, + gain = 20, + }) + + minetest.set_node(pos, {name=ore_name}) + spawners.add_effects(pos, 1) + end + end + +end + +function spawners.check_around_radius_ores(pos, check_node) + local player_near = spawners.check_around_radius(pos); + local found_node = false + local node_ore_pos = nil + if check_node then + + node_ore_pos = minetest.find_node_near(pos, 2, {check_node}) + + if node_ore_pos then + found_node = node_ore_pos + end + end + + return player_near, found_node +end + +function spawners.check_node_status_ores(pos, ore_name, check_node) + if not check_node then return end + + local player_near, found_node = spawners.check_around_radius_ores(pos, check_node) + + if player_near and found_node then + return true, found_node + else + return true, false + end +end \ No newline at end of file diff --git a/spawners_ores/depends.txt b/spawners_ores/depends.txt new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/spawners_ores/depends.txt @@ -0,0 +1 @@ +default diff --git a/spawners_ores/init.lua b/spawners_ores/init.lua new file mode 100644 index 0000000..12a768a --- /dev/null +++ b/spawners_ores/init.lua @@ -0,0 +1,42 @@ +-- Main settings +dofile(minetest.get_modpath("spawners").."/settings.txt") + +-- Spawners configurations +dofile(minetest.get_modpath("spawners").."/config.lua") + +-- API +dofile(minetest.get_modpath("spawners").."/API.lua") + +-- Spawners for mobs +dofile(minetest.get_modpath("spawners").."/spawners_mobs.lua") + +-- Spawners for ores +dofile(minetest.get_modpath("spawners").."/spawners_ores.lua") + +-- include mummy mobs redo addon (mob) +if minetest.get_modpath("mobs") then + dofile(minetest.get_modpath("spawners").."/mob_mummy.lua") +end + +-- Spawners Pyramids +if SPAWN_PYRAMIDS then + dofile(minetest.get_modpath("spawners").."/pyramids.lua") + + print("[Mod][spawners] Pyramids enabled") +end + +-- Add Spawners to dungeons, temples.. +if SPAWNERS_GENERATE then + dofile(minetest.get_modpath("spawners").."/spawners_gen.lua") + + print("[Mod][spawners] Spawners generate enabled") +end + +-- Add Chests to dungeons, temples.. +if CHESTS_GENERATE then + dofile(minetest.get_modpath("spawners").."/chests_gen.lua") + + print("[Mod][spawners] Chests generate enabled") +end + +print ("[Mod] Spawners 0.6 Loaded.") \ No newline at end of file diff --git a/sounds/strike.ogg b/spawners_ores/sounds/strike.ogg similarity index 100% rename from sounds/strike.ogg rename to spawners_ores/sounds/strike.ogg diff --git a/spawners_ores/spawners_ores.lua b/spawners_ores/spawners_ores.lua new file mode 100644 index 0000000..8ecfede --- /dev/null +++ b/spawners_ores/spawners_ores.lua @@ -0,0 +1,335 @@ +-- Formspecs +local ore_formspec = + "size[8,8.5]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "label[2,1.7;Input Ingot]".. + "list[current_name;fuel;3.5,1.5;1,1;]".. + "list[current_player;main;0,4.25;8,1;]".. + "list[current_player;main;0,5.5;8,3;8]".. + "button_exit[5,1.5;2,1;exit;Save]".. + "listring[current_name;fuel]".. + "listring[current_player;main]".. + default.get_hotbar_bg(0, 4.25) + +function spawners.get_formspec(pos) + + -- Inizialize metadata + local meta = minetest.get_meta(pos) + + -- Inizialize inventory + local inv = meta:get_inventory() + for listname, size in pairs({ + fuel = 1, + }) do + if inv:get_size(listname) ~= size then + inv:set_size(listname, size) + end + end + + -- Update formspec, infotext and node + meta:set_string("formspec", ore_formspec) +end + +local function can_dig(pos, player) + local meta = minetest.get_meta(pos); + local inv = meta:get_inventory() + return inv:is_empty("fuel") +end + +local function allow_metadata_inventory_put(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then + minetest.record_protection_violation(pos, player:get_player_name()) + return + end + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local ingot = minetest.get_node_or_nil(pos).name + + ingot = string.split(ingot, ":") + ingot = string.split(ingot[2], "_") + + if ingot[3] == "iron" then + ingot[3] = "steel" + end + + if stack:get_name() == "default:"..ingot[3].."_ingot" then + return stack:get_count() + else + return 0 + end +end + +local function allow_metadata_inventory_take(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then + minetest.record_protection_violation(pos, player:get_player_name()) + return 0 + end + return stack:get_count() +end + +local function on_receive_fields(pos, formname, fields, sender) + local ore_node = minetest.get_node_or_nil(pos) + + if minetest.is_protected(pos, sender:get_player_name()) then + minetest.record_protection_violation(pos, sender:get_player_name()) + return + end + + -- get the ore name + local ingot = ore_node.name + ingot = string.split(ingot, ":") + ingot = string.split(ingot[2], "_") + + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local fuellist = inv:get_list("fuel") + + if inv:is_empty("fuel") then + if ore_node.name ~= "spawners:stone_with_"..ingot[3].."_spawner" then + minetest.swap_node(pos, {name="spawners:stone_with_"..ingot[3].."_spawner"}) + end + meta:set_string("infotext", ingot[3].." ore spawner is empty") + else + meta:set_string("infotext", ingot[3].." ore spawner fuel: "..inv:get_stack("fuel", 1):get_count()) + end + + -- fix iron vs. steel issue + if ingot[3] == "iron" then + ingot[3] = "steel" + end + + if not fuellist[1]:is_empty() and inv:get_stack("fuel", 1):get_name() == "default:"..ingot[3].."_ingot" then + + -- fix iron vs. steel issue + if ingot[3] == "steel" then + ingot[3] = "iron" + end + + local waiting, found_node = spawners.check_node_status_ores(pos, "stone_with_"..ingot[3], "default:stone") + + if found_node then + minetest.swap_node(pos, {name="spawners:stone_with_"..ingot[3].."_spawner_active"}) + elseif waiting then + minetest.swap_node(pos, {name="spawners:stone_with_"..ingot[3].."_spawner_waiting"}) + + meta:set_string("infotext", "Waiting status - player was away or no stone around, "..ingot[3].." ore spawner fuel: "..inv:get_stack("fuel", 1):get_count()) + else + return + end + end +end + +-- Ores creation +function spawners.create_ore(ore_name, mod_prefix, size, offset, texture, sound_custom) + -- dummy inside the spawner + local dummy_ore_definition = { + hp_max = 1, + physical = false, + collisionbox = {0,0,0,0,0,0}, + visual = "wielditem", + visual_size = size, + timer = 0, + textures={"default:"..ore_name}, + makes_footstep_sound = false, + automatic_rotate = math.pi * -3, + m_name = "dummy_ore" + } + + local ore = string.split(ore_name, "_") + + dummy_ore_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_ore_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:"..ore_name.."_spawner_active" and n.name ~= "spawners:"..ore_name.."_spawner_waiting" and n.name ~= "spawners:"..ore_name.."_spawner" then + self.object:remove() + end + end + end + + minetest.register_entity("spawners:dummy_ore_"..ore_name, dummy_ore_definition) + + -- node spawner active + minetest.register_node("spawners:"..ore_name.."_spawner_active", { + description = ore_name.." spawner active", + paramtype = "light", + light_source = 4, + drawtype = "allfaces", + walkable = true, + sounds = default.node_sound_stone_defaults(), + damage_per_second = 4, + sunlight_propagates = true, + tiles = { + { + name = "spawners_spawner_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 2.0 + }, + } + }, + is_ground_content = true, + groups = {cracky=1,level=2,igniter=1,not_in_creative_inventory=1}, + drop = "spawners:"..ore_name.."_spawner", + can_dig = can_dig, + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_take = allow_metadata_inventory_take, + on_receive_fields = on_receive_fields, + }) + + -- node spawner waiting - no stone around or no fuel + minetest.register_node("spawners:"..ore_name.."_spawner_waiting", { + description = ore_name.." spawner waiting", + paramtype = "light", + light_source = 2, + drawtype = "allfaces", + walkable = true, + sounds = default.node_sound_stone_defaults(), + sunlight_propagates = true, + tiles = { + { + name = "spawners_spawner_waiting_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 2.0 + }, + } + }, + is_ground_content = true, + groups = {cracky=1,level=2,not_in_creative_inventory=1}, + drop = "spawners:"..ore_name.."_spawner", + can_dig = can_dig, + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_take = allow_metadata_inventory_take, + on_receive_fields = on_receive_fields, + }) + + -- node spawner inactive (default) + minetest.register_node("spawners:"..ore_name.."_spawner", { + description = ore_name.." spawner", + paramtype = "light", + drawtype = "allfaces", + walkable = true, + sounds = default.node_sound_stone_defaults(), + sunlight_propagates = true, + tiles = {"spawners_spawner.png"}, + is_ground_content = true, + groups = {cracky=1,level=2}, + stack_max = 1, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + spawners.get_formspec(pos) + pos.y = pos.y + offset + minetest.add_entity(pos,"spawners:dummy_ore_"..ore_name) + meta:set_string("infotext", ore[3].." ore spawner is empty") + end, + + can_dig = can_dig, + + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_take = allow_metadata_inventory_take, + on_receive_fields = on_receive_fields, + }) + + -- ABM + minetest.register_abm({ + nodenames = {"spawners:"..ore_name.."_spawner_active", "spawners:"..ore_name.."_spawner_waiting"}, + interval = 5.0, + chance = 5, + action = function(pos, node, active_object_count, active_object_count_wider) + + local waiting, found_node = spawners.check_node_status_ores(pos, ore_name, "default:stone") + + + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + + if found_node then + -- make sure the right node status is shown + if node.name ~= "spawners:"..ore_name.."_spawner_active" then + minetest.swap_node(pos, {name="spawners:"..ore_name.."_spawner_active"}) + end + + + -- take fuel + local stack = inv:get_stack("fuel", 1) + stack:take_item() + + + inv:set_stack("fuel", 1, stack) + + meta:set_string("infotext", ore[3].." ore spawner fuel: "..inv:get_stack("fuel", 1):get_count()) + + -- enough place to spawn more ores + spawners.start_spawning_ores(found_node, "default:"..ore_name, sound_custom) + + -- empty / no fuel + if inv:is_empty("fuel") then + minetest.swap_node(pos, {name="spawners:"..ore_name.."_spawner"}) + meta:set_string("infotext", ore[3].." ore spawner is empty.") + + end + else + -- waiting status + if node.name ~= "spawners:"..ore_name.."_spawner_waiting" then + minetest.swap_node(pos, {name="spawners:"..ore_name.."_spawner_waiting"}) + + meta:set_string("infotext", "Waiting status - player was away or no stone around, "..ore[3].." ore spawner fuel: "..inv:get_stack("fuel", 1):get_count()) + end + end + + end + }) + +end + +-- default:stone_with_gold +spawners.create_ore("stone_with_gold", "", {x=.33,y=.33}, 0, {"default_stone.png^default_mineral_gold.png"}, "strike") + +-- default:stone_with_iron +spawners.create_ore("stone_with_iron", "", {x=.33,y=.33}, 0, {"default_stone.png^default_mineral_gold.png"}, "strike") + +-- default:stone_with_copper +spawners.create_ore("stone_with_copper", "", {x=.33,y=.33}, 0, {"default_stone.png^default_mineral_gold.png"}, "strike") + + +-- recipes +minetest.register_craft({ + output = "spawners:stone_with_gold_spawner", + recipe = { + {"default:diamondblock", "fire:flint_and_steel", "default:diamondblock"}, + {"xpanes:bar_flat", "default:goldblock", "xpanes:bar_flat"}, + {"default:diamondblock", "xpanes:bar_flat", "default:diamondblock"}, + } +}) + +minetest.register_craft({ + output = "spawners:stone_with_iron_spawner", + recipe = { + {"default:diamondblock", "fire:flint_and_steel", "default:diamondblock"}, + {"xpanes:bar_flat", "default:steelblock", "xpanes:bar_flat"}, + {"default:diamondblock", "xpanes:bar_flat", "default:diamondblock"}, + } +}) + +minetest.register_craft({ + output = "spawners:stone_with_copper_spawner", + recipe = { + {"default:diamondblock", "fire:flint_and_steel", "default:diamondblock"}, + {"xpanes:bar_flat", "default:copperblock", "xpanes:bar_flat"}, + {"default:diamondblock", "xpanes:bar_flat", "default:diamondblock"}, + } +}) diff --git a/spawners_ores/textures/spawners_smoke_particle.png b/spawners_ores/textures/spawners_smoke_particle.png new file mode 100644 index 0000000000000000000000000000000000000000..89d81c146dfc92d2528e05abcd0fa5892d1902a8 GIT binary patch literal 233 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnL3?x0byx0z;*aCb)T!Hle|NocXoPQU{Vk`;r z3ubV5b|VeMN%D4gVd!9$^#F1>3p^r=85p>QL70(Y)*K0-AbW|YuPgflMtL3qew(+N z|A9g=o-U3d9M@gX9ppTqz{7e$zUswAK`XEDY;$2Nhwy?HIng8W`vuQD6r3zC@PVu0 z?t514Hxn-2Jkb)%QaB+p#8y0V;`zg7yA7ppFY9hA4w`GoJ$Y3@o9)W_qe@|aPx||P U4xd~x9cT}Or>mdKI;Vst0FT2;djJ3c literal 0 HcmV?d00001 diff --git a/spawners_ores/textures/spawners_spawner.png b/spawners_ores/textures/spawners_spawner.png new file mode 100644 index 0000000000000000000000000000000000000000..dd6803e2a09e9d86afb0a935ba21f6e7f5680994 GIT binary patch literal 535 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dy_5nU2u0WbcLXk&OnNM1kPgY$( zQCCn&Pf*!FNX1Y{)mT`~L|ENSM8jNE(?U$wR$Sjf!oX3=#9i9VOU^b}!6E$a?TE)f zBN$79{DK)Ap4~_Tagw~{XE)7O>#0i!&( zi9wyt=Z8Q&fu1goAr_}=gBgXI6?n9njFw7!{rw+({lS9c@66tx2)cgRr1yy7PW9qv zCD*bABI84!Oz3{OD*aO(=fR~XnseR>o_=>-$}?=yn@%e!=6Ribe<#YC=b5ni`2C)z z^VHk1kx7Q{*7Mrl%}r7Z8Pv0#6{~DNoRIEitW><}x%zM~kacsr-OX7mayw+cUf!N~ zh3{1c&x-%2_&!>go{PJtv1qYZW5pcfvvKoQzOiC*S*E7NJ2C8e^pabSvb~I7MORDT zYhNF`VBwa;y!Th9WQwl{WoT=heRj${gDg>oi56$4oKM}#b)onF%~q}h2K&nwGFfEE zZCh`XW6S?*(;B@vo97Q7&0`n+AerW2{O#k6_ZdO%$quE$hyUDkUC{dftrKg@ozD{v z&uN!2xjK*OyUhoq=Z(`ht!9}1ODsn`?055}o7)q1Z>SROD*d{DU!K7u@4onW^BdAT X*Gl+rwz|6n7~Tw?u6{1-oD!M<)P>O2 literal 0 HcmV?d00001 diff --git a/spawners_ores/textures/spawners_spawner_animated.png b/spawners_ores/textures/spawners_spawner_animated.png new file mode 100644 index 0000000000000000000000000000000000000000..cf0c2c3c409f654fa988226b014872c338e8474d GIT binary patch literal 18168 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 RcUlcOb;9;I=9o*u{{xlO^hN*x literal 0 HcmV?d00001 diff --git a/spawners_ores/textures/spawners_spawner_waiting_animated.png b/spawners_ores/textures/spawners_spawner_waiting_animated.png new file mode 100644 index 0000000000000000000000000000000000000000..179f8c282b2401497bc7dc47b92a414487d9a36c GIT binary patch literal 4735 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 N002ovPDHLkV1fdzfKvbf literal 0 HcmV?d00001