Version 1.1
Added sheeps, fixed issues, restructured code
33
README.txt
@ -2,11 +2,11 @@ Minetest mod "Creatures"
|
|||||||
=======================
|
=======================
|
||||||
by BlockMen (c) 2014
|
by BlockMen (c) 2014
|
||||||
|
|
||||||
Version: 1.0.1 Beta
|
Version: 1.1 Beta
|
||||||
|
|
||||||
About
|
About
|
||||||
~~~~~
|
~~~~~
|
||||||
This mod add (currently only) hostile mobs to Minetest, so far Zombies and Ghosts.
|
This mod adds 2 hostile and 1 friendly mob to Minetest, so far zombies, ghosts and sheeps.
|
||||||
|
|
||||||
Zombies can spawn to every day-time in the world as long there is not to much light.
|
Zombies can spawn to every day-time in the world as long there is not to much light.
|
||||||
So you will find some in caves, dark forests and ofc a lot at night. If they notice you they will attack.
|
So you will find some in caves, dark forests and ofc a lot at night. If they notice you they will attack.
|
||||||
@ -14,14 +14,23 @@ Zombies have 20 HP (like players) and drop rotten flesh randomly.
|
|||||||
|
|
||||||
Ghosts only spawn at night-time. Also they don't spawn underground and are a bit more rare than zombies.
|
Ghosts only spawn at night-time. Also they don't spawn underground and are a bit more rare than zombies.
|
||||||
They are flying in the world and attack you aswell if they notice you.
|
They are flying in the world and attack you aswell if they notice you.
|
||||||
Ghosts have 15 HP and don't drop any items atm (might be changed if i have an idea what they could drop).
|
Ghosts have 12 HP and don't drop any items atm (might be changed if i have an idea what they could drop).
|
||||||
|
|
||||||
|
Sheeps spawn only at day-time and are friendly mobs. They remain around 5 minutes in the world unless there
|
||||||
|
are other sheeps around, then there is no fixed limit. If there is grass (dirt with grass) they eat the grass
|
||||||
|
and get new wool that way.
|
||||||
|
Sheeps have 8 HP and drop 1-2 wool when punched. They need to eat grass until they can produce new wool.
|
||||||
|
|
||||||
They can't harm you in your house (in case there is no door open). If it becomes day both mobs will take damage
|
They can't harm you in your house (in case there is no door open). If it becomes day both mobs will take damage
|
||||||
by the sunlight, so they will die after a while.
|
by the sunlight, so they will die after a while.
|
||||||
|
|
||||||
|
|
||||||
Notice: You weapons get damage when hitting a zombie or ghost.
|
Notice: Weapons and tools get damaged when hitting a zombie or ghost. The wearout is calculated on the damage amout
|
||||||
|
of the tools/weapons. The more damage they can do that longer they can be used.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
- Diamond Sword: 1500 uses
|
||||||
|
- Wooden Sword: 30 uses
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -39,6 +48,13 @@ following sounds are created by Under7dude (freesound.org)
|
|||||||
- creatures_zombie.3.ogg, CC0
|
- creatures_zombie.3.ogg, CC0
|
||||||
- creatures_zombie_death.ogg, CC0
|
- creatures_zombie_death.ogg, CC0
|
||||||
|
|
||||||
|
following sounds are created by confusion_music (freesound.org)
|
||||||
|
- creatures_sheep.1.ogg, CC-BY 3.0
|
||||||
|
- creatures_sheep.2.ogg, CC-BY 3.0
|
||||||
|
|
||||||
|
following sound is created by Yuval (freesound.org)
|
||||||
|
- creatures_sheep.3.ogg, CC-BY 3.0
|
||||||
|
|
||||||
All other sounds (c) Copyright BlockMen (2014), CC-BY 3.0
|
All other sounds (c) Copyright BlockMen (2014), CC-BY 3.0
|
||||||
|
|
||||||
Changelog:
|
Changelog:
|
||||||
@ -46,6 +62,15 @@ Changelog:
|
|||||||
# 1.0.1
|
# 1.0.1
|
||||||
- fixed incompatibility with pyramids mod
|
- fixed incompatibility with pyramids mod
|
||||||
|
|
||||||
|
# 1.1
|
||||||
|
- new mob: sheep
|
||||||
|
- fixed crash caused by unknown node
|
||||||
|
- fixed spawning, added spawn limit
|
||||||
|
- fixed weapon & tool damage
|
||||||
|
- tweaked and restructured code
|
||||||
|
- ghosts only spawn on grass and desert-sand blocks
|
||||||
|
- ghosts have now 12 HP (instead 15 HP)
|
||||||
|
|
||||||
This program is free software. It comes without any warranty, to
|
This program is free software. It comes without any warranty, to
|
||||||
the extent permitted by applicable law. You can redistribute it
|
the extent permitted by applicable law. You can redistribute it
|
||||||
and/or modify it under the terms of the Do What The Fuck You Want
|
and/or modify it under the terms of the Do What The Fuck You Want
|
||||||
|
@ -1 +1,2 @@
|
|||||||
default
|
default
|
||||||
|
wool
|
104
ghost.lua
@ -2,17 +2,17 @@ local g_chillaxin_speed = 2
|
|||||||
local g_animation_speed = 10
|
local g_animation_speed = 10
|
||||||
local g_mesh = "creatures_mob.x"
|
local g_mesh = "creatures_mob.x"
|
||||||
local g_texture = {"creatures_ghost.png"}
|
local g_texture = {"creatures_ghost.png"}
|
||||||
local g_hp = 15
|
local g_hp = 12
|
||||||
local g_drop = ""
|
local g_drop = ""
|
||||||
local g_player_radius = 14
|
local g_player_radius = 14
|
||||||
local g_hit_radius = 1
|
local g_hit_radius = 1
|
||||||
local g_ll = 7
|
creatures.g_ll = 7
|
||||||
|
|
||||||
local g_sound_normal = "creatures_ghost"
|
local g_sound_normal = "creatures_ghost"
|
||||||
local g_sound_hit = "creatures_ghost_hit"
|
local g_sound_hit = "creatures_ghost_hit"
|
||||||
local g_sound_dead = "creatures_ghost_death"
|
local g_sound_dead = "creatures_ghost_death"
|
||||||
|
|
||||||
local g_spawn_nodes = {"default:dirt_with_grass","default:stone","default:dirt","default:desert_sand"}
|
creatures.g_spawn_nodes = {"default:dirt_with_grass","default:desert_sand"}
|
||||||
|
|
||||||
local function g_get_animations()
|
local function g_get_animations()
|
||||||
return {
|
return {
|
||||||
@ -21,13 +21,6 @@ local function g_get_animations()
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local ANIM_STAND = 1
|
|
||||||
local ANIM_SIT = 2
|
|
||||||
local ANIM_LAY = 3
|
|
||||||
local ANIM_WALK = 4
|
|
||||||
local ANIM_WALK_MINE = 5
|
|
||||||
local ANIM_MINE = 6
|
|
||||||
|
|
||||||
function g_hit(self)
|
function g_hit(self)
|
||||||
local sound = g_sound_hit
|
local sound = g_sound_hit
|
||||||
if self.object:get_hp() < 1 then sound = g_sound_dead end
|
if self.object:get_hp() < 1 then sound = g_sound_dead end
|
||||||
@ -85,7 +78,7 @@ GHOST_DEF.on_activate = function(self)
|
|||||||
self.anim = g_get_animations()
|
self.anim = g_get_animations()
|
||||||
self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, g_animation_speed, 0)
|
self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, g_animation_speed, 0)
|
||||||
self.npc_anim = ANIM_STAND
|
self.npc_anim = ANIM_STAND
|
||||||
self.object:setacceleration({x=0,y=0,z=0})--20
|
self.object:setacceleration({x=0,y=0,z=0})
|
||||||
self.state = 1
|
self.state = 1
|
||||||
self.object:set_hp(g_hp)
|
self.object:set_hp(g_hp)
|
||||||
self.object:set_armor_groups({fleshy=130})
|
self.object:set_armor_groups({fleshy=130})
|
||||||
@ -113,19 +106,8 @@ GHOST_DEF.on_punch = function(self, puncher, time_from_last_punch, tool_capabili
|
|||||||
elseif self.state >= 2 then
|
elseif self.state >= 2 then
|
||||||
self.state = 9
|
self.state = 9
|
||||||
end
|
end
|
||||||
--add wear to swords
|
-- add wear to sword/tool
|
||||||
if not minetest.setting_getbool("creative_mode") then
|
creatures.add_wear(puncher, tool_capabilities)
|
||||||
local item = puncher:get_wielded_item()
|
|
||||||
local def = item:get_definition()
|
|
||||||
if def and def.tool_capabilities and def.tool_capabilities.groupcaps
|
|
||||||
and def.tool_capabilities.groupcaps.snappy then
|
|
||||||
local uses = def.tool_capabilities.groupcaps.snappy.uses or 10
|
|
||||||
uses = uses*2 --since default values are too low
|
|
||||||
local wear = 65535/uses
|
|
||||||
item:add_wear(wear)
|
|
||||||
puncher:set_wielded_item(item)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -151,7 +133,6 @@ GHOST_DEF.on_step = function(self, dtime)
|
|||||||
|
|
||||||
-- death
|
-- death
|
||||||
if self.object:get_hp() < 1 then
|
if self.object:get_hp() < 1 then
|
||||||
--self.object:setvelocity({x=0,y=-20,z=0})
|
|
||||||
self.object:set_hp(0)
|
self.object:set_hp(0)
|
||||||
self.attacker = ""
|
self.attacker = ""
|
||||||
self.state = 0
|
self.state = 0
|
||||||
@ -167,10 +148,12 @@ GHOST_DEF.on_step = function(self, dtime)
|
|||||||
-- die when in water, lava or sunlight
|
-- die when in water, lava or sunlight
|
||||||
local wtime = minetest.env:get_timeofday()
|
local wtime = minetest.env:get_timeofday()
|
||||||
local ll = minetest.env:get_node_light({x=current_pos.x,y=current_pos.y+1,z=current_pos.z}) or 0
|
local ll = minetest.env:get_node_light({x=current_pos.x,y=current_pos.y+1,z=current_pos.z}) or 0
|
||||||
if current_node.name == "default:water_source" or
|
local nn = nil
|
||||||
current_node.name == "default:water_flowing" or
|
if current_node ~= nil then nn = current_node.name end
|
||||||
current_node.name == "default:lava_source" or
|
if nn ~= nil and nn == "default:water_source" or
|
||||||
current_node.name == "default:lava_flowing" or
|
nn == "default:water_flowing" or
|
||||||
|
nn == "default:lava_source" or
|
||||||
|
nn == "default:lava_flowing" or
|
||||||
(wtime > 0.2 and wtime < 0.805 and current_pos.y > 0 and ll > 11) then
|
(wtime > 0.2 and wtime < 0.805 and current_pos.y > 0 and ll > 11) then
|
||||||
self.sound_timer = self.sound_timer + dtime
|
self.sound_timer = self.sound_timer + dtime
|
||||||
if self.sound_timer >= 0.8 then
|
if self.sound_timer >= 0.8 then
|
||||||
@ -241,10 +224,10 @@ GHOST_DEF.on_step = function(self, dtime)
|
|||||||
self.direction = {x = math.sin(self.yaw)*-1, y = 0, z = math.cos(self.yaw)}
|
self.direction = {x = math.sin(self.yaw)*-1, y = 0, z = math.cos(self.yaw)}
|
||||||
end
|
end
|
||||||
self.object:setvelocity({x=0,y=self.object:getvelocity().y,z=0})
|
self.object:setvelocity({x=0,y=self.object:getvelocity().y,z=0})
|
||||||
if self.npc_anim ~= ANIM_STAND then
|
if self.npc_anim ~= creatures.ANIM_STAND then
|
||||||
self.anim = g_get_animations()
|
self.anim = g_get_animations()
|
||||||
self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, g_animation_speed, 0)
|
self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, g_animation_speed, 0)
|
||||||
self.npc_anim = ANIM_STAND
|
self.npc_anim = creatures.ANIM_STAND
|
||||||
end
|
end
|
||||||
if self.attacker ~= "" then
|
if self.attacker ~= "" then
|
||||||
self.direction = {x = math.sin(self.yaw)*-1, y = 0, z = math.cos(self.yaw)}
|
self.direction = {x = math.sin(self.yaw)*-1, y = 0, z = math.cos(self.yaw)}
|
||||||
@ -264,10 +247,10 @@ GHOST_DEF.on_step = function(self, dtime)
|
|||||||
self.turn_timer = 0
|
self.turn_timer = 0
|
||||||
self.direction = {x = math.sin(self.yaw)*-1, y = 0, z = math.cos(self.yaw)}
|
self.direction = {x = math.sin(self.yaw)*-1, y = 0, z = math.cos(self.yaw)}
|
||||||
end
|
end
|
||||||
if self.npc_anim ~= ANIM_WALK then
|
if self.npc_anim ~= creatures.ANIM_WALK then
|
||||||
self.anim = g_get_animations()
|
self.anim = g_get_animations()
|
||||||
self.object:set_animation({x=self.anim.walk_START,y=self.anim.walk_END}, g_animation_speed, 0)
|
self.object:set_animation({x=self.anim.walk_START,y=self.anim.walk_END}, g_animation_speed, 0)
|
||||||
self.npc_anim = ANIM_WALK
|
self.npc_anim = creatures.ANIM_WALK
|
||||||
end
|
end
|
||||||
--jump
|
--jump
|
||||||
if self.direction ~= nil and self.attacker ~= "" then
|
if self.direction ~= nil and self.attacker ~= "" then
|
||||||
@ -311,58 +294,3 @@ GHOST_DEF.on_step = function(self, dtime)
|
|||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_entity("creatures:ghost", GHOST_DEF)
|
minetest.register_entity("creatures:ghost", GHOST_DEF)
|
||||||
|
|
||||||
|
|
||||||
--spawn-egg
|
|
||||||
|
|
||||||
minetest.register_craftitem("creatures:ghost_spawn_egg", {
|
|
||||||
description = "Ghost spawn-egg",
|
|
||||||
inventory_image = "creatures_egg_ghost.png",
|
|
||||||
liquids_pointable = false,
|
|
||||||
stack_max = 99,
|
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
|
||||||
if pointed_thing.type == "node" then
|
|
||||||
local p = pointed_thing.above
|
|
||||||
p.y = p.y+0.5
|
|
||||||
creatures.spawn(p, 1, "creatures:ghost")
|
|
||||||
if not minetest.setting_getbool("creative_mode") then itemstack:take_item() end
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
if not minetest.setting_getbool("only_peaceful_mobs") then
|
|
||||||
-- spawn randomly in world
|
|
||||||
minetest.register_abm({
|
|
||||||
nodenames = g_spawn_nodes,
|
|
||||||
interval = 44.0,
|
|
||||||
chance = 7500,
|
|
||||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
|
||||||
if pos.y < 0 then return end
|
|
||||||
pos.y = pos.y+1
|
|
||||||
local ll = minetest.env:get_node_light(pos)
|
|
||||||
local wtime = minetest.env:get_timeofday()
|
|
||||||
if not ll then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if ll >= g_ll then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if ll < -1 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if minetest.env:get_node(pos).name ~= "air" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
pos.y = pos.y+1
|
|
||||||
if minetest.env:get_node(pos).name ~= "air" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if (wtime > 0.2 and wtime < 0.805) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
creatures.spawn(pos, 1, "creatures:ghost")
|
|
||||||
end
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
98
init.lua
@ -1,12 +1,100 @@
|
|||||||
creatures = {}
|
creatures = {}
|
||||||
|
|
||||||
function creatures.spawn(pos, number, mob)
|
creatures.ANIM_STAND = 1
|
||||||
print("spawn"..mob)
|
creatures.ANIM_SIT = 2
|
||||||
--log spawning?
|
creatures.ANIM_LAY = 3
|
||||||
|
creatures.ANIM_WALK = 4
|
||||||
|
creatures.ANIM_EAT = 5
|
||||||
|
creatures.ANIM_RUN = 6
|
||||||
|
|
||||||
|
local tool_uses = {0, 30, 110, 150, 280, 300, 500, 1000}
|
||||||
|
|
||||||
|
-- helping functions
|
||||||
|
|
||||||
|
function creatures.spawn(pos, number, mob, limit, range)
|
||||||
|
if not pos or not number or not mob then return end
|
||||||
|
if number < 1 then return end
|
||||||
|
if limit == nil then limit = 1 end
|
||||||
|
if range == nil then range = 10 end
|
||||||
|
local m_name = string.sub(mob,11)
|
||||||
|
local res,mobs,player_near = creatures.find_mates(pos, m_name, range)
|
||||||
for i=1,number do
|
for i=1,number do
|
||||||
minetest.env:add_entity(pos, mob)
|
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}
|
||||||
|
if mobs+i <= limit then
|
||||||
|
minetest.after(i/5,function()
|
||||||
|
minetest.env:add_entity(p, mob)
|
||||||
|
minetest.log("action", "Spawned "..mob.." at ("..pos.x..","..pos.y..","..pos.z..")")
|
||||||
|
end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function creatures.add_wear(player, def)
|
||||||
|
if not minetest.setting_getbool("creative_mode") then
|
||||||
|
local item = player:get_wielded_item()
|
||||||
|
if def and def.damage_groups and def.damage_groups.fleshy then
|
||||||
|
local uses = tool_uses[def.damage_groups.fleshy] or 0
|
||||||
|
if uses > 0 then
|
||||||
|
local wear = 65535/uses
|
||||||
|
item:add_wear(wear)
|
||||||
|
player:set_wielded_item(item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function creatures.drop(pos, items, dir)
|
||||||
|
if dir == nil then
|
||||||
|
dir = {x=1,y=1,z=1}
|
||||||
|
end
|
||||||
|
for _,item in ipairs(items) do
|
||||||
|
for i=1,item.count do
|
||||||
|
local x = 1/math.random(1,5)*dir.x--math.random(0, 6)/3 - 0.5*dir.x
|
||||||
|
local z = 1/math.random(1,5)*dir.z--math.random(0, 6)/3 - 0.5*dir.z
|
||||||
|
local p = {x=pos.x+x,y=pos.y,z=pos.z+z}
|
||||||
|
local node = minetest.get_node_or_nil(p)
|
||||||
|
if node == nil or not node.name or node.name ~= "air" then
|
||||||
|
p = pos
|
||||||
|
end
|
||||||
|
local obj = minetest.env:add_item(p, {name=item.name})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function creatures.find_mates(pos, name, radius)
|
||||||
|
local player_near = false
|
||||||
|
local mobs = 0
|
||||||
|
for _,obj in ipairs(minetest.env:get_objects_inside_radius(pos, radius)) do
|
||||||
|
if obj:is_player() then
|
||||||
|
player_near = true
|
||||||
|
else
|
||||||
|
if obj:get_luaentity().mob_name == name then mobs = mobs + 1 end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if mobs > 1 then
|
||||||
|
return true,mobs,player_near
|
||||||
|
end
|
||||||
|
return false,mobs,player_near
|
||||||
|
end
|
||||||
|
|
||||||
|
function creatures.compare_pos(pos1,pos2)
|
||||||
|
if pos1.x == pos2.x and pos1.y == pos2.y and pos1.z == pos2.z then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- hostile mobs
|
||||||
dofile(minetest.get_modpath("creatures").."/ghost.lua")
|
dofile(minetest.get_modpath("creatures").."/ghost.lua")
|
||||||
dofile(minetest.get_modpath("creatures").."/zombie.lua")
|
dofile(minetest.get_modpath("creatures").."/zombie.lua")
|
||||||
|
|
||||||
|
-- friendly mobs
|
||||||
|
dofile(minetest.get_modpath("creatures").."/sheep.lua")
|
||||||
|
|
||||||
|
-- spawning
|
||||||
|
dofile(minetest.get_modpath("creatures").."/spawn.lua")
|
||||||
|
dofile(minetest.get_modpath("creatures").."/spawners.lua")
|
||||||
|
-- other stuff
|
||||||
|
dofile(minetest.get_modpath("creatures").."/items.lua")
|
64
items.lua
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
-- drop items
|
||||||
|
minetest.register_craftitem("creatures:flesh", {
|
||||||
|
description = "Flesh",
|
||||||
|
inventory_image = "creatures_rotten_flesh.png",
|
||||||
|
on_use = minetest.item_eat(4),
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craftitem("creatures:rotten_flesh", {
|
||||||
|
description = "Rotten Flesh",
|
||||||
|
inventory_image = "creatures_rotten_flesh.png",
|
||||||
|
on_use = minetest.item_eat(1),
|
||||||
|
})
|
||||||
|
|
||||||
|
-- spawn-eggs
|
||||||
|
minetest.register_craftitem("creatures:zombie_spawn_egg", {
|
||||||
|
description = "Zombie spawn-egg",
|
||||||
|
inventory_image = "creatures_egg_zombie.png",
|
||||||
|
liquids_pointable = false,
|
||||||
|
stack_max = 99,
|
||||||
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
if pointed_thing.type == "node" then
|
||||||
|
local p = pointed_thing.above
|
||||||
|
p.y = p.y+1
|
||||||
|
creatures.spawn(p, 1, "creatures:zombie", 1, 1)
|
||||||
|
if not minetest.setting_getbool("creative_mode") then itemstack:take_item() end
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craftitem("creatures:ghost_spawn_egg", {
|
||||||
|
description = "Ghost spawn-egg",
|
||||||
|
inventory_image = "creatures_egg_ghost.png",
|
||||||
|
liquids_pointable = false,
|
||||||
|
stack_max = 99,
|
||||||
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
if pointed_thing.type == "node" then
|
||||||
|
local p = pointed_thing.above
|
||||||
|
p.y = p.y+0.5
|
||||||
|
creatures.spawn(p, 1, "creatures:ghost", 1, 1)
|
||||||
|
if not minetest.setting_getbool("creative_mode") then itemstack:take_item() end
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craftitem("creatures:sheep_spawn_egg", {
|
||||||
|
description = "Sheep spawn-egg",
|
||||||
|
inventory_image = "creatures_egg_sheep.png",
|
||||||
|
liquids_pointable = false,
|
||||||
|
stack_max = 99,
|
||||||
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
if pointed_thing.type == "node" then
|
||||||
|
local p = pointed_thing.above
|
||||||
|
p.y = p.y+0.5
|
||||||
|
creatures.spawn(p, 1, "creatures:sheep", 1, 1)
|
||||||
|
if not minetest.setting_getbool("creative_mode") then itemstack:take_item() end
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
})
|
Before Width: | Height: | Size: 385 B After Width: | Height: | Size: 511 B |
BIN
models/creatures_sheep.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
6751
models/creatures_sheep.x
Normal file
BIN
models/creatures_sheep_hit.png
Normal file
After Width: | Height: | Size: 186 B |
BIN
models/creatures_sheep_shaved.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 195 B After Width: | Height: | Size: 264 B |
345
sheep.lua
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
local s_chillaxin_speed = 1.5
|
||||||
|
local s_animation_speed = 15
|
||||||
|
local s_mesh = "creatures_sheep.x"
|
||||||
|
local s_texture = {"creatures_sheep.png"}
|
||||||
|
local s_hp = 8
|
||||||
|
local s_life_max = 80 --~5min
|
||||||
|
local s_drop = "wool:white"
|
||||||
|
|
||||||
|
local s_player_radius = 14
|
||||||
|
|
||||||
|
local s_sound_normal = "creatures_sheep"
|
||||||
|
local s_sound_hit = "creatures_sheep"
|
||||||
|
local s_sound_dead = "creatures_sheep"
|
||||||
|
|
||||||
|
creatures.s_spawn_nodes = {"default:dirt_with_grass"}
|
||||||
|
|
||||||
|
local function s_get_animations()
|
||||||
|
return {
|
||||||
|
stand_START = 0,
|
||||||
|
stand_END = 80,
|
||||||
|
walk_START = 81,
|
||||||
|
walk_END = 100,
|
||||||
|
eat_START = 107,
|
||||||
|
eat_END = 185
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function s_eat_anim(self)
|
||||||
|
self.object:set_animation({x=self.anim.eat_START,y=self.anim.eat_END}, s_animation_speed, 0)
|
||||||
|
self.npc_anim = creatures.ANIM_EAT
|
||||||
|
end
|
||||||
|
|
||||||
|
function s_hit(self)
|
||||||
|
local sound = s_sound_hit
|
||||||
|
if self.object:get_hp() < 1 then sound = s_sound_dead end
|
||||||
|
minetest.sound_play(sound, {pos = self.object:getpos(), max_hear_distance = 10, loop = false, gain = 0.4})
|
||||||
|
prop = {
|
||||||
|
mesh = s_mesh,
|
||||||
|
textures = {self.txture[1].."^creatures_sheep_hit.png"},
|
||||||
|
}
|
||||||
|
self.object:set_properties(prop)
|
||||||
|
self.can_punch = false
|
||||||
|
minetest.after(0.4, function()
|
||||||
|
s_update_visuals_def(self)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function s_update_visuals_def(self)
|
||||||
|
self.txture = {"creatures_sheep.png"}
|
||||||
|
if not self.has_wool then
|
||||||
|
self.txture = {"creatures_sheep_shaved.png"}
|
||||||
|
end
|
||||||
|
prop = {
|
||||||
|
mesh = s_mesh,
|
||||||
|
textures = self.txture,
|
||||||
|
}
|
||||||
|
self.object:set_properties(prop)
|
||||||
|
end
|
||||||
|
|
||||||
|
SHEEP_DEF = {
|
||||||
|
physical = true,
|
||||||
|
collisionbox = {-0.4, -0.01, -0.6, 0.4, 0.9, 0.4},
|
||||||
|
visual = "mesh",
|
||||||
|
visual_size = {x=1, y=1},
|
||||||
|
mesh = s_mesh,
|
||||||
|
textures = s_texture,
|
||||||
|
txture = s_texture,
|
||||||
|
makes_footstep_sound = true,
|
||||||
|
npc_anim = 0,
|
||||||
|
lifetime = 0,
|
||||||
|
timer = 0,
|
||||||
|
turn_timer = 0,
|
||||||
|
vec = 0,
|
||||||
|
yaw = 0,
|
||||||
|
yawwer = 0,
|
||||||
|
has_wool = true,
|
||||||
|
state = 1,
|
||||||
|
can_punch = true,
|
||||||
|
dead = false,
|
||||||
|
jump_timer = 0,
|
||||||
|
last_pos = {x=0,y=0,z=0},
|
||||||
|
punch_timer = 0,
|
||||||
|
sound_timer = 0,
|
||||||
|
mob_name = "sheep"
|
||||||
|
}
|
||||||
|
|
||||||
|
SHEEP_DEF.get_staticdata = function(self)
|
||||||
|
return minetest.serialize({
|
||||||
|
itemstring = self.itemstring,
|
||||||
|
timer = self.timer,
|
||||||
|
txture = self.txture,
|
||||||
|
has_wool = self.has_wool,
|
||||||
|
lifetime = self.lifetime,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
SHEEP_DEF.on_activate = function(self, staticdata, dtime_s)
|
||||||
|
self.txture = s_texture
|
||||||
|
s_update_visuals_def(self)
|
||||||
|
self.anim = s_get_animations()
|
||||||
|
self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, s_animation_speed, 0)
|
||||||
|
self.npc_anim = ANIM_STAND
|
||||||
|
self.object:setacceleration({x=0,y=-20,z=0})
|
||||||
|
self.object:setyaw(self.object:getyaw()+((math.random(0,90)-45)/45*math.pi))
|
||||||
|
self.lastpos = self.object:getpos()
|
||||||
|
self.state = 1
|
||||||
|
self.object:set_hp(s_hp)
|
||||||
|
self.object:set_armor_groups({fleshy=130})
|
||||||
|
self.can_punch = true
|
||||||
|
self.dead = false
|
||||||
|
self.has_wool = true
|
||||||
|
self.lifetime = 0
|
||||||
|
if staticdata then
|
||||||
|
local tmp = minetest.deserialize(staticdata)
|
||||||
|
if tmp and tmp.timer then
|
||||||
|
self.timer = tmp.timer
|
||||||
|
end
|
||||||
|
if tmp and tmp.has_wool ~= nil then
|
||||||
|
self.has_wool = tmp.has_wool
|
||||||
|
end
|
||||||
|
if tmp and tmp.lifetime ~= nil then
|
||||||
|
self.lifetime = tmp.lifetime
|
||||||
|
end
|
||||||
|
if not self.has_wool then
|
||||||
|
s_update_visuals_def(self)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
SHEEP_DEF.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
|
||||||
|
if not self.can_punch then return end
|
||||||
|
|
||||||
|
--SET RUN state (panic)
|
||||||
|
self.state = 4
|
||||||
|
self.timer = 0
|
||||||
|
|
||||||
|
if puncher ~= nil then
|
||||||
|
if time_from_last_punch >= 0.2 then --0.45
|
||||||
|
s_hit(self)
|
||||||
|
local v = self.object:getvelocity()
|
||||||
|
self.direction = {x=v.x, y=v.y, z=v.z}
|
||||||
|
self.punch_timer = 0
|
||||||
|
self.object:setvelocity({x=dir.x*2.5,y=5.2,z=dir.z*2.5})
|
||||||
|
self.state = 9
|
||||||
|
-- add wear to sword/tool
|
||||||
|
creatures.add_wear(puncher, tool_capabilities)
|
||||||
|
end
|
||||||
|
|
||||||
|
local my_pos = self.object:getpos()
|
||||||
|
my_pos.y = my_pos.y + 0.5
|
||||||
|
|
||||||
|
-- drop 1-2 whool when punched
|
||||||
|
if self.has_wool then
|
||||||
|
self.has_wool = false
|
||||||
|
creatures.drop(my_pos, {{name=s_drop, count=math.random(1,2)}}, dir)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
SHEEP_DEF.on_step = function(self, dtime)
|
||||||
|
if self.dead then return end
|
||||||
|
self.timer = self.timer + 0.01
|
||||||
|
self.lifetime = self.lifetime + 0.01
|
||||||
|
self.turn_timer = self.turn_timer + 0.01
|
||||||
|
self.jump_timer = self.jump_timer + 0.01
|
||||||
|
self.punch_timer = self.punch_timer + 0.01
|
||||||
|
self.sound_timer = self.sound_timer + 0.01
|
||||||
|
|
||||||
|
local current_pos = self.object:getpos()
|
||||||
|
local current_node = minetest.env:get_node(current_pos)
|
||||||
|
|
||||||
|
-- death
|
||||||
|
if self.object:get_hp() < 1 then
|
||||||
|
self.object:setvelocity({x=0,y=-20,z=0})
|
||||||
|
self.object:set_hp(0)
|
||||||
|
self.state = 0
|
||||||
|
self.dead = true
|
||||||
|
minetest.sound_play(s_sound_dead, {pos = current_pos, max_hear_distance = 10, gain = 0.9})
|
||||||
|
self.object:set_animation({x=self.anim.lay_START,y=self.anim.lay_END}, s_animation_speed, 0)
|
||||||
|
minetest.after(1, function()
|
||||||
|
if self.has_wool then
|
||||||
|
local obj = minetest.env:add_item(current_pos, s_drop)
|
||||||
|
end
|
||||||
|
self.object:remove()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- die if old and alone
|
||||||
|
if self.lifetime > s_life_max then
|
||||||
|
if creatures.find_mates(current_pos, "sheep", 18) then
|
||||||
|
self.lifetime = 0
|
||||||
|
else
|
||||||
|
self.object:set_hp(0)
|
||||||
|
self.state = 0
|
||||||
|
self.dead = true
|
||||||
|
self.object:remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- die when in water, lava
|
||||||
|
local wtime = minetest.env:get_timeofday()
|
||||||
|
local ll = minetest.env:get_node_light({x=current_pos.x,y=current_pos.y+1,z=current_pos.z}) or 0
|
||||||
|
local nn = nil
|
||||||
|
if current_node ~= nil then nn = current_node.name end
|
||||||
|
if nn ~= nil and nn == "default:water_source" or
|
||||||
|
nn == "default:water_flowing" or
|
||||||
|
nn == "default:lava_source" or
|
||||||
|
nn == "default:lava_flowing" then
|
||||||
|
self.sound_timer = self.sound_timer + 0.1
|
||||||
|
if self.sound_timer >= 0.8 then
|
||||||
|
local damage = 2
|
||||||
|
self.sound_timer = 0
|
||||||
|
self.object:set_hp(self.object:get_hp()-damage)
|
||||||
|
s_hit(self)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- update moving state depending on current state
|
||||||
|
if self.state < 4 then
|
||||||
|
if self.timer > 4/self.state then
|
||||||
|
self.timer = 0
|
||||||
|
local new = math.random(1,3)
|
||||||
|
if self.state == 3 then new = 1 end
|
||||||
|
self.state = new
|
||||||
|
s_update_visuals_def(self)
|
||||||
|
end
|
||||||
|
elseif self.state == 4 and self.timer > 1.5 then
|
||||||
|
self.state = 2
|
||||||
|
self.timer = 0
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- play random sound
|
||||||
|
if self.sound_timer > self.timer + math.random(5,self.lifetime/2) then
|
||||||
|
minetest.sound_play(s_sound_normal, {pos = current_pos, max_hear_distance = 10, gain = 0.7})
|
||||||
|
self.sound_timer = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
-- after knocked back
|
||||||
|
if self.state >= 8 then
|
||||||
|
if self.punch_timer > 0.15 then
|
||||||
|
if self.state == 9 then
|
||||||
|
self.object:setvelocity({x=self.direction.x*s_chillaxin_speed,y=-20,z=self.direction.z*s_chillaxin_speed})
|
||||||
|
self.state = 4
|
||||||
|
self.punch_timer = 0
|
||||||
|
elseif self.state == 8 then
|
||||||
|
self.object:setvelocity({x=0,y=-20,z=0})
|
||||||
|
self.state = 1
|
||||||
|
end
|
||||||
|
self.can_punch = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--STANDING
|
||||||
|
if self.state == 1 then
|
||||||
|
self.yawwer = true
|
||||||
|
if self.turn_timer > math.random(1,4) then
|
||||||
|
local last = self.yaw
|
||||||
|
self.yaw = last + math.random(-0.5,1)
|
||||||
|
if self.yaw > 22 or self.yaw < -17 then self.yaw = 0 end
|
||||||
|
self.object:setyaw(self.yaw)
|
||||||
|
self.turn_timer = 0
|
||||||
|
self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
|
||||||
|
end
|
||||||
|
self.object:setvelocity({x=0,y=self.object:getvelocity().y,z=0})
|
||||||
|
if self.npc_anim ~= creatures.ANIM_STAND then
|
||||||
|
self.anim = s_get_animations()
|
||||||
|
self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, s_animation_speed, 0)
|
||||||
|
self.npc_anim = creatures.ANIM_STAND
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- stop walking when not moving
|
||||||
|
if self.state == 2 and creatures.compare_pos(self.object:getpos(),self.lastpos) and self.jump_timer <= 0.2 then
|
||||||
|
self.state = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
-- WALKING
|
||||||
|
if self.state == 2 or self.state == 4 then
|
||||||
|
self.lastpos = self.object:getpos()
|
||||||
|
local speed = 1
|
||||||
|
local anim = creatures.ANIM_WALK
|
||||||
|
if self.state == 4 then
|
||||||
|
speed = 2.2
|
||||||
|
anim = creatures.ANIM_RUN
|
||||||
|
end
|
||||||
|
--[[if self.farmer ~= "" then
|
||||||
|
--use this for following weed, etc
|
||||||
|
self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
|
||||||
|
end]]
|
||||||
|
|
||||||
|
if self.direction ~= nil then
|
||||||
|
self.object:setvelocity({x=self.direction.x*s_chillaxin_speed*speed,y=self.object:getvelocity().y,z=self.direction.z*s_chillaxin_speed*speed})
|
||||||
|
end
|
||||||
|
if (self.turn_timer > math.random(0.8,2)) or (self.state == 4 and self.turn_timer > 0.2) then
|
||||||
|
if self.state == 2 then
|
||||||
|
local last = self.yaw
|
||||||
|
self.yaw = last + math.random(-1,0.5)
|
||||||
|
if self.yaw > 22 or self.yaw < -17 then self.yaw = 0 end
|
||||||
|
else
|
||||||
|
self.yaw = 360 * math.random()
|
||||||
|
end
|
||||||
|
self.object:setyaw(self.yaw)
|
||||||
|
self.turn_timer = 0
|
||||||
|
self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
|
||||||
|
end
|
||||||
|
if self.npc_anim ~= anim then
|
||||||
|
self.object:set_animation({x=self.anim.walk_START,y=self.anim.walk_END}, s_animation_speed*speed, 0)
|
||||||
|
self.npc_anim = anim
|
||||||
|
end
|
||||||
|
--jump
|
||||||
|
if self.direction ~= nil then
|
||||||
|
if self.jump_timer > 0.2 then
|
||||||
|
self.jump_timer = 0
|
||||||
|
local p = current_pos
|
||||||
|
local n = minetest.env:get_node({x=p.x + self.direction.x,y=p.y,z=p.z + self.direction.z})
|
||||||
|
if n and n.name and minetest.registered_items[n.name].walkable and minetest.registered_items[n.name].groups.fences == nil and n.name ~= "default:fence_wood" then
|
||||||
|
self.object:setvelocity({x=self.object:getvelocity().x,y=6.85,z=self.object:getvelocity().z})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- EATING
|
||||||
|
if self.state == 3 then--and not self.has_wool then
|
||||||
|
self.object:setvelocity({x=0,y=self.object:getvelocity().y,z=0})
|
||||||
|
local p = {x=current_pos.x,y=current_pos.y-1,z=current_pos.z}
|
||||||
|
local n = minetest.get_node(p) or nil
|
||||||
|
if n and n.name and n.name == "default:dirt_with_grass" then
|
||||||
|
if self.timer == 0 then
|
||||||
|
s_eat_anim(self)
|
||||||
|
self.timer = 0.45
|
||||||
|
end
|
||||||
|
minetest.after(1.8,function()
|
||||||
|
minetest.set_node(p,{name="default:dirt"})
|
||||||
|
self.has_wool = true
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_entity("creatures:sheep", SHEEP_DEF)
|
BIN
sounds/creatures_sheep.1.ogg
Normal file
BIN
sounds/creatures_sheep.2.ogg
Normal file
BIN
sounds/creatures_sheep.3.ogg
Normal file
88
spawn.lua
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
-- hostile mobs
|
||||||
|
if not minetest.setting_getbool("only_peaceful_mobs") then
|
||||||
|
-- zombie
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames = creatures.z_spawn_nodes,
|
||||||
|
interval = 40.0,
|
||||||
|
chance = 7600,
|
||||||
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
|
local n = minetest.get_node_or_nil(pos)
|
||||||
|
--if n and n.name and n.name ~= "default:stone" and math.random(1,4)>3 then return end
|
||||||
|
pos.y = pos.y+1
|
||||||
|
local ll = minetest.env:get_node_light(pos)
|
||||||
|
local wtime = minetest.env:get_timeofday()
|
||||||
|
if not ll then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if ll >= creatures.z_ll then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if ll < -1 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if minetest.env:get_node(pos).name ~= "air" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
pos.y = pos.y+1
|
||||||
|
if minetest.env:get_node(pos).name ~= "air" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
creatures.spawn(pos, 1, "creatures:zombie", 2, 20)
|
||||||
|
end})
|
||||||
|
-- ghost
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames = creatures.g_spawn_nodes,
|
||||||
|
interval = 44.0,
|
||||||
|
chance = 8350,
|
||||||
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
|
if pos.y < 0 then return end
|
||||||
|
pos.y = pos.y+1
|
||||||
|
local ll = minetest.env:get_node_light(pos)
|
||||||
|
local wtime = minetest.env:get_timeofday()
|
||||||
|
if not ll then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if ll >= creatures.g_ll then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if ll < -1 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if minetest.env:get_node(pos).name ~= "air" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
pos.y = pos.y+1
|
||||||
|
if minetest.env:get_node(pos).name ~= "air" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if (wtime > 0.2 and wtime < 0.805) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
creatures.spawn(pos, 1, "creatures:ghost", 2, 35)
|
||||||
|
end})
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- peaceful
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames = creatures.s_spawn_nodes,
|
||||||
|
interval = 55.0,
|
||||||
|
chance = 7800,
|
||||||
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
|
if pos.y < 0 then return end
|
||||||
|
pos.y = pos.y+1
|
||||||
|
local ll = minetest.env:get_node_light(pos) or 0
|
||||||
|
if ll < 14 then return end
|
||||||
|
local wtime = minetest.env:get_timeofday()
|
||||||
|
if minetest.env:get_node(pos).name ~= "air" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if minetest.env:get_node(pos).name ~= "air" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if (wtime < 0.2 and wtime > 0.805) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if math.random(1,10) > 8 then return end
|
||||||
|
creatures.spawn(pos, math.random(1,2), "creatures:sheep", 5, 35)
|
||||||
|
end})
|
94
spawners.lua
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
function creatures.register_spawner(mob,size,offset,mesh,texture,range,max,max_ll,min_ll,day_only)
|
||||||
|
local DUMMY = {
|
||||||
|
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 * -2.9,
|
||||||
|
m_name = "dummy"
|
||||||
|
}
|
||||||
|
|
||||||
|
DUMMY.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
|
||||||
|
|
||||||
|
DUMMY.on_step = function(self, dtime)
|
||||||
|
self.timer = self.timer + 0.01
|
||||||
|
local n = minetest.get_node_or_nil(self.object:getpos())
|
||||||
|
if self.timer > 1 then
|
||||||
|
if n and n.name and n.name ~= "creatures:"..mob.."_spawner" then
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
DUMMY.on_punch = function(self, hitter)
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_entity("creatures:dummy_"..mob, DUMMY)
|
||||||
|
|
||||||
|
-- node
|
||||||
|
minetest.register_node("creatures:"..mob.."_spawner", {
|
||||||
|
description = mob.." spawner",
|
||||||
|
paramtype = "light",
|
||||||
|
tiles = {"creatures_spawner.png"},
|
||||||
|
is_ground_content = true,
|
||||||
|
drawtype = "allfaces",
|
||||||
|
groups = {cracky=1,level=1},
|
||||||
|
drop = "",
|
||||||
|
on_construct = function(pos)
|
||||||
|
pos.y = pos.y + offset
|
||||||
|
minetest.env:add_entity(pos,"creatures:dummy_"..mob)
|
||||||
|
end,
|
||||||
|
on_destruct = function(pos)
|
||||||
|
for _,obj in ipairs(minetest.env:get_objects_inside_radius(pos, 1)) do
|
||||||
|
if not obj:is_player() then
|
||||||
|
if obj ~= nil and obj:get_luaentity().m_name == "dummy" then
|
||||||
|
obj:remove()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
--abm
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames = {"creatures:"..mob.."_spawner"},
|
||||||
|
interval = 2.0,
|
||||||
|
chance = 20,
|
||||||
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
|
local res,player_near = false
|
||||||
|
local mobs = 0
|
||||||
|
res,mobs,player_near = creatures.find_mates(pos, mob, range)
|
||||||
|
if player_near then
|
||||||
|
if mobs < max then
|
||||||
|
pos.x = pos.x+1
|
||||||
|
local p = minetest.find_node_near(pos, 5, {"air"})
|
||||||
|
local ll = minetest.env:get_node_light(p)
|
||||||
|
local wtime = minetest.env:get_timeofday()
|
||||||
|
if not ll then return end
|
||||||
|
if ll > max_ll then return end
|
||||||
|
if ll < min_ll then return end
|
||||||
|
if minetest.env:get_node(p).name ~= "air" then return end
|
||||||
|
p.y = p.y+1
|
||||||
|
if minetest.env:get_node(p).name ~= "air" then return end
|
||||||
|
if not day_only then
|
||||||
|
if (wtime > 0.2 and wtime < 0.805) and pos.y > 0 then return end
|
||||||
|
end
|
||||||
|
|
||||||
|
p.y = p.y-1
|
||||||
|
creatures.spawn(p, 1, "creatures:"..mob,range,max)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end })
|
||||||
|
end
|
||||||
|
|
||||||
|
-- spawner
|
||||||
|
creatures.register_spawner("zombie",{x=0.42,y=0.42},0.08,"creatures_mob.x",{"creatures_zombie.png"},17,6,7,-1,false)
|
||||||
|
creatures.register_spawner("sheep",{x=0.42,y=0.42},-0.3,"creatures_sheep.x",{"creatures_sheep.png"},17,6,18,10,true)
|
BIN
textures/creatures_egg_sheep.png
Normal file
After Width: | Height: | Size: 675 B |
BIN
textures/creatures_flesh.png
Normal file
After Width: | Height: | Size: 351 B |
230
zombie.lua
@ -1,10 +1,3 @@
|
|||||||
minetest.register_craftitem("creatures:rotten_flesh", {
|
|
||||||
description = "Rotten Flesh",
|
|
||||||
inventory_image = "creatures_rotten_flesh.png",
|
|
||||||
on_use = minetest.item_eat(1),
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
local z_chillaxin_speed = 1.5
|
local z_chillaxin_speed = 1.5
|
||||||
local z_animation_speed = 15
|
local z_animation_speed = 15
|
||||||
local z_mesh = "creatures_mob.x"
|
local z_mesh = "creatures_mob.x"
|
||||||
@ -14,15 +7,15 @@ local z_drop = "creatures:rotten_flesh"
|
|||||||
|
|
||||||
local z_player_radius = 14
|
local z_player_radius = 14
|
||||||
local z_hit_radius = 1.4
|
local z_hit_radius = 1.4
|
||||||
local z_ll = 7
|
creatures.z_ll = 7
|
||||||
|
|
||||||
local z_sound_normal = "creatures_zombie"
|
local z_sound_normal = "creatures_zombie"
|
||||||
local z_sound_hit = "creatures_zombie_hit"
|
local z_sound_hit = "creatures_zombie_hit"
|
||||||
local z_sound_dead = "creatures_zombie_death"
|
local z_sound_dead = "creatures_zombie_death"
|
||||||
|
|
||||||
local z_spawn_nodes = {"default:dirt_with_grass","default:stone","default:dirt","default:desert_sand"}
|
creatures.z_spawn_nodes = {"default:dirt_with_grass","default:stone","default:dirt","default:desert_sand"}
|
||||||
local z_spawner_range = 17
|
creatures.z_spawner_range = 17
|
||||||
local z_spawner_max_mobs = 6
|
creatures.z_spawner_max_mobs = 6
|
||||||
|
|
||||||
local function z_get_animations()
|
local function z_get_animations()
|
||||||
return {
|
return {
|
||||||
@ -38,13 +31,6 @@ local function z_get_animations()
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local ANIM_STAND = 1
|
|
||||||
local ANIM_SIT = 2
|
|
||||||
local ANIM_LAY = 3
|
|
||||||
local ANIM_WALK = 4
|
|
||||||
local ANIM_WALK_MINE = 5
|
|
||||||
local ANIM_MINE = 6
|
|
||||||
|
|
||||||
function z_hit(self)
|
function z_hit(self)
|
||||||
local sound = z_sound_hit
|
local sound = z_sound_hit
|
||||||
if self.object:get_hp() < 1 then sound = z_sound_dead end
|
if self.object:get_hp() < 1 then sound = z_sound_dead end
|
||||||
@ -95,40 +81,6 @@ ZOMBIE_DEF = {
|
|||||||
mob_name = "zombie"
|
mob_name = "zombie"
|
||||||
}
|
}
|
||||||
|
|
||||||
spawner_DEF = {
|
|
||||||
hp_max = 1,
|
|
||||||
physical = true,
|
|
||||||
collisionbox = {0,0,0,0,0,0},
|
|
||||||
visual = "mesh",
|
|
||||||
visual_size = {x=0.42,y=0.42},
|
|
||||||
mesh = z_mesh,
|
|
||||||
textures = z_texture,
|
|
||||||
makes_footstep_sound = false,
|
|
||||||
timer = 0,
|
|
||||||
automatic_rotate = math.pi * -2.9,
|
|
||||||
m_name = "dummy"
|
|
||||||
}
|
|
||||||
|
|
||||||
spawner_DEF.on_activate = function(self)
|
|
||||||
z_update_visuals_def(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
|
|
||||||
|
|
||||||
spawner_DEF.on_step = function(self, dtime)
|
|
||||||
self.timer = self.timer + 0.01
|
|
||||||
local n = minetest.get_node_or_nil(self.object:getpos())
|
|
||||||
if self.timer > 1 then
|
|
||||||
if n and n.name and n.name ~= "creatures:zombie_spawner" then
|
|
||||||
self.object:remove()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
spawner_DEF.on_punch = function(self, hitter)
|
|
||||||
end
|
|
||||||
|
|
||||||
ZOMBIE_DEF.on_activate = function(self)
|
ZOMBIE_DEF.on_activate = function(self)
|
||||||
z_update_visuals_def(self)
|
z_update_visuals_def(self)
|
||||||
self.anim = z_get_animations()
|
self.anim = z_get_animations()
|
||||||
@ -161,24 +113,13 @@ ZOMBIE_DEF.on_punch = function(self, puncher, time_from_last_punch, tool_capabil
|
|||||||
elseif self.state >= 2 then
|
elseif self.state >= 2 then
|
||||||
self.state = 9
|
self.state = 9
|
||||||
end
|
end
|
||||||
--add wear to swords
|
-- add wear to sword/tool
|
||||||
if not minetest.setting_getbool("creative_mode") then
|
creatures.add_wear(puncher, tool_capabilities)
|
||||||
local item = puncher:get_wielded_item()
|
|
||||||
local def = item:get_definition()
|
|
||||||
if def and def.tool_capabilities and def.tool_capabilities.groupcaps
|
|
||||||
and def.tool_capabilities.groupcaps.snappy then
|
|
||||||
local uses = def.tool_capabilities.groupcaps.snappy.uses or 10
|
|
||||||
uses = uses*2 --since default values are too low
|
|
||||||
local wear = 65535/uses
|
|
||||||
item:add_wear(wear)
|
|
||||||
puncher:set_wielded_item(item)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.object:get_hp() < 1 then
|
if self.object:get_hp() < 1 then
|
||||||
local obj = minetest.env:add_item(my_pos, z_drop.." "..math.random(0,3))
|
creatures.drop(my_pos, {{name=z_drop, count=math.random(0,2)}}, dir)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -192,7 +133,7 @@ ZOMBIE_DEF.on_step = function(self, dtime)
|
|||||||
self.sound_timer = self.sound_timer + 0.01
|
self.sound_timer = self.sound_timer + 0.01
|
||||||
|
|
||||||
local current_pos = self.object:getpos()
|
local current_pos = self.object:getpos()
|
||||||
local current_node = minetest.env:get_node(current_pos)
|
local current_node = minetest.env:get_node_or_nil(current_pos)
|
||||||
if self.time_passed == nil then
|
if self.time_passed == nil then
|
||||||
self.time_passed = 0
|
self.time_passed = 0
|
||||||
end
|
end
|
||||||
@ -207,18 +148,22 @@ ZOMBIE_DEF.on_step = function(self, dtime)
|
|||||||
minetest.sound_play(z_sound_dead, {pos = current_pos, max_hear_distance = 10, gain = 0.9})
|
minetest.sound_play(z_sound_dead, {pos = current_pos, max_hear_distance = 10, gain = 0.9})
|
||||||
self.object:set_animation({x=self.anim.lay_START,y=self.anim.lay_END}, z_animation_speed, 0)
|
self.object:set_animation({x=self.anim.lay_START,y=self.anim.lay_END}, z_animation_speed, 0)
|
||||||
minetest.after(1, function()
|
minetest.after(1, function()
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
local obj = minetest.env:add_item(current_pos, z_drop.." "..math.random(0,3))
|
if self.object:get_hp() < 1 then
|
||||||
|
creatures.drop(current_pos, {{name=z_drop, count=math.random(0,2)}})
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- die when in water, lava or sunlight
|
-- die when in water, lava or sunlight
|
||||||
local wtime = minetest.env:get_timeofday()
|
local wtime = minetest.env:get_timeofday()
|
||||||
local ll = minetest.env:get_node_light({x=current_pos.x,y=current_pos.y+1,z=current_pos.z}) or 0
|
local ll = minetest.env:get_node_light({x=current_pos.x,y=current_pos.y+1,z=current_pos.z}) or 0
|
||||||
if current_node.name == "default:water_source" or
|
local nn = nil
|
||||||
current_node.name == "default:water_flowing" or
|
if current_node ~= nil then nn = current_node.name end
|
||||||
current_node.name == "default:lava_source" or
|
if nn ~= nil and nn == "default:water_source" or
|
||||||
current_node.name == "default:lava_flowing" or
|
nn == "default:water_flowing" or
|
||||||
|
nn == "default:lava_source" or
|
||||||
|
nn == "default:lava_flowing" or
|
||||||
(wtime > 0.2 and wtime < 0.805 and current_pos.y > 0 and ll > 11) then
|
(wtime > 0.2 and wtime < 0.805 and current_pos.y > 0 and ll > 11) then
|
||||||
self.sound_timer = self.sound_timer + dtime
|
self.sound_timer = self.sound_timer + dtime
|
||||||
if self.sound_timer >= 0.8 then
|
if self.sound_timer >= 0.8 then
|
||||||
@ -282,17 +227,17 @@ ZOMBIE_DEF.on_step = function(self, dtime)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.attacker == "" and self.turn_timer > math.random(1,4) then--and yawwer == true then
|
if self.attacker == "" and self.turn_timer > math.random(1,4) then
|
||||||
self.yaw = 360 * math.random()
|
self.yaw = 360 * math.random()
|
||||||
self.object:setyaw(self.yaw)
|
self.object:setyaw(self.yaw)
|
||||||
self.turn_timer = 0
|
self.turn_timer = 0
|
||||||
self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
|
self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
|
||||||
end
|
end
|
||||||
self.object:setvelocity({x=0,y=self.object:getvelocity().y,z=0})
|
self.object:setvelocity({x=0,y=self.object:getvelocity().y,z=0})
|
||||||
if self.npc_anim ~= ANIM_STAND then
|
if self.npc_anim ~= creatures.ANIM_STAND then
|
||||||
self.anim = z_get_animations()
|
self.anim = z_get_animations()
|
||||||
self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, z_animation_speed, 0)
|
self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, z_animation_speed, 0)
|
||||||
self.npc_anim = ANIM_STAND
|
self.npc_anim = creatures.ANIM_STAND
|
||||||
end
|
end
|
||||||
if self.attacker ~= "" then
|
if self.attacker ~= "" then
|
||||||
self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
|
self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
|
||||||
@ -333,8 +278,7 @@ ZOMBIE_DEF.on_step = function(self, dtime)
|
|||||||
if self.state == 2 then
|
if self.state == 2 then
|
||||||
|
|
||||||
if self.attacker ~= "" then
|
if self.attacker ~= "" then
|
||||||
self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
|
self.direction = {x=math.sin(self.yaw)*-1, y=-20, z=math.cos(self.yaw)}
|
||||||
--self.state = 2
|
|
||||||
end
|
end
|
||||||
if self.direction ~= nil then
|
if self.direction ~= nil then
|
||||||
self.object:setvelocity({x=self.direction.x*z_chillaxin_speed,y=self.object:getvelocity().y,z=self.direction.z*z_chillaxin_speed})
|
self.object:setvelocity({x=self.direction.x*z_chillaxin_speed,y=self.object:getvelocity().y,z=self.direction.z*z_chillaxin_speed})
|
||||||
@ -343,25 +287,21 @@ ZOMBIE_DEF.on_step = function(self, dtime)
|
|||||||
self.yaw = 360 * math.random()
|
self.yaw = 360 * math.random()
|
||||||
self.object:setyaw(self.yaw)
|
self.object:setyaw(self.yaw)
|
||||||
self.turn_timer = 0
|
self.turn_timer = 0
|
||||||
self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
|
self.direction = {x=math.sin(self.yaw)*-1, y=-20, z=math.cos(self.yaw)}
|
||||||
end
|
end
|
||||||
if self.npc_anim ~= ANIM_WALK then
|
if self.npc_anim ~= creatures.ANIM_WALK then
|
||||||
self.npc_anim = ANIM_WALK
|
self.npc_anim = creatures.ANIM_WALK
|
||||||
--self.anim = z_get_animations()
|
|
||||||
self.object:set_animation({x=self.anim.walk_START,y=self.anim.walk_END}, z_animation_speed, 0)
|
self.object:set_animation({x=self.anim.walk_START,y=self.anim.walk_END}, z_animation_speed, 0)
|
||||||
self.npc_anim = ANIM_WALK
|
|
||||||
end
|
end
|
||||||
--jump
|
--jump
|
||||||
if self.direction ~= nil then
|
if self.direction ~= nil then
|
||||||
if self.jump_timer > 0.3 then
|
if self.jump_timer > 0.25 then
|
||||||
self.jump_timer = 0
|
self.jump_timer = 0
|
||||||
local p = current_pos
|
local p = current_pos
|
||||||
local n = minetest.env:get_node({x=p.x + self.direction.x,y=p.y-0.5,z=p.z + self.direction.z})
|
local n = minetest.env:get_node_or_nil({x=p.x + self.direction.x,y=p.y-0.5,z=p.z + self.direction.z})
|
||||||
--print(n.name)
|
if n and n.name and minetest.registered_items[n.name].walkable and minetest.registered_items[n.name].groups.fences == nil and n.name ~= "default:fence_wood" then
|
||||||
if n and n.name and minetest.registered_items[n.name].walkable then
|
self.object:setvelocity({x=self.object:getvelocity().x,y=7.1,z=self.object:getvelocity().z})
|
||||||
self.object:setvelocity({x=self.object:getvelocity().x,y=7,z=self.object:getvelocity().z})
|
|
||||||
end
|
end
|
||||||
--end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -384,115 +324,3 @@ ZOMBIE_DEF.on_step = function(self, dtime)
|
|||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_entity("creatures:zombie", ZOMBIE_DEF)
|
minetest.register_entity("creatures:zombie", ZOMBIE_DEF)
|
||||||
minetest.register_entity("creatures:z_spawner_mob", spawner_DEF)
|
|
||||||
|
|
||||||
|
|
||||||
--spawn-egg/spawner
|
|
||||||
|
|
||||||
minetest.register_craftitem("creatures:zombie_spawn_egg", {
|
|
||||||
description = "Zombie spawn-egg",
|
|
||||||
inventory_image = "creatures_egg_zombie.png",
|
|
||||||
liquids_pointable = false,
|
|
||||||
stack_max = 99,
|
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
|
||||||
if pointed_thing.type == "node" then
|
|
||||||
local p = pointed_thing.above
|
|
||||||
p.y = p.y+1
|
|
||||||
creatures.spawn(p, 1, "creatures:zombie")
|
|
||||||
if not minetest.setting_getbool("creative_mode") then itemstack:take_item() end
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_node("creatures:zombie_spawner", {
|
|
||||||
description = "Zombie spawner",
|
|
||||||
paramtype = "light",
|
|
||||||
tiles = {"creatures_spawner.png"},
|
|
||||||
is_ground_content = true,
|
|
||||||
drawtype = "allfaces",
|
|
||||||
groups = {cracky=1,level=1},
|
|
||||||
drop = "",
|
|
||||||
on_construct = function(pos)
|
|
||||||
pos.y = pos.y + 0.08
|
|
||||||
minetest.env:add_entity(pos,"creatures:z_spawner_mob")
|
|
||||||
end,
|
|
||||||
on_destruct = function(pos)
|
|
||||||
for _,obj in ipairs(minetest.env:get_objects_inside_radius(pos, 1)) do
|
|
||||||
if not obj:is_player() then
|
|
||||||
if obj ~= nil and obj:get_luaentity().m_name == "dummy" then
|
|
||||||
obj:remove()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
|
|
||||||
if not minetest.setting_getbool("only_peaceful_mobs") then
|
|
||||||
-- spawn randomly in world
|
|
||||||
minetest.register_abm({
|
|
||||||
nodenames = z_spawn_nodes,
|
|
||||||
interval = 40.0,
|
|
||||||
chance = 7200,
|
|
||||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
|
||||||
local n = minetest.get_node(pos)
|
|
||||||
--if n and n.name and n.name ~= "default:stone" and math.random(1,4)>3 then return end
|
|
||||||
pos.y = pos.y+1
|
|
||||||
local ll = minetest.env:get_node_light(pos)
|
|
||||||
local wtime = minetest.env:get_timeofday()
|
|
||||||
if not ll then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if ll >= z_ll then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if ll < -1 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if minetest.env:get_node(pos).name ~= "air" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
pos.y = pos.y+1
|
|
||||||
if minetest.env:get_node(pos).name ~= "air" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
creatures.spawn(pos, 1, "creatures:zombie")
|
|
||||||
end
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_abm({
|
|
||||||
nodenames = {"creatures:zombie_spawner"},
|
|
||||||
interval = 2.0,
|
|
||||||
chance = 20,
|
|
||||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
|
||||||
local player_near = false
|
|
||||||
local mobs = 0
|
|
||||||
for _,obj in ipairs(minetest.env:get_objects_inside_radius(pos, z_spawner_range)) do
|
|
||||||
if obj:is_player() then
|
|
||||||
player_near = true
|
|
||||||
else
|
|
||||||
if obj:get_luaentity().mob_name == "zombie" then mobs = mobs + 1 end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if player_near then
|
|
||||||
if mobs < z_spawner_max_mobs then
|
|
||||||
pos.x = pos.x+1
|
|
||||||
local p = minetest.find_node_near(pos, 5, {"air"})
|
|
||||||
--p.y = p.y+1
|
|
||||||
local ll = minetest.env:get_node_light(p)
|
|
||||||
local wtime = minetest.env:get_timeofday()
|
|
||||||
if not ll then return end
|
|
||||||
if ll > 8 then return end
|
|
||||||
if ll < -1 then return end
|
|
||||||
if minetest.env:get_node(p).name ~= "air" then return end
|
|
||||||
p.y = p.y+1
|
|
||||||
if minetest.env:get_node(p).name ~= "air" then return end
|
|
||||||
if (wtime > 0.2 and wtime < 0.805) and pos.y > 0 then return end
|
|
||||||
p.y = p.y-1
|
|
||||||
creatures.spawn(p, 1, "creatures:zombie")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|