Version 1.0.1

master
BlockMen 2014-03-13 10:38:24 +01:00
commit d5db6af4de
23 changed files with 6456 additions and 0 deletions

53
README.txt Normal file
View File

@ -0,0 +1,53 @@
Minetest mod "Creatures"
=======================
by BlockMen (c) 2014
Version: 1.0.1 Beta
About
~~~~~
This mod add (currently only) hostile mobs to Minetest, so far Zombies and Ghosts.
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.
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.
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).
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.
Notice: You weapons get damage when hitting a zombie or ghost.
License of source code, textures and mesh model: WTFPL
------------------------------------------------------
(c) Copyright BlockMen (2014)
Licenses of sounds
------------------
following sounds are created by Under7dude (freesound.org)
- creatures_zombie.1.ogg, CC0
- creatures_zombie.2.ogg, CC0
- creatures_zombie.3.ogg, CC0
- creatures_zombie_death.ogg, CC0
All other sounds (c) Copyright BlockMen (2014), CC-BY 3.0
Changelog:
----------
# 1.0.1
- fixed incompatibility with pyramids mod
This program is free software. It comes without any warranty, to
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
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

1
depends.txt Normal file
View File

@ -0,0 +1 @@
default

368
ghost.lua Normal file
View File

@ -0,0 +1,368 @@
local g_chillaxin_speed = 2
local g_animation_speed = 10
local g_mesh = "creatures_mob.x"
local g_texture = {"creatures_ghost.png"}
local g_hp = 15
local g_drop = ""
local g_player_radius = 14
local g_hit_radius = 1
local g_ll = 7
local g_sound_normal = "creatures_ghost"
local g_sound_hit = "creatures_ghost_hit"
local g_sound_dead = "creatures_ghost_death"
local g_spawn_nodes = {"default:dirt_with_grass","default:stone","default:dirt","default:desert_sand"}
local function g_get_animations()
return {
walk_START = 168,
walk_END = 187
}
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)
local sound = g_sound_hit
if self.object:get_hp() < 1 then sound = g_sound_dead end
minetest.sound_play(sound, {pos = self.object:getpos(), max_hear_distance = 10, loop = false, gain = 0.4})
prop = {
mesh = g_mesh,
textures = {"creatures_ghost.png^creatures_ghost_hit.png"},
}
self.object:set_properties(prop)
self.can_punch = false
minetest.after(0.4, function()
g_update_visuals_def(self)
end)
end
function g_update_visuals_def(self)
self.can_punch = true
prop = {
mesh = g_mesh,
textures = g_texture,
}
self.object:set_properties(prop)
end
GHOST_DEF = {
physical = true,
collisionbox = {-0.3, -0.5, -0.3, 0.3, 0.75, 0.3},
visual = "mesh",
visual_size = {x=1, y=1},
mesh = g_mesh,
textures = g_texture,
makes_footstep_sound = false,
npc_anim = 0,
timer = 0,
turn_timer = 0,
vec = 0,
yaw = 0,
yawwer = 0,
dist = 0,
state = 1,
can_punch = true,
dead = false,
jump_timer = 0,
last_pos = {x=0,y=0,z=0},
punch_timer = 0,
sound_timer = 0,
attacker = "",
attacking_timer = 0,
mob_name = "ghost"
}
GHOST_DEF.on_activate = function(self)
g_update_visuals_def(self)
self.anim = g_get_animations()
self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, g_animation_speed, 0)
self.npc_anim = ANIM_STAND
self.object:setacceleration({x=0,y=0,z=0})--20
self.state = 1
self.object:set_hp(g_hp)
self.object:set_armor_groups({fleshy=130})
self.last_pos = {x=0,y=0,z=0}
self.can_punch = true
self.dead = false
self.dist = math.random(0,1)
end
GHOST_DEF.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
if not self.can_punch then return end
local my_pos = self.object:getpos()
if puncher ~= nil then
self.attacker = puncher
if time_from_last_punch >= 0.45 then
g_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*g_chillaxin_speed,y=0,z=dir.z*g_chillaxin_speed})
if self.state == 1 then
self.state = 8
elseif self.state >= 2 then
self.state = 9
end
--add wear to swords
if not minetest.setting_getbool("creative_mode") then
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
if self.object:get_hp() < 1 then
local obj = minetest.env:add_item(my_pos, g_drop.." "..math.random(0,3))
end
end
GHOST_DEF.on_step = function(self, dtime)
if self.dead then return end
self.timer = self.timer + 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.attacking_timer = self.attacking_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)
if self.time_passed == nil then
self.time_passed = 0
end
-- death
if self.object:get_hp() < 1 then
--self.object:setvelocity({x=0,y=-20,z=0})
self.object:set_hp(0)
self.attacker = ""
self.state = 0
self.dead = true
minetest.sound_play(g_sound_dead, {pos = current_pos, max_hear_distance = 10 , gain = 0.5})
self.object:set_animation({x=self.anim.lay_START,y=self.anim.lay_END}, g_animation_speed, 0)
minetest.after(1, function()
self.object:remove()
local obj = minetest.env:add_item(current_pos, g_drop.." "..math.random(0,3))
end)
end
-- die when in water, lava or sunlight
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
if current_node.name == "default:water_source" or
current_node.name == "default:water_flowing" or
current_node.name == "default:lava_source" or
current_node.name == "default:lava_flowing" or
(wtime > 0.2 and wtime < 0.805 and current_pos.y > 0 and ll > 11) then
self.sound_timer = self.sound_timer + dtime
if self.sound_timer >= 0.8 then
local damage = 5
if ll > 11 then damage = 2 end
self.sound_timer = 0
self.object:set_hp(self.object:get_hp()-damage)
g_hit(self)
end
else
self.time_passed = 0
end
-- update moving state every 1 or 2 seconds
if self.state < 3 then
if self.timer > 0.2 then
if self.attacker == "" then
self.state = math.random(1,2)
else self.state = 1 end
self.timer = 0
end
end
-- play random sound
if self.sound_timer > math.random(5,35) then
minetest.sound_play(g_sound_normal, {pos = current_pos, max_hear_distance = 10, gain = 0.6})
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*g_chillaxin_speed,y=0,z=self.direction.z*g_chillaxin_speed})
self.state = 2
elseif self.state == 8 then
self.object:setvelocity({x=0,y=0,z=0})
self.state = 1
end
end
end
--STANDING
if self.state == 1 then
self.yawwer = true
self.attacker = ""
-- seach for players
for _,object in ipairs(minetest.env:get_objects_inside_radius(current_pos, g_player_radius)) do
if object:is_player() then
self.yawwer = false
NPC = current_pos
PLAYER = object:getpos()
self.vec = {x=PLAYER.x-NPC.x, y=PLAYER.y-NPC.y, z=PLAYER.z-NPC.z}
self.yaw = math.atan(self.vec.z/self.vec.x)+math.pi^2
if PLAYER.x > NPC.x then
self.yaw = self.yaw + math.pi
end
self.yaw = self.yaw - 2
self.object:setyaw(self.yaw)
self.attacker = object
end
end
if self.attacker == "" and self.turn_timer > math.random(1,4) then
self.yaw = 360 * math.random()
self.object:setyaw(self.yaw)
self.turn_timer = 0
self.direction = {x = math.sin(self.yaw)*-1, y = 0, z = math.cos(self.yaw)}
end
self.object:setvelocity({x=0,y=self.object:getvelocity().y,z=0})
if self.npc_anim ~= ANIM_STAND then
self.anim = g_get_animations()
self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, g_animation_speed, 0)
self.npc_anim = ANIM_STAND
end
if self.attacker ~= "" then
self.direction = {x = math.sin(self.yaw)*-1, y = 0, z = math.cos(self.yaw)}
self.state = 2
end
end
-- WALKING
if self.state == 2 then
if self.direction ~= nil then
self.object:setvelocity({x=self.direction.x*g_chillaxin_speed,y=self.object:getvelocity().y,z=self.direction.z*g_chillaxin_speed})
end
if self.turn_timer > math.random(1,4) and not self.attacker then
self.yaw = 360 * math.random()
self.object:setyaw(self.yaw)
self.turn_timer = 0
self.direction = {x = math.sin(self.yaw)*-1, y = 0, z = math.cos(self.yaw)}
end
if self.npc_anim ~= ANIM_WALK then
self.anim = g_get_animations()
self.object:set_animation({x=self.anim.walk_START,y=self.anim.walk_END}, g_animation_speed, 0)
self.npc_anim = ANIM_WALK
end
--jump
if self.direction ~= nil and self.attacker ~= "" then
if self.jump_timer > 0.1 then
self.jump_timer = 0
local p1 = current_pos
local me_y = math.floor(p1.y)
local p2 = self.attacker:getpos()
local p_y = math.floor(p2.y+3-self.dist)
if me_y < p_y then
self.object:setvelocity({x=self.object:getvelocity().x,y=1*g_chillaxin_speed,z=self.object:getvelocity().z})
elseif me_y > p_y then
self.object:setvelocity({x=self.object:getvelocity().x,y=-1*g_chillaxin_speed,z=self.object:getvelocity().z})
else
self.object:setvelocity({x=self.object:getvelocity().x,y=0,z=self.object:getvelocity().z})
end
end
end
if self.attacker == "" then
self.object:setvelocity({x=self.object:getvelocity().x,y=0,z=self.object:getvelocity().z})
end
if self.attacker ~= "" and minetest.setting_getbool("enable_damage") then
local s = current_pos
local p = self.attacker:getpos()
p.y = p.y+3-self.dist
self.direction = {x = math.sin(self.yaw)*-1, y = 0, z = math.cos(self.yaw)}
if (s ~= nil and p ~= nil) then
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^0.5)^2
if dist < g_hit_radius and self.attacking_timer > 0.6 then
self.attacker:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups = {fleshy=1}
})
self.attacking_timer = 0
end
end
end
end
end
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

