From 74adc847b65c7b79a875839a7d0b5db8ba382d40 Mon Sep 17 00:00:00 2001 From: Juraj Vajda Date: Thu, 7 Jan 2016 20:22:12 +0100 Subject: [PATCH] Initial commit --- README.md | 3 + depends.txt | 5 + init.lua | 389 +++++++++++++++++++++ license.txt | 13 + textures/spawners_spawner.png | Bin 0 -> 453 bytes textures/spawners_spawner_animated.png | Bin 0 -> 2014 bytes textures/spawners_spawner_off_animated.png | Bin 0 -> 499 bytes 7 files changed, 410 insertions(+) create mode 100644 README.md create mode 100644 depends.txt create mode 100644 init.lua create mode 100644 license.txt create mode 100644 textures/spawners_spawner.png create mode 100644 textures/spawners_spawner_animated.png create mode 100644 textures/spawners_spawner_off_animated.png 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 0000000000000000000000000000000000000000..06037b40a5cc29a20cc52be33d7889590121f698 GIT binary patch literal 453 zcmV;$0XqJPP)pGQAtEWRCt`FQtfVnFcj?rY;GzFv>T;@1#2h>Hqn_adoU6n{p`oa z6`Wf#_oL~_>Bl|y+`|HyLKp|GG=y>R5(}xfP}K>O=Nw_)jLxItfV|uj$AobRx|a4! ze2wd|uXkXch!J!x<4V&7UDV$`m~(mNWJ+(CFm5C<%p2&UCh5y{1z{ZKT!L>tr3W&_ z{Zj^MkN<078gIe+%3Ntg#R0-NsJuY0Oc)1gkKjr}Ri}~Kk%^DeP=zpWepPTMG^xI+ z1!<26x|S{16Oc8Fm1s?za02*{f vSad;kbZBpK099;dVPqgvd2@7SZF4LjNp52<$sIm+00000NkvXXu0mjf4L89x literal 0 HcmV?d00001 diff --git a/textures/spawners_spawner_animated.png b/textures/spawners_spawner_animated.png new file mode 100644 index 0000000000000000000000000000000000000000..1f7e27ab44aec282302c676c2ec679ccbd7372dd GIT binary patch literal 2014 zcmV<42O;>0P)Sr&F)Lyuk*fnY9rVnvx_45VTRfNmmgZd!D4I-hA1m1;1W zZ61+tM4EIlopU>%bS!y%W~g=@fqhlpYXGEpRj+&)&vO`#fMlb9KdydGnuBAYg-XkW z5Sxi`?|cTIi*vh+A-9S=n~!3Wj*O0yeVvqRu98u+mRg>iexIF=)Rj}Gp>3<6ZpNKR z$C+;7nK-edcgCSw;G9n8pE$gxaJ8v{vZ$Q4sfe|)iPEiez_NbgtxUDCsn)ZGy}6j; zvuVk>g5tDu-L;Rxy0GB9dg8rp*}k6G!-nm^X2-;_|dfv#1^UFTv$dAy` znadO+Q;JEx8dB->foE{->l}}x#Hd3d4{g>*?#%=|NX^MmL;+sm#rFGUqy{&e=J~Dy=A3 zXQx;|+cHU-Qc{SwKkSCkz1-b%Z*I!DEo=}Hl9Q8@n-AY}?>QDsL00ZrU|9gLrYvTO zgZKgbRhw1Fzrw3m`GUAazcLRP01J3|N_oIygdWkNIApWpUe=8+0bGh)Cy4=RP)F?Z znLHeM%am0;46=#A76;opTiGCw04(_803tXJHVyh`wSs>cdH^_Zx&4bgOJ2*YCz0~Z z%1wm2b5R+Xg`a}^N1z{>0#EK9Fi-RFJUtF^hCvqtzlw&cABgWoza_tdJSzT@<`D+y z5rpF4dE%aTzI_hhT>Cs5;~|D#D%aO2kC*<6M|iNvY`p^cg4?m8OM-=-yU)Edb(OOUQ zCHMXYz>W90W9CznN4V`%eXx3D=wp3nl0K}LdBWpiuS)gt_?<=d@$k~=^pPL&$g7~f zHu#A?;xI%W;b{KwRlfL^*2fi@?d>b5k9kuc(F>DDw{GZT=S|Jf$BN7sr)21(@qzHT z@vcSnv9xhW^|3U4l0KN+8Q4tmu&u&~M?nVN;M%}9EI_}#J&a+qy}g7-BkZF`KNK0o zn7GHLBYZZTDjx3S`D08UoxtF+ z8}to*+}@WwY=cLO5gv1Iy9STwH_GGAS(Ar-N*)z$s3bhPaT$4(<8GQS1N0bRzEB?a z7!Um34U@+p&Ql(1QEcer_Q6CRG3D{?Zrmh19``KD<0to&`pD>UWMIPlA^hqwZzGR3 zkL$_6mTTxyTTXc}#e+@MN3de>@Vh%9{`H`WIh1YU@Dbw}k?|z4@FAHJ8oIi~EWA?)7>W_KdSV4AP1?~DO z8~koke*jnOEuYdnB2|w?Y5n0S9*#4%-imMeuxs)FZq(~63JiVZp3C~9MC*_DJG4H% zJpfvNeE*M8e|-7zN%hBgKR2!qC@CH#yhJ}ZRQ2g$%41kWkK!=x=U5N@dXwi5D_<;{ zJi4@>Ywnu;%RSlOir}Q5+kfQ|9^ZX1>hi07#kD?k!QS*pe zB{Y;;QPS^sG!I>`^M)eU;IiM(Kz3TyW7DcWEgJP{B{1}{!~3+~=Z#Hqe)DMkf%W=k w#_0DCwzH()zdq!Y$0L80_WO6Q9oO&w3+tw41|aF+yZ`_I07*qoM6N<$g4`bSX8-^I literal 0 HcmV?d00001 diff --git a/textures/spawners_spawner_off_animated.png b/textures/spawners_spawner_off_animated.png new file mode 100644 index 0000000000000000000000000000000000000000..9df39a7d747f07ed6a3116f95cb37d2b86b90e70 GIT binary patch literal 499 zcmV9OC`)0kQ(@J6eChkDSn~Ltrx8_ z9>x2yM