update mobs mod
fix npc male/female not tamed reduce volume and convert npc female sound move .blend in others_thing chmod 755
@ -28,6 +28,7 @@ This mod contains the following additions:
|
|||||||
|
|
||||||
Changelog:
|
Changelog:
|
||||||
|
|
||||||
|
1.17- Added 'dogshoot' attack type, shoots when out of reach, melee attack when in reach, also api tweaks and self.reach added
|
||||||
1.16- Mobs follow multiple items now, Npc's can breed
|
1.16- Mobs follow multiple items now, Npc's can breed
|
||||||
1.15- Added Feeding/Taming/Breeding function, right-click to pick up any sheep with X mark on them and replace with new one to fix compatibility.
|
1.15- Added Feeding/Taming/Breeding function, right-click to pick up any sheep with X mark on them and replace with new one to fix compatibility.
|
||||||
1.14- All .self variables saved in staticdata, Fixed self.health bug
|
1.14- All .self variables saved in staticdata, Fixed self.health bug
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
-- Mobs Api (17th September 2015)
|
-- Mobs Api (27th September 2015)
|
||||||
mobs = {}
|
mobs = {}
|
||||||
mobs.mod = "redo"
|
mobs.mod = "redo"
|
||||||
|
|
||||||
@ -10,7 +10,8 @@ mobs.protected = tonumber(minetest.setting_get("mobs_spawn_protected")) or 1
|
|||||||
mobs.remove = minetest.setting_getbool("remove_far_mobs")
|
mobs.remove = minetest.setting_getbool("remove_far_mobs")
|
||||||
|
|
||||||
function mobs:register_mob(name, def)
|
function mobs:register_mob(name, def)
|
||||||
minetest.register_entity(name, {
|
|
||||||
|
minetest.register_entity(name, {
|
||||||
stepheight = def.stepheight or 0.6,
|
stepheight = def.stepheight or 0.6,
|
||||||
name = name,
|
name = name,
|
||||||
fly = def.fly,
|
fly = def.fly,
|
||||||
@ -34,7 +35,7 @@ function mobs:register_mob(name, def)
|
|||||||
view_range = def.view_range or 5,
|
view_range = def.view_range or 5,
|
||||||
walk_velocity = def.walk_velocity or 1,
|
walk_velocity = def.walk_velocity or 1,
|
||||||
run_velocity = def.run_velocity or 2,
|
run_velocity = def.run_velocity or 2,
|
||||||
damage = def.damage,
|
damage = def.damage or 0,
|
||||||
light_damage = def.light_damage or 0,
|
light_damage = def.light_damage or 0,
|
||||||
water_damage = def.water_damage or 0,
|
water_damage = def.water_damage or 0,
|
||||||
lava_damage = def.lava_damage or 0,
|
lava_damage = def.lava_damage or 0,
|
||||||
@ -49,7 +50,7 @@ function mobs:register_mob(name, def)
|
|||||||
shoot_interval = def.shoot_interval,
|
shoot_interval = def.shoot_interval,
|
||||||
sounds = def.sounds or {},
|
sounds = def.sounds or {},
|
||||||
animation = def.animation,
|
animation = def.animation,
|
||||||
follow = def.follow, -- or "",
|
follow = def.follow,
|
||||||
jump = def.jump or true,
|
jump = def.jump or true,
|
||||||
walk_chance = def.walk_chance or 50,
|
walk_chance = def.walk_chance or 50,
|
||||||
attacks_monsters = def.attacks_monsters or false,
|
attacks_monsters = def.attacks_monsters or false,
|
||||||
@ -67,7 +68,7 @@ function mobs:register_mob(name, def)
|
|||||||
replace_with = def.replace_with,
|
replace_with = def.replace_with,
|
||||||
replace_offset = def.replace_offset or 0,
|
replace_offset = def.replace_offset or 0,
|
||||||
timer = 0,
|
timer = 0,
|
||||||
env_damage_timer = 0, -- only if state = "attack"
|
env_damage_timer = 0, -- only used when state = "attack"
|
||||||
attack = {player = nil, dist = nil},
|
attack = {player = nil, dist = nil},
|
||||||
state = "stand",
|
state = "stand",
|
||||||
tamed = false,
|
tamed = false,
|
||||||
@ -77,8 +78,10 @@ function mobs:register_mob(name, def)
|
|||||||
child = false,
|
child = false,
|
||||||
gotten = false,
|
gotten = false,
|
||||||
health = 0,
|
health = 0,
|
||||||
|
reach = def.reach or 3,
|
||||||
|
htimer = 0,
|
||||||
|
|
||||||
do_attack = function(self, player, dist)
|
do_attack = function(self, player)
|
||||||
if self.state ~= "attack" then
|
if self.state ~= "attack" then
|
||||||
if math.random(0,100) < 90
|
if math.random(0,100) < 90
|
||||||
and self.sounds.war_cry then
|
and self.sounds.war_cry then
|
||||||
@ -88,8 +91,7 @@ function mobs:register_mob(name, def)
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
self.state = "attack"
|
self.state = "attack"
|
||||||
self.attack.player = player
|
self.attack = player
|
||||||
self.attack.dist = dist
|
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
@ -102,7 +104,11 @@ function mobs:register_mob(name, def)
|
|||||||
local yaw = self.object:getyaw() + self.rotate
|
local yaw = self.object:getyaw() + self.rotate
|
||||||
local x = math.sin(yaw) * -v
|
local x = math.sin(yaw) * -v
|
||||||
local z = math.cos(yaw) * v
|
local z = math.cos(yaw) * v
|
||||||
self.object:setvelocity({x = x, y = self.object:getvelocity().y, z = z})
|
self.object:setvelocity({
|
||||||
|
x = x,
|
||||||
|
y = self.object:getvelocity().y,
|
||||||
|
z = z}
|
||||||
|
)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
get_velocity = function(self)
|
get_velocity = function(self)
|
||||||
@ -120,7 +126,6 @@ function mobs:register_mob(name, def)
|
|||||||
local d = {x = vx / ds, z = vz / ds}
|
local d = {x = vx / ds, z = vz / ds}
|
||||||
local p = {x = pos.x / ps, z = pos.z / ps}
|
local p = {x = pos.x / ps, z = pos.z / ps}
|
||||||
local an = (d.x * p.x) + (d.z * p.z)
|
local an = (d.x * p.x) + (d.z * p.z)
|
||||||
|
|
||||||
if math.deg(math.acos(an)) > (self.fov / 2) then
|
if math.deg(math.acos(an)) > (self.fov / 2) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@ -183,13 +188,14 @@ function mobs:register_mob(name, def)
|
|||||||
|
|
||||||
on_step = function(self, dtime)
|
on_step = function(self, dtime)
|
||||||
|
|
||||||
|
-- remove monsters if playing on peaceful
|
||||||
if (self.type == "monster" and peaceful_only)
|
if (self.type == "monster" and peaceful_only)
|
||||||
or not within_limits(self.object:getpos(), 0) then
|
or not within_limits(self.object:getpos(), 0) then
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- if lifetimer run out and not npc; tamed or attacking then remove mob
|
-- when lifetimer expires remove mob (except npc and tamed)
|
||||||
if self.type ~= "npc"
|
if self.type ~= "npc"
|
||||||
and not self.tamed then
|
and not self.tamed then
|
||||||
self.lifetimer = self.lifetimer - dtime
|
self.lifetimer = self.lifetimer - dtime
|
||||||
@ -203,10 +209,10 @@ function mobs:register_mob(name, def)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- check for mob drop/replace (used for chicken egg and sheep eating grass/wheat)
|
-- node replace check (chicken lays egg, cow eats grass etc)
|
||||||
if self.replace_rate
|
if self.replace_rate
|
||||||
and self.child == false
|
and self.child == false
|
||||||
and math.random(1,self.replace_rate) == 1 then
|
and math.random(1, self.replace_rate) == 1 then
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:getpos()
|
||||||
local nodeunder = minetest.get_node_or_nil({x=pos.x, y=pos.y-1, z=pos.z}) --MFF (Mg egg not in air)
|
local nodeunder = minetest.get_node_or_nil({x=pos.x, y=pos.y-1, z=pos.z}) --MFF (Mg egg not in air)
|
||||||
pos.y = pos.y + self.replace_offset
|
pos.y = pos.y + self.replace_offset
|
||||||
@ -215,7 +221,6 @@ function mobs:register_mob(name, def)
|
|||||||
and self.object:getvelocity().y == 0
|
and self.object:getvelocity().y == 0
|
||||||
and #minetest.find_nodes_in_area(pos, pos, self.replace_what) > 0 --then
|
and #minetest.find_nodes_in_area(pos, pos, self.replace_what) > 0 --then
|
||||||
and nodeunder and nodeunder.name ~= "air" then --MFF (Mg egg not in air)
|
and nodeunder and nodeunder.name ~= "air" then --MFF (Mg egg not in air)
|
||||||
--and self.state == "stand" then
|
|
||||||
minetest.set_node(pos, {name = self.replace_with})
|
minetest.set_node(pos, {name = self.replace_with})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -225,14 +230,9 @@ function mobs:register_mob(name, def)
|
|||||||
if not self.fly then
|
if not self.fly then
|
||||||
-- floating in water (or falling)
|
-- floating in water (or falling)
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:getpos()
|
||||||
local nod = minetest.get_node_or_nil(pos)
|
|
||||||
if nod then nod = nod.name else nod = "default:dirt" end
|
|
||||||
local nodef = minetest.registered_nodes[nod]
|
|
||||||
if not nodef then
|
|
||||||
nodef = {groups = {}}
|
|
||||||
end
|
|
||||||
|
|
||||||
local v = self.object:getvelocity()
|
local v = self.object:getvelocity()
|
||||||
|
|
||||||
|
-- going up then apply gravity
|
||||||
if v.y > 0.1 then
|
if v.y > 0.1 then
|
||||||
self.object:setacceleration({
|
self.object:setacceleration({
|
||||||
x = 0,
|
x = 0,
|
||||||
@ -240,7 +240,9 @@ function mobs:register_mob(name, def)
|
|||||||
z = 0
|
z = 0
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
if nodef.groups.water then
|
|
||||||
|
-- in water then float up
|
||||||
|
if minetest.registered_nodes[node_ok(pos).name].groups.water then
|
||||||
if self.floats == 1 then
|
if self.floats == 1 then
|
||||||
self.object:setacceleration({
|
self.object:setacceleration({
|
||||||
x = 0,
|
x = 0,
|
||||||
@ -249,6 +251,7 @@ function mobs:register_mob(name, def)
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
-- fall downwards
|
||||||
self.object:setacceleration({
|
self.object:setacceleration({
|
||||||
x = 0,
|
x = 0,
|
||||||
y = self.fall_speed,
|
y = self.fall_speed,
|
||||||
@ -287,6 +290,7 @@ function mobs:register_mob(name, def)
|
|||||||
self.timer = 0
|
self.timer = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- mob plays random sound at times
|
||||||
if self.sounds.random
|
if self.sounds.random
|
||||||
and math.random(1, 100) <= 1 then
|
and math.random(1, 100) <= 1 then
|
||||||
minetest.sound_play(self.sounds.random, {
|
minetest.sound_play(self.sounds.random, {
|
||||||
@ -296,7 +300,9 @@ function mobs:register_mob(name, def)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local do_env_damage = function(self)
|
local do_env_damage = function(self)
|
||||||
|
if self.htimer > 0 then
|
||||||
|
self.htimer = self.htimer - 1
|
||||||
|
end
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:getpos()
|
||||||
local tod = minetest.get_timeofday()
|
local tod = minetest.get_timeofday()
|
||||||
|
|
||||||
@ -311,9 +317,9 @@ function mobs:register_mob(name, def)
|
|||||||
if check_for_death(self) then return end
|
if check_for_death(self) then return end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.water_damage ~= 0 or self.lava_damage ~= 0 then
|
||||||
pos.y = pos.y + self.collisionbox[2] -- foot level
|
pos.y = pos.y + self.collisionbox[2] -- foot level
|
||||||
local nod = minetest.get_node_or_nil(pos)
|
local nod = node_ok(pos, "air") -- print ("standing in "..nod.name)
|
||||||
if not nod then return end ; -- print ("standing in "..nod.name)
|
|
||||||
local nodef = minetest.registered_nodes[nod.name]
|
local nodef = minetest.registered_nodes[nod.name]
|
||||||
if not nodef then return end
|
if not nodef then return end
|
||||||
pos.y = pos.y + 1
|
pos.y = pos.y + 1
|
||||||
@ -330,12 +336,13 @@ function mobs:register_mob(name, def)
|
|||||||
if self.lava_damage ~= 0
|
if self.lava_damage ~= 0
|
||||||
and (nodef.groups.lava
|
and (nodef.groups.lava
|
||||||
or nod.name == "fire:basic_flame"
|
or nod.name == "fire:basic_flame"
|
||||||
or nod.name == "xanadu:safe_fire") then
|
or nod.name == "xanadu:safe_fire"
|
||||||
|
or nod.name == "fire:eternal_flame") then
|
||||||
self.object:set_hp(self.object:get_hp() - self.lava_damage)
|
self.object:set_hp(self.object:get_hp() - self.lava_damage)
|
||||||
effect(pos, 5, "fire_basic_flame.png")
|
effect(pos, 5, "fire_basic_flame.png")
|
||||||
if check_for_death(self) then return end
|
if check_for_death(self) then return end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local do_jump = function(self)
|
local do_jump = function(self)
|
||||||
@ -343,32 +350,24 @@ function mobs:register_mob(name, def)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
self.jumptimer = (self.jumptimer or 0) + 1
|
|
||||||
if self.jumptimer < 3 then
|
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:getpos()
|
||||||
pos.y = (pos.y + self.collisionbox[2]) - 0.2
|
pos.y = (pos.y + self.collisionbox[2]) - 0.2
|
||||||
local nod = minetest.get_node_or_nil(pos)
|
local nod = node_ok(pos)
|
||||||
--print ("standing on:", nod.name, pos.y)
|
--print ("standing on:", nod.name, pos.y)
|
||||||
if not nod
|
if minetest.registered_nodes[nod.name].walkable == false then
|
||||||
or not minetest.registered_nodes[nod.name]
|
|
||||||
or minetest.registered_nodes[nod.name].walkable == false then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if self.direction then
|
if self.direction then
|
||||||
pos.y = pos.y + 0.5
|
pos.y = pos.y + 0.5
|
||||||
local nod = minetest.get_node_or_nil({
|
local nod = node_ok({
|
||||||
x = pos.x + self.direction.x,
|
x = pos.x + self.direction.x,
|
||||||
y = pos.y,
|
y = pos.y,
|
||||||
z = pos.z + self.direction.z
|
z = pos.z + self.direction.z
|
||||||
})
|
})
|
||||||
--print ("in front:", nod.name, pos.y)
|
--print ("in front:", nod.name, pos.y)
|
||||||
if nod and nod.name and
|
if nod.name ~= "air"
|
||||||
(nod.name ~= "air"
|
and minetest.registered_items[nod.name].walkable
|
||||||
or self.walk_chance == 0) then
|
and not nod.name:find("fence")
|
||||||
local def = minetest.registered_items[nod.name]
|
|
||||||
if (def
|
|
||||||
and def.walkable
|
|
||||||
and not nod.name:find("fence"))
|
|
||||||
or self.walk_chance == 0 then
|
or self.walk_chance == 0 then
|
||||||
local v = self.object:getvelocity()
|
local v = self.object:getvelocity()
|
||||||
v.y = self.jump_height + 1
|
v.y = self.jump_height + 1
|
||||||
@ -384,10 +383,6 @@ function mobs:register_mob(name, def)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
|
||||||
self.jumptimer = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- environmental damage timer (every 1 second)
|
-- environmental damage timer (every 1 second)
|
||||||
self.env_damage_timer = self.env_damage_timer + dtime
|
self.env_damage_timer = self.env_damage_timer + dtime
|
||||||
@ -454,7 +449,7 @@ function mobs:register_mob(name, def)
|
|||||||
end
|
end
|
||||||
-- attack player
|
-- attack player
|
||||||
if min_player then
|
if min_player then
|
||||||
self.do_attack(self, min_player, min_dist)
|
self.do_attack(self, min_player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -482,11 +477,12 @@ function mobs:register_mob(name, def)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if min_player then
|
if min_player then
|
||||||
self.do_attack(self, min_player, min_dist)
|
self.do_attack(self, min_player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- horny animal can mate for 40 seconds, afterwards horny animal cannot mate again for 200 seconds
|
-- horny animal can mate for 40 seconds,
|
||||||
|
-- afterwards horny animal cannot mate again for 200 seconds
|
||||||
if self.horny == true
|
if self.horny == true
|
||||||
and self.hornytimer < 240
|
and self.hornytimer < 240
|
||||||
and self.child == false then
|
and self.child == false then
|
||||||
@ -497,7 +493,7 @@ function mobs:register_mob(name, def)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- if animal is child take 240 seconds before growing into adult
|
-- child take 240 seconds before growing into adult
|
||||||
if self.child == true then
|
if self.child == true then
|
||||||
self.hornytimer = self.hornytimer + 1
|
self.hornytimer = self.hornytimer + 1
|
||||||
if self.hornytimer > 240 then
|
if self.hornytimer > 240 then
|
||||||
@ -509,7 +505,7 @@ function mobs:register_mob(name, def)
|
|||||||
visual_size = self.base_size,
|
visual_size = self.base_size,
|
||||||
collisionbox = self.base_colbox,
|
collisionbox = self.base_colbox,
|
||||||
})
|
})
|
||||||
-- jump when grown to now fall into ground
|
-- jump when grown so not to fall into ground
|
||||||
local v = self.object:getvelocity()
|
local v = self.object:getvelocity()
|
||||||
v.y = self.jump_height
|
v.y = self.jump_height
|
||||||
v.x = 0 ; v.z = 0
|
v.x = 0 ; v.z = 0
|
||||||
@ -517,7 +513,7 @@ function mobs:register_mob(name, def)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- if animal is horny, find another same animal who is horny and mate
|
-- find another same animal who is also horny and mate
|
||||||
if self.horny == true
|
if self.horny == true
|
||||||
and self.hornytimer <= 40 then
|
and self.hornytimer <= 40 then
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:getpos()
|
||||||
@ -552,6 +548,8 @@ function mobs:register_mob(name, def)
|
|||||||
and ent.hornytimer <= 40 then
|
and ent.hornytimer <= 40 then
|
||||||
num = num + 1
|
num = num + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- found your mate? then have a baby
|
||||||
if num > 1 then
|
if num > 1 then
|
||||||
self.hornytimer = 41
|
self.hornytimer = 41
|
||||||
ent.hornytimer = 41
|
ent.hornytimer = 41
|
||||||
@ -618,13 +616,12 @@ function mobs:register_mob(name, def)
|
|||||||
-- stop following player if not holding specific item
|
-- stop following player if not holding specific item
|
||||||
if self.following
|
if self.following
|
||||||
and self.following.is_player
|
and self.following.is_player
|
||||||
--and self.following:get_wielded_item():get_name() ~= self.follow then
|
|
||||||
and follow_holding(self, self.following) == false then
|
and follow_holding(self, self.following) == false then
|
||||||
self.following = nil
|
self.following = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- follow player or mob
|
-- follow that thing
|
||||||
if self.following then
|
if self.following then
|
||||||
local s = self.object:getpos()
|
local s = self.object:getpos()
|
||||||
local p
|
local p
|
||||||
@ -638,6 +635,8 @@ function mobs:register_mob(name, def)
|
|||||||
|
|
||||||
if p then
|
if p then
|
||||||
local dist = ((p.x - s.x) ^ 2 + (p.y - s.y) ^ 2 + (p.z - s.z) ^ 2) ^ 0.5
|
local dist = ((p.x - s.x) ^ 2 + (p.y - s.y) ^ 2 + (p.z - s.z) ^ 2) ^ 0.5
|
||||||
|
|
||||||
|
-- dont follow if out of range
|
||||||
if dist > self.view_range then
|
if dist > self.view_range then
|
||||||
self.following = nil
|
self.following = nil
|
||||||
else
|
else
|
||||||
@ -649,7 +648,7 @@ function mobs:register_mob(name, def)
|
|||||||
self.object:setyaw(yaw)
|
self.object:setyaw(yaw)
|
||||||
|
|
||||||
-- anyone but standing npc's can move along
|
-- anyone but standing npc's can move along
|
||||||
if dist > 4 --/MFF (Crabman|07/14/2015) follow but at distance, default value is 2
|
if dist > self.reach
|
||||||
and self.order ~= "stand" then
|
and self.order ~= "stand" then
|
||||||
if (self.jump
|
if (self.jump
|
||||||
and self.get_velocity(self) <= 0.5
|
and self.get_velocity(self) <= 0.5
|
||||||
@ -658,7 +657,7 @@ function mobs:register_mob(name, def)
|
|||||||
and self.jump_chance > 0) then
|
and self.jump_chance > 0) then
|
||||||
self.direction = {
|
self.direction = {
|
||||||
x = math.sin(yaw) * -1,
|
x = math.sin(yaw) * -1,
|
||||||
y = -20,
|
y = 0,
|
||||||
z = math.cos(yaw)
|
z = math.cos(yaw)
|
||||||
}
|
}
|
||||||
do_jump(self)
|
do_jump(self)
|
||||||
@ -677,15 +676,13 @@ function mobs:register_mob(name, def)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if self.state == "stand" then
|
if self.state == "stand" then
|
||||||
-- randomly turn
|
|
||||||
if math.random(1, 4) == 1 then
|
if math.random(1, 4) == 1 then
|
||||||
-- if there is a player nearby look at them
|
|
||||||
local lp = nil
|
local lp = nil
|
||||||
local s = self.object:getpos()
|
local s = self.object:getpos()
|
||||||
|
|
||||||
if self.type == "npc" then
|
if self.type == "npc" then
|
||||||
local o = minetest.get_objects_inside_radius(self.object:getpos(), 3)
|
local o = minetest.get_objects_inside_radius(self.object:getpos(), 3)
|
||||||
|
|
||||||
local yaw = 0
|
local yaw = 0
|
||||||
for _,o in ipairs(o) do
|
for _,o in ipairs(o) do
|
||||||
if o:is_player() then
|
if o:is_player() then
|
||||||
@ -695,6 +692,7 @@ function mobs:register_mob(name, def)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- look at any players nearby, otherwise turn randomly
|
||||||
if lp ~= nil then
|
if lp ~= nil then
|
||||||
local vec = {x = lp.x - s.x, y = lp.y - s.y, z = lp.z - s.z}
|
local vec = {x = lp.x - s.x, y = lp.y - s.y, z = lp.z - s.z}
|
||||||
yaw = (math.atan(vec.z / vec.x) + math.pi / 2) - self.rotate
|
yaw = (math.atan(vec.z / vec.x) + math.pi / 2) - self.rotate
|
||||||
@ -723,29 +721,24 @@ function mobs:register_mob(name, def)
|
|||||||
self.state = "walk"
|
self.state = "walk"
|
||||||
self.set_animation(self, "walk")
|
self.set_animation(self, "walk")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- jumping mobs only
|
|
||||||
-- if self.jump and math.random(1, 100) <= self.jump_chance then
|
|
||||||
-- self.direction = {x = 0, y = 0, z = 0}
|
|
||||||
-- do_jump(self)
|
|
||||||
-- self.set_velocity(self, self.walk_velocity)
|
|
||||||
-- end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif self.state == "walk" then
|
elseif self.state == "walk" then
|
||||||
local s = self.object:getpos()
|
local s = self.object:getpos()
|
||||||
local lp = minetest.find_node_near(s, 1, {"group:water"})
|
local lp = minetest.find_node_near(s, 1, {"group:water"})
|
||||||
|
|
||||||
-- water swimmers cannot move out of water
|
-- water swimmers cannot move out of water
|
||||||
if self.fly
|
if self.fly
|
||||||
and self.fly_in == "default:water_source"
|
and self.fly_in == "default:water_source"
|
||||||
and not lp then
|
and not lp then
|
||||||
print ("out of water")
|
print ("out of water")
|
||||||
self.set_velocity(self, 0)
|
self.set_velocity(self, 0)
|
||||||
self.state = "flop" -- change to undefined state so nothing more happens
|
-- change to undefined state so nothing more happens
|
||||||
|
self.state = "flop"
|
||||||
self:set_animation("stand")
|
self:set_animation("stand")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- if water nearby then turn away
|
-- if water nearby then turn away
|
||||||
if lp then
|
if lp then
|
||||||
local vec = {x = lp.x - s.x, y = lp.y - s.y, z = lp.z - s.z}
|
local vec = {x = lp.x - s.x, y = lp.y - s.y, z = lp.z - s.z}
|
||||||
@ -754,16 +747,17 @@ end
|
|||||||
yaw = yaw + math.pi
|
yaw = yaw + math.pi
|
||||||
end
|
end
|
||||||
self.object:setyaw(yaw)
|
self.object:setyaw(yaw)
|
||||||
|
|
||||||
-- otherwise randomly turn
|
-- otherwise randomly turn
|
||||||
elseif math.random(1, 100) <= 30 then
|
elseif math.random(1, 100) <= 30 then
|
||||||
self.object:setyaw(self.object:getyaw() + ((math.random(0, 360) - 180) / 180 * math.pi))
|
self.object:setyaw(self.object:getyaw() + ((math.random(0, 360) - 180) / 180 * math.pi))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- jump when walking comes to a halt
|
||||||
if self.jump and self.get_velocity(self) <= 0.5
|
if self.jump and self.get_velocity(self) <= 0.5
|
||||||
and self.object:getvelocity().y == 0 then
|
and self.object:getvelocity().y == 0 then
|
||||||
self.direction = {
|
self.direction = {
|
||||||
x = math.sin(yaw) * -1,
|
x = math.sin(yaw) * -1,
|
||||||
y = -20,
|
y = 0,
|
||||||
z = math.cos(yaw)
|
z = math.cos(yaw)
|
||||||
}
|
}
|
||||||
do_jump(self)
|
do_jump(self)
|
||||||
@ -777,40 +771,40 @@ end
|
|||||||
self:set_animation("stand")
|
self:set_animation("stand")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- exploding mobs
|
-- attack routines (explode, dogfight, shoot, dogshoot)
|
||||||
elseif self.state == "attack" and self.attack_type == "explode" then
|
elseif self.state == "attack" then
|
||||||
if not self.attack.player
|
|
||||||
or not self.attack.player:is_player() then
|
-- calculate distance from mob and enemy
|
||||||
self.state = "stand"
|
|
||||||
self:set_animation("stand")
|
|
||||||
self.timer = 0
|
|
||||||
self.blinktimer = 0
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local s = self.object:getpos()
|
local s = self.object:getpos()
|
||||||
local p = self.attack.player:getpos()
|
local p = self.attack:getpos() or s
|
||||||
local dist = ((p.x - s.x) ^ 2 + (p.y - s.y) ^ 2 + (p.z - s.z) ^ 2) ^ 0.5
|
local dist = ((p.x - s.x) ^ 2 + (p.y - s.y) ^ 2 + (p.z - s.z) ^ 2) ^ 0.5
|
||||||
if dist > self.view_range or self.attack.player:get_hp() <= 0 then
|
|
||||||
|
-- stop attacking if no player or out of range
|
||||||
|
if dist > self.view_range
|
||||||
|
or not self.attack
|
||||||
|
or not self.attack:getpos()
|
||||||
|
or self.attack:get_hp() <= 0 then
|
||||||
|
--print(" ** stop attacking **", dist, self.view_range)
|
||||||
self.state = "stand"
|
self.state = "stand"
|
||||||
self.v_start = false
|
|
||||||
self.set_velocity(self, 0)
|
self.set_velocity(self, 0)
|
||||||
|
self:set_animation("stand")
|
||||||
|
self.attack = nil
|
||||||
|
self.v_start = false
|
||||||
self.timer = 0
|
self.timer = 0
|
||||||
self.blinktimer = 0
|
self.blinktimer = 0
|
||||||
self.attack = {player = nil, dist = nil}
|
|
||||||
self:set_animation("stand")
|
|
||||||
return
|
return
|
||||||
else
|
|
||||||
self:set_animation("walk")
|
|
||||||
self.attack.dist = dist
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.attack_type == "explode" then
|
||||||
|
|
||||||
local vec = {x = p.x - s.x, y = p.y - s.y, z = p.z - s.z}
|
local vec = {x = p.x - s.x, y = p.y - s.y, z = p.z - s.z}
|
||||||
yaw = math.atan(vec.z / vec.x) + math.pi / 2 - self.rotate
|
yaw = math.atan(vec.z / vec.x) + math.pi / 2 - self.rotate
|
||||||
if p.x > s.x then
|
if p.x > s.x then
|
||||||
yaw = yaw + math.pi
|
yaw = yaw + math.pi
|
||||||
end
|
end
|
||||||
self.object:setyaw(yaw)
|
self.object:setyaw(yaw)
|
||||||
if self.attack.dist > 3 then
|
|
||||||
|
if dist > self.reach then
|
||||||
if not self.v_start then
|
if not self.v_start then
|
||||||
self.v_start = true
|
self.v_start = true
|
||||||
self.set_velocity(self, self.run_velocity)
|
self.set_velocity(self, self.run_velocity)
|
||||||
@ -843,6 +837,7 @@ end
|
|||||||
end
|
end
|
||||||
if self.timer > 3 then
|
if self.timer > 3 then
|
||||||
local pos = vector.round(self.object:getpos())
|
local pos = vector.round(self.object:getpos())
|
||||||
|
-- hurt player/mobs caught in blast area
|
||||||
entity_physics(pos, 3, self) -- hurt player/mobs caught in blast area --/MFF (Crabman|06/23/2015)add self to use punch function
|
entity_physics(pos, 3, self) -- hurt player/mobs caught in blast area --/MFF (Crabman|06/23/2015)add self to use punch function
|
||||||
if minetest.find_node_near(pos, 1, {"group:water"})
|
if minetest.find_node_near(pos, 1, {"group:water"})
|
||||||
or minetest.is_protected(pos, "") then
|
or minetest.is_protected(pos, "") then
|
||||||
@ -862,26 +857,15 @@ end
|
|||||||
mobs:explosion(pos, 2, 0, 1, self.sounds.explode)
|
mobs:explosion(pos, 2, 0, 1, self.sounds.explode)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- end of exploding mobs
|
|
||||||
|
|
||||||
elseif self.state == "attack"
|
elseif self.attack_type == "dogfight"
|
||||||
and self.attack_type == "dogfight" then
|
or (self.attack_type == "dogshoot" and dist <= self.reach) then
|
||||||
if not self.attack.player
|
|
||||||
or not self.attack.player:getpos() then
|
|
||||||
print("stop attacking")
|
|
||||||
self.state = "stand"
|
|
||||||
self:set_animation("stand")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local s = self.object:getpos()
|
|
||||||
local p = self.attack.player:getpos()
|
|
||||||
local dist = ((p.x - s.x) ^ 2 + (p.y - s.y) ^ 2 + (p.z - s.z) ^ 2) ^ 0.5
|
|
||||||
|
|
||||||
-- fly bit modified from BlockMens creatures mod
|
-- fly bit modified from BlockMens creatures mod
|
||||||
if self.fly
|
if self.fly
|
||||||
and dist > 2 then
|
and dist > self.reach then
|
||||||
|
|
||||||
local nod = minetest.get_node_or_nil(s)
|
local nod = node_ok(s)
|
||||||
local p1 = s
|
local p1 = s
|
||||||
local me_y = math.floor(p1.y)
|
local me_y = math.floor(p1.y)
|
||||||
local p2 = p
|
local p2 = p
|
||||||
@ -921,16 +905,6 @@ end
|
|||||||
end
|
end
|
||||||
-- end fly bit
|
-- end fly bit
|
||||||
|
|
||||||
if dist > self.view_range
|
|
||||||
or self.attack.player:get_hp() <= 0 then
|
|
||||||
self.state = "stand"
|
|
||||||
self.set_velocity(self, 0)
|
|
||||||
self.attack = {player = nil, dist = nil}
|
|
||||||
self:set_animation("stand")
|
|
||||||
return
|
|
||||||
else
|
|
||||||
self.attack.dist = dist
|
|
||||||
end
|
|
||||||
|
|
||||||
local vec = {x = p.x - s.x, y = p.y - s.y, z = p.z - s.z}
|
local vec = {x = p.x - s.x, y = p.y - s.y, z = p.z - s.z}
|
||||||
yaw = (math.atan(vec.z / vec.x) + math.pi / 2) - self.rotate
|
yaw = (math.atan(vec.z / vec.x) + math.pi / 2) - self.rotate
|
||||||
@ -938,8 +912,11 @@ end
|
|||||||
yaw = yaw + math.pi
|
yaw = yaw + math.pi
|
||||||
end
|
end
|
||||||
self.object:setyaw(yaw)
|
self.object:setyaw(yaw)
|
||||||
-- attack distance is 2 + half of mob width so the bigger mobs can attack (like slimes)
|
|
||||||
if self.attack.dist > ((-self.collisionbox[1] + self.collisionbox[4]) / 2) + 2 then
|
-- move towards enemy if beyond mob reach
|
||||||
|
-- set reach for each mob (default is 3)
|
||||||
|
if dist > self.reach then
|
||||||
|
|
||||||
-- jump attack
|
-- jump attack
|
||||||
if (self.jump
|
if (self.jump
|
||||||
and self.get_velocity(self) <= 0.5
|
and self.get_velocity(self) <= 0.5
|
||||||
@ -948,7 +925,7 @@ end
|
|||||||
and self.jump_chance > 0) then
|
and self.jump_chance > 0) then
|
||||||
self.direction = {
|
self.direction = {
|
||||||
x = math.sin(yaw) * -1,
|
x = math.sin(yaw) * -1,
|
||||||
y = -20,
|
y = 0,
|
||||||
z = math.cos(yaw)
|
z = math.cos(yaw)
|
||||||
}
|
}
|
||||||
do_jump(self)
|
do_jump(self)
|
||||||
@ -965,45 +942,28 @@ end
|
|||||||
p2.y = p2.y + 1.5
|
p2.y = p2.y + 1.5
|
||||||
s2.y = s2.y + 1.5
|
s2.y = s2.y + 1.5
|
||||||
if minetest.line_of_sight(p2, s2) == true then
|
if minetest.line_of_sight(p2, s2) == true then
|
||||||
|
-- play attack sound
|
||||||
if self.sounds.attack then
|
if self.sounds.attack then
|
||||||
minetest.sound_play(self.sounds.attack, {
|
minetest.sound_play(self.sounds.attack, {
|
||||||
object = self.object,
|
object = self.object,
|
||||||
max_hear_distance = self.sounds.distance
|
max_hear_distance = self.sounds.distance
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
self.attack.player:punch(self.object, 1.0, {
|
-- punch player
|
||||||
|
self.attack:punch(self.object, 1.0, {
|
||||||
full_punch_interval=1.0,
|
full_punch_interval=1.0,
|
||||||
damage_groups = {fleshy=self.damage}
|
damage_groups = {fleshy=self.damage}
|
||||||
}, vec)
|
}, nil)
|
||||||
if self.attack.player:get_hp() <= 0 then
|
|
||||||
self.state = "stand"
|
|
||||||
self:set_animation("stand")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif self.state == "attack"
|
elseif self.attack_type == "shoot"
|
||||||
and self.attack_type == "shoot" then
|
or (self.attack_type == "dogshoot" and dist > self.reach) then
|
||||||
|
|
||||||
local s = self.object:getpos()
|
|
||||||
local p = self.attack.player:getpos()
|
|
||||||
if not p then
|
|
||||||
self.state = "stand"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
p.y = p.y - .5
|
p.y = p.y - .5
|
||||||
s.y = s.y + .5
|
s.y = s.y + .5
|
||||||
local dist = ((p.x - s.x) ^ 2 + (p.y - s.y) ^ 2 + (p.z - s.z) ^ 2) ^ 0.5
|
local dist = ((p.x - s.x) ^ 2 + (p.y - s.y) ^ 2 + (p.z - s.z) ^ 2) ^ 0.5
|
||||||
if dist > self.view_range
|
|
||||||
or self.attack.player:get_hp() <= 0 then
|
|
||||||
self.state = "stand"
|
|
||||||
self.set_velocity(self, 0)
|
|
||||||
self:set_animation("stand")
|
|
||||||
return
|
|
||||||
else
|
|
||||||
self.attack.dist = dist
|
|
||||||
end
|
|
||||||
|
|
||||||
local vec = {x = p.x - s.x, y = p.y - s.y, z = p.z - s.z}
|
local vec = {x = p.x - s.x, y = p.y - s.y, z = p.z - s.z}
|
||||||
yaw = (math.atan(vec.z / vec.x) + math.pi / 2) - self.rotate
|
yaw = (math.atan(vec.z / vec.x) + math.pi / 2) - self.rotate
|
||||||
@ -1017,11 +977,11 @@ end
|
|||||||
and self.timer > self.shoot_interval
|
and self.timer > self.shoot_interval
|
||||||
and math.random(1, 100) <= 60 then
|
and math.random(1, 100) <= 60 then
|
||||||
self.timer = 0
|
self.timer = 0
|
||||||
|
|
||||||
self:set_animation("punch")
|
self:set_animation("punch")
|
||||||
|
|
||||||
if self.sounds.attack then
|
-- play shoot attack sound
|
||||||
minetest.sound_play(self.sounds.attack, {
|
if self.sounds.shoot_attack then
|
||||||
|
minetest.sound_play(self.sounds.shoot_attack, {
|
||||||
object = self.object,
|
object = self.object,
|
||||||
max_hear_distance = self.sounds.distance
|
max_hear_distance = self.sounds.distance
|
||||||
})
|
})
|
||||||
@ -1032,13 +992,16 @@ end
|
|||||||
local obj = minetest.add_entity(p, self.arrow)
|
local obj = minetest.add_entity(p, self.arrow)
|
||||||
local amount = (vec.x ^ 2 + vec.y ^ 2 + vec.z ^ 2) ^ 0.5
|
local amount = (vec.x ^ 2 + vec.y ^ 2 + vec.z ^ 2) ^ 0.5
|
||||||
local v = obj:get_luaentity().velocity
|
local v = obj:get_luaentity().velocity
|
||||||
vec.y = vec.y + self.shoot_offset -- this makes shoot aim accurate
|
-- offset makes shoot aim accurate
|
||||||
|
vec.y = vec.y + self.shoot_offset
|
||||||
vec.x = vec.x *v / amount
|
vec.x = vec.x *v / amount
|
||||||
vec.y = vec.y *v / amount
|
vec.y = vec.y *v / amount
|
||||||
vec.z = vec.z *v / amount
|
vec.z = vec.z *v / amount
|
||||||
obj:setvelocity(vec)
|
obj:setvelocity(vec)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end -- END if self.state == "attack"
|
||||||
end,
|
end,
|
||||||
|
|
||||||
on_activate = function(self, staticdata, dtime_s)
|
on_activate = function(self, staticdata, dtime_s)
|
||||||
@ -1082,7 +1045,7 @@ end
|
|||||||
mesh = def.gotten_mesh
|
mesh = def.gotten_mesh
|
||||||
end
|
end
|
||||||
|
|
||||||
-- if object is child then set half size
|
-- set child objects to half size
|
||||||
if self.child == true then
|
if self.child == true then
|
||||||
vis_size = {
|
vis_size = {
|
||||||
x = self.base_size.x / 2,
|
x = self.base_size.x / 2,
|
||||||
@ -1105,10 +1068,9 @@ end
|
|||||||
self.health = math.random (self.hp_min, self.hp_max)
|
self.health = math.random (self.hp_min, self.hp_max)
|
||||||
end
|
end
|
||||||
|
|
||||||
self.object:set_hp( self.health )
|
self.object:set_hp(self.health)
|
||||||
self.object:set_armor_groups({fleshy = self.armor})
|
self.object:set_armor_groups({fleshy = self.armor})
|
||||||
self.state = "stand"
|
self.state = "stand"
|
||||||
--self.order = "stand"
|
|
||||||
self.following = nil
|
self.following = nil
|
||||||
self.old_y = self.object:getpos().y
|
self.old_y = self.object:getpos().y
|
||||||
self.object:setyaw(math.random(1, 360) / 180 * math.pi)
|
self.object:setyaw(math.random(1, 360) / 180 * math.pi)
|
||||||
@ -1119,7 +1081,6 @@ end
|
|||||||
self.visual_size = vis_size
|
self.visual_size = vis_size
|
||||||
-- set anything changed above
|
-- set anything changed above
|
||||||
self.object:set_properties(self)
|
self.object:set_properties(self)
|
||||||
|
|
||||||
end,
|
end,
|
||||||
|
|
||||||
get_staticdata = function(self)
|
get_staticdata = function(self)
|
||||||
@ -1132,6 +1093,7 @@ end
|
|||||||
self.remove_ok = true
|
self.remove_ok = true
|
||||||
self.attack = nil
|
self.attack = nil
|
||||||
self.following = nil
|
self.following = nil
|
||||||
|
self.state = "stand"
|
||||||
|
|
||||||
local tmp = {}
|
local tmp = {}
|
||||||
for _,stat in pairs(self) do
|
for _,stat in pairs(self) do
|
||||||
@ -1203,7 +1165,7 @@ end
|
|||||||
if self.passive == false
|
if self.passive == false
|
||||||
and not self.tamed then
|
and not self.tamed then
|
||||||
if self.state ~= "attack" then
|
if self.state ~= "attack" then
|
||||||
self.do_attack(self, hitter, 1)
|
self.do_attack(self, hitter)
|
||||||
end
|
end
|
||||||
-- alert others to the attack
|
-- alert others to the attack
|
||||||
local obj = nil
|
local obj = nil
|
||||||
@ -1213,18 +1175,19 @@ end
|
|||||||
if obj.group_attack == true
|
if obj.group_attack == true
|
||||||
and not obj.tamed --MFF(crabman) group tamed don't attack
|
and not obj.tamed --MFF(crabman) group tamed don't attack
|
||||||
and obj.state ~= "attack" then
|
and obj.state ~= "attack" then
|
||||||
obj.do_attack(obj, hitter, 1)
|
obj.do_attack(obj, hitter)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
end
|
|
||||||
|
end -- END mobs:register_mob function
|
||||||
|
|
||||||
mobs.spawning_mobs = {}
|
mobs.spawning_mobs = {}
|
||||||
|
|
||||||
function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, interval, chance, active_object_count, min_height, max_height, spawn_in_area)
|
function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, interval, chance, active_object_count, min_height, max_height, spawn_in_area) --MFF crabman
|
||||||
mobs.spawning_mobs[name] = true
|
mobs.spawning_mobs[name] = true
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
nodenames = nodes,
|
nodenames = nodes,
|
||||||
@ -1245,7 +1208,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter
|
|||||||
-- mobs cannot spawn inside protected areas if enabled
|
-- mobs cannot spawn inside protected areas if enabled
|
||||||
if mobs.protected == 1
|
if mobs.protected == 1
|
||||||
and minetest.is_protected(pos, "")
|
and minetest.is_protected(pos, "")
|
||||||
and not spawn_in_area then
|
and not spawn_in_area then --MFF crabman
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1260,21 +1223,11 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- are we spawning inside a solid node?
|
-- are we spawning inside a solid node?
|
||||||
local nod = minetest.get_node_or_nil(pos)
|
if minetest.registered_nodes[node_ok(pos).name].walkable == true then
|
||||||
if not nod
|
|
||||||
or not nod.name
|
|
||||||
or not minetest.registered_nodes[nod.name]
|
|
||||||
or minetest.registered_nodes[nod.name].walkable == true then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
pos.y = pos.y + 1
|
pos.y = pos.y + 1
|
||||||
|
if minetest.registered_nodes[node_ok(pos).name].walkable == true then
|
||||||
nod = minetest.get_node_or_nil(pos)
|
|
||||||
if not nod
|
|
||||||
or not nod.name
|
|
||||||
or not minetest.registered_nodes[nod.name]
|
|
||||||
or minetest.registered_nodes[nod.name].walkable == true then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1357,7 +1310,8 @@ function mobs:explosion(pos, radius, fire, smoke, sound)
|
|||||||
and data[vi] ~= c_obsidian
|
and data[vi] ~= c_obsidian
|
||||||
and data[vi] ~= c_brick
|
and data[vi] ~= c_brick
|
||||||
and data[vi] ~= c_chest then
|
and data[vi] ~= c_chest then
|
||||||
local n = minetest.get_node(p).name
|
local n = node_ok(p).name
|
||||||
|
|
||||||
if not minetest.is_protected(p, "") --/MFF (Crabman|06/23/2015) re-added node protected in areas
|
if not minetest.is_protected(p, "") --/MFF (Crabman|06/23/2015) re-added node protected in areas
|
||||||
and minetest.get_item_group(n, "unbreakable") ~= 1 then
|
and minetest.get_item_group(n, "unbreakable") ~= 1 then
|
||||||
-- if chest then drop items inside
|
-- if chest then drop items inside
|
||||||
@ -1372,7 +1326,8 @@ function mobs:explosion(pos, radius, fire, smoke, sound)
|
|||||||
obj:setvelocity({
|
obj:setvelocity({
|
||||||
x = math.random(-2, 2),
|
x = math.random(-2, 2),
|
||||||
y = 7,
|
y = 7,
|
||||||
z = math.random(-2, 2)})
|
z = math.random(-2, 2)
|
||||||
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1408,7 +1363,6 @@ function check_for_death(self)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:getpos()
|
||||||
pos.y = pos.y + 0.5 -- drop items half a block higher
|
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
local obj = nil
|
local obj = nil
|
||||||
for _,drop in ipairs(self.drops) do
|
for _,drop in ipairs(self.drops) do
|
||||||
@ -1490,13 +1444,9 @@ function mobs:register_arrow(name, def)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local engage = 10 - (self.velocity / 2) -- clear entity before arrow becomes active
|
if self.hit_node then
|
||||||
local node = minetest.get_node_or_nil(pos)
|
local node = node_ok(pos).name
|
||||||
if node then node = node.name else node = "air" end
|
if minetest.registered_nodes[node].walkable then
|
||||||
|
|
||||||
if self.hit_node
|
|
||||||
and minetest.registered_nodes[node]
|
|
||||||
and minetest.registered_nodes[node].walkable then
|
|
||||||
self.hit_node(self, pos, node)
|
self.hit_node(self, pos, node)
|
||||||
if self.drop == true then
|
if self.drop == true then
|
||||||
pos.y = pos.y + 1
|
pos.y = pos.y + 1
|
||||||
@ -1506,9 +1456,11 @@ function mobs:register_arrow(name, def)
|
|||||||
self.object:remove() ; -- print ("hit node")
|
self.object:remove() ; -- print ("hit node")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if (self.hit_player or self.hit_mob)
|
if (self.hit_player or self.hit_mob)
|
||||||
and self.timer > engage then
|
-- clear entity before arrow becomes active
|
||||||
|
and self.timer > (10 - (self.velocity / 2)) then
|
||||||
for _,player in pairs(minetest.get_objects_inside_radius(pos, 1.0)) do
|
for _,player in pairs(minetest.get_objects_inside_radius(pos, 1.0)) do
|
||||||
if self.hit_player
|
if self.hit_player
|
||||||
and player:is_player() then
|
and player:is_player() then
|
||||||
@ -1545,16 +1497,19 @@ function mobs:register_egg(mob, desc, background, addegg)
|
|||||||
local pos = pointed_thing.above
|
local pos = pointed_thing.above
|
||||||
if pos and within_limits(pos, 0)
|
if pos and within_limits(pos, 0)
|
||||||
and not minetest.is_protected(pos, placer:get_player_name()) then
|
and not minetest.is_protected(pos, placer:get_player_name()) then
|
||||||
pos.y = pos.y + 0.5
|
pos.y = pos.y + 1
|
||||||
local mob = minetest.add_entity(pos, mob)
|
local mob = minetest.add_entity(pos, mob)
|
||||||
local ent = mob:get_luaentity()
|
local ent = mob:get_luaentity()
|
||||||
if ent.type ~= "monster" then
|
if ent.type ~= "monster" then
|
||||||
-- set owner
|
-- set owner and tame
|
||||||
ent.owner = placer:get_player_name()
|
ent.owner = placer:get_player_name()
|
||||||
ent.tamed = true
|
ent.tamed = true
|
||||||
end
|
end
|
||||||
|
-- if not in creative then take item
|
||||||
|
if not minetest.setting_getbool("creative_mode") then
|
||||||
itemstack:take_item()
|
itemstack:take_item()
|
||||||
end
|
end
|
||||||
|
end
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
@ -1642,30 +1597,29 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
|
|||||||
|
|
||||||
if not self.follow then return false end
|
if not self.follow then return false end
|
||||||
|
|
||||||
local item = clicker:get_wielded_item()
|
|
||||||
|
|
||||||
-- can eat/tame with item in hand
|
-- can eat/tame with item in hand
|
||||||
if follow_holding(self, clicker) then
|
if follow_holding(self, clicker) then
|
||||||
|
|
||||||
-- take item
|
-- take item
|
||||||
if not minetest.setting_getbool("creative_mode") then
|
if not minetest.setting_getbool("creative_mode") then
|
||||||
|
local item = clicker:get_wielded_item()
|
||||||
item:take_item()
|
item:take_item()
|
||||||
clicker:set_wielded_item(item)
|
clicker:set_wielded_item(item)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- heal health
|
-- heal health
|
||||||
local hp = self.object:get_hp()
|
local hp = self.object:get_hp()
|
||||||
--if hp < self.hp_max then
|
|
||||||
hp = hp + 4
|
hp = hp + 4
|
||||||
if hp >= self.hp_max then
|
if hp >= self.hp_max
|
||||||
|
and self.htimer < 1 then
|
||||||
hp = self.hp_max
|
hp = self.hp_max
|
||||||
minetest.chat_send_player(clicker:get_player_name(),
|
minetest.chat_send_player(clicker:get_player_name(),
|
||||||
self.name:split(":")[2]
|
self.name:split(":")[2]
|
||||||
.. " at full health")
|
.. " at full health (" .. tostring(hp) .. ")")
|
||||||
|
self.htimer = 5
|
||||||
end
|
end
|
||||||
self.object:set_hp(hp)
|
self.object:set_hp(hp)
|
||||||
self.health = hp
|
self.health = hp
|
||||||
--end
|
|
||||||
|
|
||||||
-- make children grow quicker
|
-- make children grow quicker
|
||||||
if self.child == true then
|
if self.child == true then
|
||||||
@ -1715,3 +1669,15 @@ function within_limits(pos, radius)
|
|||||||
return false -- beyond limits
|
return false -- beyond limits
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function node_ok(pos, fallback)
|
||||||
|
fallback = fallback or "default:dirt"
|
||||||
|
local node = minetest.get_node_or_nil(pos)
|
||||||
|
if not node then
|
||||||
|
return minetest.registered_nodes[fallback]
|
||||||
|
end
|
||||||
|
local nodef = minetest.registered_nodes[node.name]
|
||||||
|
if nodef then
|
||||||
|
return node
|
||||||
|
end
|
||||||
|
return minetest.registered_nodes[fallback]
|
||||||
|
end
|
||||||
|
@ -6,6 +6,7 @@ mobs:register_mob("mobs:bunny", {
|
|||||||
type = "animal",
|
type = "animal",
|
||||||
-- is it aggressive
|
-- is it aggressive
|
||||||
passive = true,
|
passive = true,
|
||||||
|
reach = 1,
|
||||||
-- health & armor
|
-- health & armor
|
||||||
hp_min = 3, hp_max = 6, armor = 200,
|
hp_min = 3, hp_max = 6, armor = 200,
|
||||||
-- textures and model
|
-- textures and model
|
||||||
@ -62,7 +63,6 @@ mobs:register_mob("mobs:bunny", {
|
|||||||
textures = {"mobs_bunny_evil.png"},
|
textures = {"mobs_bunny_evil.png"},
|
||||||
})
|
})
|
||||||
self.type = "monster"
|
self.type = "monster"
|
||||||
self.state = "attack"
|
|
||||||
self.object:set_hp(20)
|
self.object:set_hp(20)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -8,6 +8,7 @@ mobs:register_mob("mobs:cow", {
|
|||||||
passive = false,
|
passive = false,
|
||||||
group_attack = true,
|
group_attack = true,
|
||||||
attack_type = "dogfight",
|
attack_type = "dogfight",
|
||||||
|
reach = 2,
|
||||||
damage = 4,
|
damage = 4,
|
||||||
-- health & armor
|
-- health & armor
|
||||||
hp_min = 25,
|
hp_min = 25,
|
||||||
|
@ -7,6 +7,7 @@ mobs:register_mob("mobs:dirt_monster", {
|
|||||||
-- aggressive, deals 6 damage to player when hit
|
-- aggressive, deals 6 damage to player when hit
|
||||||
passive = false,
|
passive = false,
|
||||||
attack_type = "dogfight",
|
attack_type = "dogfight",
|
||||||
|
reach = 2,
|
||||||
damage = 5,
|
damage = 5,
|
||||||
-- health & armor
|
-- health & armor
|
||||||
hp_min = 25,
|
hp_min = 25,
|
||||||
|
@ -10,7 +10,8 @@ mobs:register_mob("mobs:dungeon_master", {
|
|||||||
-- aggressive, shoots fireballs at player, deal 13 damages
|
-- aggressive, shoots fireballs at player, deal 13 damages
|
||||||
passive = false,
|
passive = false,
|
||||||
damage = 12,
|
damage = 12,
|
||||||
attack_type = "shoot",
|
attack_type = "dogshoot",
|
||||||
|
reach = 3,
|
||||||
shoot_interval = 2.5,
|
shoot_interval = 2.5,
|
||||||
arrow = "mobs:fireball",
|
arrow = "mobs:fireball",
|
||||||
shoot_offset = 1,
|
shoot_offset = 1,
|
||||||
@ -32,7 +33,7 @@ mobs:register_mob("mobs:dungeon_master", {
|
|||||||
makes_footstep_sound = true,
|
makes_footstep_sound = true,
|
||||||
sounds = {
|
sounds = {
|
||||||
random = "mobs_dungeonmaster",
|
random = "mobs_dungeonmaster",
|
||||||
attack = "mobs_fireball",
|
shoot_attack = "mobs_fireball",
|
||||||
},
|
},
|
||||||
-- speed and jump
|
-- speed and jump
|
||||||
walk_velocity = 1,
|
walk_velocity = 1,
|
||||||
|
@ -7,6 +7,7 @@ mobs:register_mob("mobs:lava_flan", {
|
|||||||
-- aggressive, deals 5 damage to player when hit
|
-- aggressive, deals 5 damage to player when hit
|
||||||
passive = false,
|
passive = false,
|
||||||
attack_type = "dogfight",
|
attack_type = "dogfight",
|
||||||
|
reach = 2,
|
||||||
damage = 5,
|
damage = 5,
|
||||||
-- health and armor
|
-- health and armor
|
||||||
hp_min = 20,
|
hp_min = 20,
|
||||||
|
0
mods/mobs/models/mobs_shark.b3d
Normal file → Executable file
@ -86,6 +86,7 @@ mobs:register_mob("mobs:npc", {
|
|||||||
end
|
end
|
||||||
if self.diamond_count >= 4 then
|
if self.diamond_count >= 4 then
|
||||||
self.damages = 3
|
self.damages = 3
|
||||||
|
self.tamed = true
|
||||||
self.owner = clicker:get_player_name()
|
self.owner = clicker:get_player_name()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -90,6 +90,7 @@ mobs:register_mob("mobs:npc_female", {
|
|||||||
end
|
end
|
||||||
if self.diamond_count >= 4 then
|
if self.diamond_count >= 4 then
|
||||||
self.damages = 3
|
self.damages = 3
|
||||||
|
self.tamed = true
|
||||||
self.owner = clicker:get_player_name()
|
self.owner = clicker:get_player_name()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -7,6 +7,7 @@ mobs:register_mob("mobs:oerkki", {
|
|||||||
-- aggressive, deals 7 damage when player hit
|
-- aggressive, deals 7 damage when player hit
|
||||||
passive = false,
|
passive = false,
|
||||||
attack_type = "dogfight",
|
attack_type = "dogfight",
|
||||||
|
reach = 2,
|
||||||
damage = 6,
|
damage = 6,
|
||||||
-- health & armor
|
-- health & armor
|
||||||
hp_min = 40,
|
hp_min = 40,
|
||||||
@ -25,7 +26,7 @@ mobs:register_mob("mobs:oerkki", {
|
|||||||
makes_footstep_sound = false,
|
makes_footstep_sound = false,
|
||||||
sounds = {
|
sounds = {
|
||||||
random = "mobs_oerkki",
|
random = "mobs_oerkki",
|
||||||
attack = "mobs_oerkki_attack",
|
shoot_attack = "mobs_oerkki_attack",
|
||||||
},
|
},
|
||||||
-- speed and jump
|
-- speed and jump
|
||||||
walk_velocity = 2,
|
walk_velocity = 2,
|
||||||
|
@ -7,6 +7,7 @@ mobs:register_mob("mobs:sand_monster", {
|
|||||||
-- aggressive, deals 5 damage to player when hit
|
-- aggressive, deals 5 damage to player when hit
|
||||||
passive = false,
|
passive = false,
|
||||||
attack_type = "dogfight",
|
attack_type = "dogfight",
|
||||||
|
reach = 2,
|
||||||
damage = 4,
|
damage = 4,
|
||||||
-- health & armor
|
-- health & armor
|
||||||
hp_min = 15,
|
hp_min = 15,
|
||||||
|
0
mods/mobs/shark.lua
Normal file → Executable file
@ -7,6 +7,7 @@ mobs:register_mob("mobs:spider", {
|
|||||||
-- agressive, does 6 damage to player when hit
|
-- agressive, does 6 damage to player when hit
|
||||||
passive = false,
|
passive = false,
|
||||||
attack_type = "dogfight",
|
attack_type = "dogfight",
|
||||||
|
reach = 2,
|
||||||
damage = 5,
|
damage = 5,
|
||||||
-- health & armor
|
-- health & armor
|
||||||
hp_min = 30,
|
hp_min = 30,
|
||||||
|
@ -7,6 +7,7 @@ mobs:register_mob("mobs:stone_monster", {
|
|||||||
-- aggressive, deals 8 damage to player when hit
|
-- aggressive, deals 8 damage to player when hit
|
||||||
passive = false,
|
passive = false,
|
||||||
attack_type = "dogfight",
|
attack_type = "dogfight",
|
||||||
|
reach = 2,
|
||||||
damage = 7,
|
damage = 7,
|
||||||
-- health & armor
|
-- health & armor
|
||||||
hp_min = 20,
|
hp_min = 20,
|
||||||
|
0
mods/mobs/textures/mobs_cow_inv.png
Normal file → Executable file
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
0
mods/mobs/textures/mobs_shark_shark_item.png
Normal file → Executable file
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
0
mods/mobs/textures/shark_first.png
Normal file → Executable file
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
0
mods/mobs/textures/shark_second.png
Normal file → Executable file
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
0
mods/mobs/textures/shark_third.png
Normal file → Executable file
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@ -7,6 +7,7 @@ mobs:register_mob("mobs:tree_monster", {
|
|||||||
-- aggressive, deals 9 damage to player when hit
|
-- aggressive, deals 9 damage to player when hit
|
||||||
passive = false,
|
passive = false,
|
||||||
attack_type = "dogfight",
|
attack_type = "dogfight",
|
||||||
|
reach = 2,
|
||||||
damage = 8,
|
damage = 8,
|
||||||
-- health & armor
|
-- health & armor
|
||||||
hp_min = 40,
|
hp_min = 40,
|
||||||
|
@ -8,6 +8,7 @@ mobs:register_mob("mobs:pumba", {
|
|||||||
passive = false,
|
passive = false,
|
||||||
group_attack = true,
|
group_attack = true,
|
||||||
attack_type = "dogfight",
|
attack_type = "dogfight",
|
||||||
|
reach = 2,
|
||||||
damage = 4,
|
damage = 4,
|
||||||
-- health & armor
|
-- health & armor
|
||||||
hp_min = 15,
|
hp_min = 15,
|
||||||
|