12
init.lua Normal file
View File

@ -0,0 +1,12 @@
creatures = {}
function creatures.spawn(pos, number, mob)
print("spawn"..mob)
--log spawning?
for i=1,number do
minetest.env:add_entity(pos, mob)
end
end
dofile(minetest.get_modpath("creatures").."/ghost.lua")
dofile(minetest.get_modpath("creatures").."/zombie.lua")

BIN
models/creatures_ghost.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

5524
models/creatures_mob.x Normal file

File diff suppressed because it is too large Load Diff

BIN
models/creatures_zombie.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 714 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 B

498
zombie.lua Normal file
View File

@ -0,0 +1,498 @@
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_animation_speed = 15
local z_mesh = "creatures_mob.x"
local z_texture = {"creatures_zombie.png"}
local z_hp = 20
local z_drop = "creatures:rotten_flesh"
local z_player_radius = 14
local z_hit_radius = 1.4
local z_ll = 7
local z_sound_normal = "creatures_zombie"
local z_sound_hit = "creatures_zombie_hit"
local z_sound_dead = "creatures_zombie_death"
local z_spawn_nodes = {"default:dirt_with_grass","default:stone","default:dirt","default:desert_sand"}
local z_spawner_range = 17
local z_spawner_max_mobs = 6
local function z_get_animations()
return {
stand_START = 0,
stand_END = 79,
lay_START = 162,
lay_END = 166,
walk_START = 168,
walk_END = 188,
-- not used
sit_START = 81,
sit_END = 160
}
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)
local sound = z_sound_hit
if self.object:get_hp() < 1 then sound = z_sound_dead end
minetest.sound_play(sound, {pos = self.object:getpos(), max_hear_distance = 10, loop = false, gain = 0.4})
prop = {
mesh = z_mesh,
textures = {"creatures_zombie.png^creatures_zombie_hit.png"},
}
self.object:set_properties(prop)
self.can_punch = false
minetest.after(0.4, function()
z_update_visuals_def(self)
end)
end
function z_update_visuals_def(self)
self.can_punch = true
prop = {
mesh = z_mesh,
textures = z_texture,
}
self.object:set_properties(prop)
end
ZOMBIE_DEF = {
physical = true,
collisionbox = {-0.25, -1, -0.3, 0.25, 0.75, 0.3},
visual = "mesh",
visual_size = {x=1, y=1},
mesh = z_mesh,
textures = z_texture,
makes_footstep_sound = true,
npc_anim = 0,
timer = 0,
turn_timer = 0,
vec = 0,
yaw = 0,
yawwer = 0,
state = 1,
can_punch = true,
dead = false,
jump_timer = 0,
last_pos = {x=0,y=0,z=0},
punch_timer = 0,
sound_timer = 0,
attacker = "",
attacking_timer = 0,
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)
z_update_visuals_def(self)
self.anim = z_get_animations()
self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, z_animation_speed, 0)
self.npc_anim = ANIM_STAND
self.object:setacceleration({x=0,y=-20,z=0})
self.state = 1
self.object:set_hp(z_hp)
self.object:set_armor_groups({fleshy=130})
self.last_pos = {x=0,y=0,z=0}
self.can_punch = true
self.dead = false
end
ZOMBIE_DEF.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
if not self.can_punch then return end
local my_pos = self.object:getpos()
if puncher ~= nil then
self.attacker = puncher
if time_from_last_punch >= 0.45 then
z_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*z_chillaxin_speed,y=5,z=dir.z*z_chillaxin_speed})
if self.state == 1 then
self.state = 8
elseif self.state >= 2 then
self.state = 9
end
--add wear to swords
if not minetest.setting_getbool("creative_mode") then
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
if self.object:get_hp() < 1 then
local obj = minetest.env:add_item(my_pos, z_drop.." "..math.random(0,3))
end
end
ZOMBIE_DEF.on_step = function(self, dtime)
if self.dead then return end
self.timer = self.timer + 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.attacking_timer = self.attacking_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)
if self.time_passed == nil then
self.time_passed = 0
end
-- death
if self.object:get_hp() < 1 then
self.object:setvelocity({x=0,y=-20,z=0})
self.object:set_hp(0)
self.attacker = ""
self.state = 0
self.dead = true
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)
minetest.after(1, function()
self.object:remove()
local obj = minetest.env:add_item(current_pos, z_drop.." "..math.random(0,3))
end)
end
-- die when in water, lava or sunlight
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
if current_node.name == "default:water_source" or
current_node.name == "default:water_flowing" or
current_node.name == "default:lava_source" or
current_node.name == "default:lava_flowing" or
(wtime > 0.2 and wtime < 0.805 and current_pos.y > 0 and ll > 11) then
self.sound_timer = self.sound_timer + dtime
if self.sound_timer >= 0.8 then
local damage = 5
if ll > 11 then damage = 2 end
self.sound_timer = 0
self.object:set_hp(self.object:get_hp()-damage)
z_hit(self)
end
else
self.time_passed = 0
end
-- update moving state every 0.5 or 1 second
if self.state < 3 then
if self.timer > 0.2 then
if self.attacker == "" then
self.state = math.random(1,2)
else self.state = 5 end
self.timer = 0
end
end
-- play random sound
if self.sound_timer > math.random(5,35) then
minetest.sound_play(z_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*z_chillaxin_speed,y=-20,z=self.direction.z*z_chillaxin_speed})
self.state = 2
elseif self.state == 8 then
self.object:setvelocity({x=0,y=-20,z=0})
self.state = 1
end
end
end
--STANDING
if self.state == 1 then
self.yawwer = true
self.attacker = ""
-- seach for players
for _,object in ipairs(minetest.env:get_objects_inside_radius(current_pos, z_player_radius)) do
if object:is_player() then
self.yawwer = false
NPC = current_pos
PLAYER = object:getpos()
self.vec = {x=PLAYER.x-NPC.x, y=PLAYER.y-NPC.y, z=PLAYER.z-NPC.z}
self.yaw = math.atan(self.vec.z/self.vec.x)+math.pi^2
if PLAYER.x > NPC.x then
self.yaw = self.yaw + math.pi
end
self.yaw = self.yaw - 2
self.object:setyaw(self.yaw)
self.attacker = object
end
end
if self.attacker == "" and self.turn_timer > math.random(1,4) then--and yawwer == true then
self.yaw = 360 * math.random()
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 ~= ANIM_STAND then
self.anim = z_get_animations()
self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, z_animation_speed, 0)
self.npc_anim = ANIM_STAND
end
if self.attacker ~= "" then
self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
self.state = 2
end
end
--UPDATE DIR
if self.state == 5 then
self.yawwer = true
self.attacker = ""
-- seach for players
for _,object in ipairs(minetest.env:get_objects_inside_radius(current_pos, z_player_radius)) do
if object:is_player() then
self.yawwer = false
NPC = current_pos
PLAYER = object:getpos()
self.vec = {x=PLAYER.x-NPC.x, y=PLAYER.y-NPC.y, z=PLAYER.z-NPC.z}
self.yaw = math.atan(self.vec.z/self.vec.x)+math.pi^2
if PLAYER.x > NPC.x then
self.yaw = self.yaw + math.pi
end
self.yaw = self.yaw - 2
self.object:setyaw(self.yaw)
self.attacker = object
end
end
if self.attacker ~= "" then
self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
self.state = 2
else
self.state =1
end
end
-- WALKING
if self.state == 2 then
if self.attacker ~= "" then
self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
--self.state = 2
end
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})
end
if self.turn_timer > math.random(1,4) and not self.attacker then
self.yaw = 360 * math.random()
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_WALK then
self.npc_anim = 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.npc_anim = ANIM_WALK
end
--jump
if self.direction ~= nil then
if self.jump_timer > 0.3 then
self.jump_timer = 0
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})
--print(n.name)
if n and n.name and minetest.registered_items[n.name].walkable then
self.object:setvelocity({x=self.object:getvelocity().x,y=7,z=self.object:getvelocity().z})
end
--end
end
end
if self.attacker ~= "" and minetest.setting_getbool("enable_damage") then
local s = current_pos
local p = self.attacker:getpos()
if (s ~= nil and p ~= nil) then
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
if dist < z_hit_radius and self.attacking_timer > 0.6 then
self.attacker:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups = {fleshy=1}
})
self.attacking_timer = 0
end
end
end
end
end
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