Optimized code
parent
8c57ef83c3
commit
7b868a73ed
744
api.lua
744
api.lua
|
@ -2,8 +2,6 @@
|
|||
mobs = {}
|
||||
mobs.mod = "redo"
|
||||
|
||||
local pi = math.pi
|
||||
|
||||
-- Load settings
|
||||
local damage_enabled = minetest.setting_getbool("enable_damage")
|
||||
local peaceful_only = minetest.setting_getbool("only_peaceful_mobs")
|
||||
|
@ -11,9 +9,345 @@ local disable_blood = minetest.setting_getbool("mobs_disable_blood")
|
|||
mobs.protected = tonumber(minetest.setting_get("mobs_spawn_protected")) or 1
|
||||
mobs.remove = minetest.setting_getbool("remove_far_mobs")
|
||||
|
||||
-- internal functions
|
||||
|
||||
local pi = math.pi
|
||||
|
||||
local do_attack = function(self, player)
|
||||
if self.state ~= "attack" then
|
||||
if math.random(0,100) < 90
|
||||
and self.sounds.war_cry then
|
||||
minetest.sound_play(self.sounds.war_cry,{
|
||||
object = self.object,
|
||||
max_hear_distance = self.sounds.distance
|
||||
})
|
||||
end
|
||||
self.state = "attack"
|
||||
self.attack = player
|
||||
end
|
||||
end
|
||||
|
||||
local set_velocity = function(self, v)
|
||||
v = (v or 0)
|
||||
if self.drawtype
|
||||
and self.drawtype == "side" then
|
||||
self.rotate = math.rad(90)
|
||||
end
|
||||
local yaw = self.object:getyaw() + self.rotate
|
||||
local x = math.sin(yaw) * -v
|
||||
local z = math.cos(yaw) * v
|
||||
self.object:setvelocity({
|
||||
x = x,
|
||||
y = self.object:getvelocity().y,
|
||||
z = z
|
||||
})
|
||||
end
|
||||
|
||||
local get_velocity = function(self)
|
||||
local v = self.object:getvelocity()
|
||||
return (v.x ^ 2 + v.z ^ 2) ^ (0.5)
|
||||
end
|
||||
|
||||
local set_animation2 = function(self, type)
|
||||
if not self.animation then
|
||||
return
|
||||
end
|
||||
if not self.animation.current then
|
||||
self.animation.current = ""
|
||||
end
|
||||
if type == "stand"
|
||||
and self.animation.current ~= "stand" then
|
||||
if self.animation.stand_start
|
||||
and self.animation.stand_end
|
||||
and self.animation.speed_normal then
|
||||
self.object:set_animation({
|
||||
x = self.animation.stand_start,
|
||||
y = self.animation.stand_end},
|
||||
self.animation.speed_normal, 0)
|
||||
self.animation.current = "stand"
|
||||
end
|
||||
elseif type == "walk"
|
||||
and self.animation.current ~= "walk" then
|
||||
if self.animation.walk_start
|
||||
and self.animation.walk_end
|
||||
and self.animation.speed_normal then
|
||||
self.object:set_animation({
|
||||
x = self.animation.walk_start,
|
||||
y = self.animation.walk_end},
|
||||
self.animation.speed_normal, 0)
|
||||
self.animation.current = "walk"
|
||||
end
|
||||
elseif type == "run"
|
||||
and self.animation.current ~= "run" then
|
||||
if self.animation.run_start
|
||||
and self.animation.run_end
|
||||
and self.animation.speed_run then
|
||||
self.object:set_animation({
|
||||
x = self.animation.run_start,
|
||||
y = self.animation.run_end},
|
||||
self.animation.speed_run, 0)
|
||||
self.animation.current = "run"
|
||||
end
|
||||
elseif type == "punch"
|
||||
and self.animation.current ~= "punch" then
|
||||
if self.animation.punch_start
|
||||
and self.animation.punch_end
|
||||
and self.animation.speed_normal then
|
||||
self.object:set_animation({
|
||||
x = self.animation.punch_start,
|
||||
y = self.animation.punch_end},
|
||||
self.animation.speed_normal, 0)
|
||||
self.animation.current = "punch"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local do_env_damage = function(self)
|
||||
|
||||
-- feed/tame text timer
|
||||
if self.htimer > 0 then
|
||||
self.htimer = self.htimer - 1
|
||||
end
|
||||
|
||||
local pos = self.object:getpos()
|
||||
local tod = minetest.get_timeofday()
|
||||
|
||||
-- daylight above ground
|
||||
if self.light_damage ~= 0
|
||||
and pos.y > 0
|
||||
and tod > 0.2
|
||||
and tod < 0.8
|
||||
and (minetest.get_node_light(pos) or 0) > 12 then
|
||||
self.object:set_hp(self.object:get_hp() - self.light_damage)
|
||||
effect(pos, 5, "tnt_smoke.png")
|
||||
if check_for_death(self) then return end
|
||||
end
|
||||
|
||||
if self.water_damage ~= 0 or self.lava_damage ~= 0 then
|
||||
pos.y = (pos.y + self.collisionbox[2]) + 0.1 -- foot level
|
||||
local nod = node_ok(pos, "air") ; -- print ("standing in "..nod.name)
|
||||
local nodef = minetest.registered_nodes[nod.name]
|
||||
pos.y = pos.y + 1
|
||||
|
||||
-- water
|
||||
if self.water_damage ~= 0
|
||||
and nodef.groups.water then
|
||||
self.object:set_hp(self.object:get_hp() - self.water_damage)
|
||||
effect(pos, 5, "bubble.png")
|
||||
if check_for_death(self) then return end
|
||||
end
|
||||
|
||||
-- lava or fire
|
||||
if self.lava_damage ~= 0
|
||||
and (nodef.groups.lava
|
||||
or nod.name == "fire:basic_flame"
|
||||
or nod.name == "fire:eternal_flame") then
|
||||
self.object:set_hp(self.object:get_hp() - self.lava_damage)
|
||||
effect(pos, 5, "fire_basic_flame.png")
|
||||
if check_for_death(self) then return end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local do_jump = function(self)
|
||||
if self.fly then
|
||||
return
|
||||
end
|
||||
|
||||
local pos = self.object:getpos()
|
||||
pos.y = (pos.y + self.collisionbox[2]) - 0.2
|
||||
local nod = node_ok(pos)
|
||||
--print ("standing on:", nod.name, pos.y)
|
||||
if minetest.registered_nodes[nod.name].walkable == false then
|
||||
return
|
||||
end
|
||||
if self.direction then
|
||||
pos.y = pos.y + 0.5
|
||||
local nod = node_ok({
|
||||
x = pos.x + self.direction.x,
|
||||
y = pos.y,
|
||||
z = pos.z + self.direction.z
|
||||
})
|
||||
--print ("in front:", nod.name, pos.y)
|
||||
if nod.name ~= "air"
|
||||
and minetest.registered_items[nod.name].walkable
|
||||
and not nod.name:find("fence")
|
||||
or self.walk_chance == 0 then
|
||||
local v = self.object:getvelocity()
|
||||
v.y = self.jump_height + 1
|
||||
v.x = v.x * 2.2
|
||||
v.z = v.z * 2.2
|
||||
self.object:setvelocity(v)
|
||||
if self.sounds.jump then
|
||||
minetest.sound_play(self.sounds.jump, {
|
||||
object = self.object,
|
||||
max_hear_distance = self.sounds.distance
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local in_fov = function(self, pos)
|
||||
-- checks if POS is in mobs field of view
|
||||
local yaw = self.object:getyaw() + self.rotate
|
||||
local vx = math.sin(yaw)
|
||||
local vz = math.cos(yaw)
|
||||
local ds = math.sqrt(vx ^ 2 + vz ^ 2)
|
||||
local ps = math.sqrt(pos.x ^ 2 + pos.z ^ 2)
|
||||
local d = {x = vx / ds, z = vz / ds}
|
||||
local p = {x = pos.x / ps, z = pos.z / ps}
|
||||
local an = (d.x * p.x) + (d.z * p.z)
|
||||
if math.deg(math.acos(an)) > (self.fov / 2) then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- particle effects
|
||||
function effect(pos, amount, texture, max_size)
|
||||
minetest.add_particlespawner({
|
||||
amount = amount,
|
||||
time = 0.25,
|
||||
minpos = pos,
|
||||
maxpos = pos,
|
||||
minvel = {x = -0, y = -2, z = -0},
|
||||
maxvel = {x = 2, y = 2, z = 2},
|
||||
minacc = {x = -4, y = -4, z = -4},
|
||||
maxacc = {x = 4, y = 4, z = 4},
|
||||
minexptime = 0.1,
|
||||
maxexptime = 1,
|
||||
minsize = 0.5,
|
||||
maxsize = (max_size or 1),
|
||||
texture = texture,
|
||||
})
|
||||
end
|
||||
|
||||
-- on mob death drop items
|
||||
function check_for_death(self)
|
||||
local hp = self.object:get_hp()
|
||||
if hp > 0 then
|
||||
self.health = hp
|
||||
if self.sounds.damage ~= nil then
|
||||
minetest.sound_play(self.sounds.damage,{
|
||||
object = self.object,
|
||||
max_hear_distance = self.sounds.distance
|
||||
})
|
||||
end
|
||||
return false
|
||||
end
|
||||
local pos = self.object:getpos()
|
||||
local obj = nil
|
||||
for _,drop in ipairs(self.drops) do
|
||||
if math.random(1, drop.chance) == 1 then
|
||||
obj = minetest.add_item(pos,
|
||||
ItemStack(drop.name.." "..math.random(drop.min, drop.max)))
|
||||
if obj then
|
||||
obj:setvelocity({
|
||||
x = math.random(-1, 1),
|
||||
y = 6,
|
||||
z = math.random(-1, 1)
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.sounds.death ~= nil then
|
||||
minetest.sound_play(self.sounds.death,{
|
||||
object = self.object,
|
||||
max_hear_distance = self.sounds.distance
|
||||
})
|
||||
end
|
||||
if self.on_die then
|
||||
self.on_die(self, pos)
|
||||
end
|
||||
self.object:remove()
|
||||
return true
|
||||
end
|
||||
|
||||
-- from TNT mod
|
||||
function calc_velocity(pos1, pos2, old_vel, power)
|
||||
local vel = vector.direction(pos1, pos2)
|
||||
vel = vector.normalize(vel)
|
||||
vel = vector.multiply(vel, power)
|
||||
local dist = vector.distance(pos1, pos2)
|
||||
dist = math.max(dist, 1)
|
||||
vel = vector.divide(vel, dist)
|
||||
vel = vector.add(vel, old_vel)
|
||||
return vel
|
||||
end
|
||||
|
||||
-- modified from TNT mod
|
||||
function entity_physics(pos, radius)
|
||||
radius = radius * 2
|
||||
local objs = minetest.get_objects_inside_radius(pos, radius)
|
||||
local obj_pos, obj_vel, dist
|
||||
for _, obj in pairs(objs) do
|
||||
obj_pos = obj:getpos()
|
||||
obj_vel = obj:getvelocity()
|
||||
dist = math.max(1, vector.distance(pos, obj_pos))
|
||||
if obj_vel ~= nil then
|
||||
obj:setvelocity(calc_velocity(pos, obj_pos, obj_vel, radius * 10))
|
||||
end
|
||||
local damage = math.floor((4 / dist) * radius)
|
||||
obj:set_hp(obj:get_hp() - damage)
|
||||
end
|
||||
end
|
||||
|
||||
-- check if within map limits (-30911 to 30927)
|
||||
function within_limits(pos, radius)
|
||||
if (pos.x - radius) > -30913
|
||||
and (pos.x + radius) < 30928
|
||||
and (pos.y - radius) > -30913
|
||||
and (pos.y + radius) < 30928
|
||||
and (pos.z - radius) > -30913
|
||||
and (pos.z + radius) < 30928 then
|
||||
return true -- within limits
|
||||
end
|
||||
return false -- beyond limits
|
||||
end
|
||||
|
||||
-- get node at location but with fallback for nil or unknown
|
||||
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
|
||||
|
||||
-- should mob follow what I'm holding ?
|
||||
function follow_holding(self, clicker)
|
||||
local item = clicker:get_wielded_item()
|
||||
local t = type(self.follow)
|
||||
|
||||
-- single item
|
||||
if t == "string"
|
||||
and item:get_name() == self.follow then
|
||||
return true
|
||||
|
||||
-- multiple items
|
||||
elseif t == "table" then
|
||||
for no = 1, #self.follow do
|
||||
if self.follow[no] == item:get_name() then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- register mob function
|
||||
|
||||
function mobs:register_mob(name, def)
|
||||
|
||||
minetest.register_entity(name, {
|
||||
|
||||
stepheight = def.stepheight or 0.6,
|
||||
name = name,
|
||||
fly = def.fly,
|
||||
|
@ -24,6 +358,7 @@ minetest.register_entity(name, {
|
|||
do_custom = def.do_custom,
|
||||
jump_height = def.jump_height or 6,
|
||||
jump_chance = def.jump_chance or 0,
|
||||
drawtype = def.drawtype, -- DEPRECATED, use rotate instead
|
||||
rotate = math.rad(def.rotate or 0), -- 0=front, 90=side, 180=back, 270=side2
|
||||
lifetimer = def.lifetimer or 180, -- 3 minutes
|
||||
hp_min = def.hp_min or 5,
|
||||
|
@ -83,111 +418,6 @@ minetest.register_entity(name, {
|
|||
reach = def.reach or 3,
|
||||
htimer = 0,
|
||||
|
||||
do_attack = function(self, player)
|
||||
if self.state ~= "attack" then
|
||||
if math.random(0,100) < 90
|
||||
and self.sounds.war_cry then
|
||||
minetest.sound_play(self.sounds.war_cry,{
|
||||
object = self.object,
|
||||
max_hear_distance = self.sounds.distance
|
||||
})
|
||||
end
|
||||
self.state = "attack"
|
||||
self.attack = player
|
||||
end
|
||||
end,
|
||||
|
||||
set_velocity = function(self, v)
|
||||
v = (v or 0)
|
||||
if def.drawtype
|
||||
and def.drawtype == "side" then
|
||||
self.rotate = math.rad(90)
|
||||
end
|
||||
local yaw = self.object:getyaw() + self.rotate
|
||||
local x = math.sin(yaw) * -v
|
||||
local z = math.cos(yaw) * v
|
||||
self.object:setvelocity({
|
||||
x = x,
|
||||
y = self.object:getvelocity().y,
|
||||
z = z}
|
||||
)
|
||||
end,
|
||||
|
||||
get_velocity = function(self)
|
||||
local v = self.object:getvelocity()
|
||||
return (v.x ^ 2 + v.z ^ 2) ^ (0.5)
|
||||
end,
|
||||
--[[
|
||||
in_fov = function(self, pos)
|
||||
-- checks if POS is in self's FOV
|
||||
local yaw = self.object:getyaw() + self.rotate
|
||||
local vx = math.sin(yaw)
|
||||
local vz = math.cos(yaw)
|
||||
local ds = math.sqrt(vx ^ 2 + vz ^ 2)
|
||||
local ps = math.sqrt(pos.x ^ 2 + pos.z ^ 2)
|
||||
local d = {x = vx / ds, z = vz / ds}
|
||||
local p = {x = pos.x / ps, z = pos.z / ps}
|
||||
local an = (d.x * p.x) + (d.z * p.z)
|
||||
if math.deg(math.acos(an)) > (self.fov / 2) then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end,
|
||||
]]
|
||||
set_animation = function(self, type)
|
||||
if not self.animation then
|
||||
return
|
||||
end
|
||||
if not self.animation.current then
|
||||
self.animation.current = ""
|
||||
end
|
||||
if type == "stand"
|
||||
and self.animation.current ~= "stand" then
|
||||
if self.animation.stand_start
|
||||
and self.animation.stand_end
|
||||
and self.animation.speed_normal then
|
||||
self.object:set_animation({
|
||||
x = self.animation.stand_start,
|
||||
y = self.animation.stand_end},
|
||||
self.animation.speed_normal, 0)
|
||||
self.animation.current = "stand"
|
||||
end
|
||||
elseif type == "walk"
|
||||
and self.animation.current ~= "walk" then
|
||||
if self.animation.walk_start
|
||||
and self.animation.walk_end
|
||||
and self.animation.speed_normal then
|
||||
self.object:set_animation({
|
||||
x = self.animation.walk_start,
|
||||
y = self.animation.walk_end},
|
||||
self.animation.speed_normal, 0)
|
||||
self.animation.current = "walk"
|
||||
end
|
||||
elseif type == "run"
|
||||
and self.animation.current ~= "run" then
|
||||
if self.animation.run_start
|
||||
and self.animation.run_end
|
||||
and self.animation.speed_run then
|
||||
self.object:set_animation({
|
||||
x = self.animation.run_start,
|
||||
y = self.animation.run_end},
|
||||
self.animation.speed_run, 0)
|
||||
self.animation.current = "run"
|
||||
end
|
||||
elseif type == "punch"
|
||||
and self.animation.current ~= "punch" then
|
||||
if self.animation.punch_start
|
||||
and self.animation.punch_end
|
||||
and self.animation.speed_normal then
|
||||
self.object:set_animation({
|
||||
x = self.animation.punch_start,
|
||||
y = self.animation.punch_end},
|
||||
self.animation.speed_normal, 0)
|
||||
self.animation.current = "punch"
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
on_step = function(self, dtime)
|
||||
|
||||
-- remove monsters if playing on peaceful
|
||||
|
@ -301,89 +531,6 @@ minetest.register_entity(name, {
|
|||
})
|
||||
end
|
||||
|
||||
local do_env_damage = function(self)
|
||||
if self.htimer > 0 then
|
||||
self.htimer = self.htimer - 1
|
||||
end
|
||||
local pos = self.object:getpos()
|
||||
local tod = minetest.get_timeofday()
|
||||
|
||||
-- daylight above ground
|
||||
if self.light_damage ~= 0
|
||||
and pos.y > 0
|
||||
and tod > 0.2
|
||||
and tod < 0.8
|
||||
and (minetest.get_node_light(pos) or 0) > 12 then
|
||||
self.object:set_hp(self.object:get_hp() - self.light_damage)
|
||||
effect(pos, 5, "tnt_smoke.png")
|
||||
if check_for_death(self) then return end
|
||||
end
|
||||
|
||||
if self.water_damage ~= 0 or self.lava_damage ~= 0 then
|
||||
pos.y = (pos.y + self.collisionbox[2]) + 0.1 -- foot level
|
||||
local nod = node_ok(pos, "air") ; -- print ("standing in "..nod.name)
|
||||
local nodef = minetest.registered_nodes[nod.name]
|
||||
pos.y = pos.y + 1
|
||||
|
||||
-- water
|
||||
if self.water_damage ~= 0
|
||||
and nodef.groups.water then
|
||||
self.object:set_hp(self.object:get_hp() - self.water_damage)
|
||||
effect(pos, 5, "bubble.png")
|
||||
if check_for_death(self) then return end
|
||||
end
|
||||
|
||||
-- lava or fire
|
||||
if self.lava_damage ~= 0
|
||||
and (nodef.groups.lava
|
||||
or nod.name == "fire:basic_flame"
|
||||
or nod.name == "fire:eternal_flame") then
|
||||
self.object:set_hp(self.object:get_hp() - self.lava_damage)
|
||||
effect(pos, 5, "fire_basic_flame.png")
|
||||
if check_for_death(self) then return end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local do_jump = function(self)
|
||||
if self.fly then
|
||||
return
|
||||
end
|
||||
|
||||
local pos = self.object:getpos()
|
||||
pos.y = (pos.y + self.collisionbox[2]) - 0.2
|
||||
local nod = node_ok(pos)
|
||||
--print ("standing on:", nod.name, pos.y)
|
||||
if minetest.registered_nodes[nod.name].walkable == false then
|
||||
return
|
||||
end
|
||||
if self.direction then
|
||||
pos.y = pos.y + 0.5
|
||||
local nod = node_ok({
|
||||
x = pos.x + self.direction.x,
|
||||
y = pos.y,
|
||||
z = pos.z + self.direction.z
|
||||
})
|
||||
--print ("in front:", nod.name, pos.y)
|
||||
if nod.name ~= "air"
|
||||
and minetest.registered_items[nod.name].walkable
|
||||
and not nod.name:find("fence")
|
||||
or self.walk_chance == 0 then
|
||||
local v = self.object:getvelocity()
|
||||
v.y = self.jump_height + 1
|
||||
v.x = v.x * 2.2
|
||||
v.z = v.z * 2.2
|
||||
self.object:setvelocity(v)
|
||||
if self.sounds.jump then
|
||||
minetest.sound_play(self.sounds.jump, {
|
||||
object = self.object,
|
||||
max_hear_distance = self.sounds.distance
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- environmental damage timer (every 1 second)
|
||||
self.env_damage_timer = self.env_damage_timer + dtime
|
||||
if self.state == "attack"
|
||||
|
@ -449,7 +596,7 @@ end
|
|||
end
|
||||
-- attack player
|
||||
if min_player then
|
||||
self.do_attack(self, min_player)
|
||||
do_attack(self, min_player)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -476,7 +623,7 @@ end
|
|||
end
|
||||
end
|
||||
if min_player then
|
||||
self.do_attack(self, min_player)
|
||||
do_attack(self, min_player)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -506,8 +653,9 @@ end
|
|||
})
|
||||
-- jump when grown so not to fall into ground
|
||||
local v = self.object:getvelocity()
|
||||
v.x = 0
|
||||
v.y = self.jump_height
|
||||
v.x = 0 ; v.z = 0
|
||||
v.z = 0
|
||||
self.object:setvelocity(v)
|
||||
end
|
||||
end
|
||||
|
@ -650,7 +798,7 @@ end
|
|||
if dist > self.reach
|
||||
and self.order ~= "stand" then
|
||||
if (self.jump
|
||||
and self.get_velocity(self) <= 0.5
|
||||
and get_velocity(self) <= 0.5
|
||||
and self.object:getvelocity().y == 0)
|
||||
or (self.object:getvelocity().y == 0
|
||||
and self.jump_chance > 0) then
|
||||
|
@ -661,13 +809,14 @@ end
|
|||
}
|
||||
do_jump(self)
|
||||
end
|
||||
self.set_velocity(self, self.walk_velocity)
|
||||
set_velocity(self, self.walk_velocity)
|
||||
if self.walk_chance ~= 0 then
|
||||
self:set_animation("walk")
|
||||
--self:set_animation("walk")
|
||||
set_animation2(self, "walk")
|
||||
end
|
||||
else
|
||||
self.set_velocity(self, 0)
|
||||
self:set_animation("stand")
|
||||
set_velocity(self, 0)
|
||||
set_animation2(self, "stand")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
@ -704,21 +853,21 @@ end
|
|||
self.object:setyaw(yaw)
|
||||
end
|
||||
|
||||
self.set_velocity(self, 0)
|
||||
self.set_animation(self, "stand")
|
||||
set_velocity(self, 0)
|
||||
set_animation2(self, "stand")
|
||||
|
||||
-- npc's ordered to stand stay standing
|
||||
if self.type == "npc"
|
||||
and self.order == "stand" then
|
||||
self.set_velocity(self, 0)
|
||||
set_velocity(self, 0)
|
||||
self.state = "stand"
|
||||
self:set_animation("stand")
|
||||
set_animation2(self, "stand")
|
||||
else
|
||||
if self.walk_chance ~= 0
|
||||
and math.random(1, 100) <= self.walk_chance then
|
||||
self.set_velocity(self, self.walk_velocity)
|
||||
set_velocity(self, self.walk_velocity)
|
||||
self.state = "walk"
|
||||
self.set_animation(self, "walk")
|
||||
set_animation2(self, "walk")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -731,10 +880,10 @@ end
|
|||
and self.fly_in == "default:water_source"
|
||||
and not lp then
|
||||
print ("out of water")
|
||||
self.set_velocity(self, 0)
|
||||
set_velocity(self, 0)
|
||||
-- change to undefined state so nothing more happens
|
||||
self.state = "flop"
|
||||
self:set_animation("stand")
|
||||
set_animation2(self, "stand")
|
||||
return
|
||||
end
|
||||
|
||||
|
@ -752,7 +901,7 @@ end
|
|||
end
|
||||
|
||||
-- jump when walking comes to a halt
|
||||
if self.jump and self.get_velocity(self) <= 0.5
|
||||
if self.jump and get_velocity(self) <= 0.5
|
||||
and self.object:getvelocity().y == 0 then
|
||||
self.direction = {
|
||||
x = math.sin(yaw) * -1,
|
||||
|
@ -762,12 +911,12 @@ end
|
|||
do_jump(self)
|
||||
end
|
||||
|
||||
self:set_animation("walk")
|
||||
self.set_velocity(self, self.walk_velocity)
|
||||
set_velocity(self, self.walk_velocity)
|
||||
set_animation2(self, "walk")
|
||||
if math.random(1, 100) <= 30 then
|
||||
self.set_velocity(self, 0)
|
||||
set_velocity(self, 0)
|
||||
self.state = "stand"
|
||||
self:set_animation("stand")
|
||||
set_animation2(self, "stand")
|
||||
end
|
||||
|
||||
-- attack routines (explode, dogfight, shoot, dogshoot)
|
||||
|
@ -785,8 +934,8 @@ end
|
|||
or self.attack:get_hp() <= 0 then
|
||||
--print(" ** stop attacking **", dist, self.view_range)
|
||||
self.state = "stand"
|
||||
self.set_velocity(self, 0)
|
||||
self:set_animation("stand")
|
||||
set_velocity(self, 0)
|
||||
set_animation2(self, "stand")
|
||||
self.attack = nil
|
||||
self.v_start = false
|
||||
self.timer = 0
|
||||
|
@ -806,23 +955,23 @@ end
|
|||
if dist > self.reach then
|
||||
if not self.v_start then
|
||||
self.v_start = true
|
||||
self.set_velocity(self, self.run_velocity)
|
||||
set_velocity(self, self.run_velocity)
|
||||
self.timer = 0
|
||||
self.blinktimer = 0
|
||||
else
|
||||
self.timer = 0
|
||||
self.blinktimer = 0
|
||||
if self.get_velocity(self) <= 0.5
|
||||
if get_velocity(self) <= 0.5
|
||||
and self.object:getvelocity().y == 0 then
|
||||
local v = self.object:getvelocity()
|
||||
v.y = 5
|
||||
self.object:setvelocity(v)
|
||||
end
|
||||
self.set_velocity(self, self.run_velocity)
|
||||
set_velocity(self, self.run_velocity)
|
||||
end
|
||||
self:set_animation("run")
|
||||
set_animation2(self, "run")
|
||||
else
|
||||
self.set_velocity(self, 0)
|
||||
set_velocity(self, 0)
|
||||
self.timer = self.timer + dtime
|
||||
self.blinktimer = (self.blinktimer or 0) + dtime
|
||||
if self.blinktimer > 0.2 then
|
||||
|
@ -916,7 +1065,7 @@ end
|
|||
if dist > self.reach then
|
||||
-- jump attack
|
||||
if (self.jump
|
||||
and self.get_velocity(self) <= 0.5
|
||||
and get_velocity(self) <= 0.5
|
||||
and self.object:getvelocity().y == 0)
|
||||
or (self.object:getvelocity().y == 0
|
||||
and self.jump_chance > 0) then
|
||||
|
@ -927,11 +1076,11 @@ end
|
|||
}
|
||||
do_jump(self)
|
||||
end
|
||||
self.set_velocity(self, self.run_velocity)
|
||||
self:set_animation("run")
|
||||
set_velocity(self, self.run_velocity)
|
||||
set_animation2(self, "run")
|
||||
else
|
||||
self.set_velocity(self, 0)
|
||||
self:set_animation("punch")
|
||||
set_velocity(self, 0)
|
||||
set_animation2(self, "punch")
|
||||
if self.timer > 1 then
|
||||
self.timer = 0
|
||||
local p2 = p
|
||||
|
@ -968,13 +1117,13 @@ end
|
|||
yaw = yaw + pi
|
||||
end
|
||||
self.object:setyaw(yaw)
|
||||
self.set_velocity(self, 0)
|
||||
set_velocity(self, 0)
|
||||
|
||||
if self.shoot_interval
|
||||
and self.timer > self.shoot_interval
|
||||
and math.random(1, 100) <= 60 then
|
||||
self.timer = 0
|
||||
self:set_animation("punch")
|
||||
set_animation2(self, "punch")
|
||||
|
||||
-- play shoot attack sound
|
||||
if self.sounds.shoot_attack then
|
||||
|
@ -1072,8 +1221,6 @@ end
|
|||
|
||||
self.object:set_hp(self.health)
|
||||
self.object:set_armor_groups({fleshy = self.armor})
|
||||
--self.state = "stand"
|
||||
--self.following = nil
|
||||
self.old_y = self.object:getpos().y
|
||||
self.object:setyaw(math.random(1, 360) / 180 * pi)
|
||||
self.sounds.distance = (self.sounds.distance or 10)
|
||||
|
@ -1171,7 +1318,7 @@ end
|
|||
if self.passive == false
|
||||
and not self.tamed then
|
||||
if self.state ~= "attack" then
|
||||
self.do_attack(self, hitter)
|
||||
do_attack(self, hitter)
|
||||
end
|
||||
-- alert others to the attack
|
||||
local obj = nil
|
||||
|
@ -1180,7 +1327,7 @@ end
|
|||
if obj then
|
||||
if obj.group_attack == true
|
||||
and obj.state ~= "attack" then
|
||||
obj.do_attack(obj, hitter)
|
||||
do_attack(obj, hitter)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1190,6 +1337,8 @@ end
|
|||
|
||||
end -- END mobs:register_mob function
|
||||
|
||||
-- global functions
|
||||
|
||||
mobs.spawning_mobs = {}
|
||||
|
||||
function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, interval, chance, active_object_count, min_height, max_height)
|
||||
|
@ -1252,25 +1401,6 @@ function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_o
|
|||
mobs:spawn_specific(name, nodes, {"air"}, min_light, max_light, 30, chance, active_object_count, -31000, max_height)
|
||||
end
|
||||
|
||||
-- particle effects
|
||||
function effect(pos, amount, texture, max_size)
|
||||
minetest.add_particlespawner({
|
||||
amount = amount,
|
||||
time = 0.25,
|
||||
minpos = pos,
|
||||
maxpos = pos,
|
||||
minvel = {x = -0, y = -2, z = -0},
|
||||
maxvel = {x = 2, y = 2, z = 2},
|
||||
minacc = {x = -4, y = -4, z = -4},
|
||||
maxacc = {x = 4, y = 4, z = 4},
|
||||
minexptime = 0.1,
|
||||
maxexptime = 1,
|
||||
minsize = 0.5,
|
||||
maxsize = (max_size or 1),
|
||||
texture = texture,
|
||||
})
|
||||
end
|
||||
|
||||
-- explosion
|
||||
function mobs:explosion(pos, radius, fire, smoke, sound)
|
||||
-- node hit, bursts into flame (cannot blast through unbreakable/specific nodes)
|
||||
|
@ -1349,76 +1479,6 @@ function mobs:explosion(pos, radius, fire, smoke, sound)
|
|||
end
|
||||
end
|
||||
|
||||
-- on mob death drop items
|
||||
function check_for_death(self)
|
||||
local hp = self.object:get_hp()
|
||||
if hp > 0 then
|
||||
self.health = hp
|
||||
if self.sounds.damage ~= nil then
|
||||
minetest.sound_play(self.sounds.damage,{
|
||||
object = self.object,
|
||||
max_hear_distance = self.sounds.distance
|
||||
})
|
||||
end
|
||||
return false
|
||||
end
|
||||
local pos = self.object:getpos()
|
||||
local obj = nil
|
||||
for _,drop in ipairs(self.drops) do
|
||||
if math.random(1, drop.chance) == 1 then
|
||||
obj = minetest.add_item(pos,
|
||||
ItemStack(drop.name.." "..math.random(drop.min, drop.max)))
|
||||
if obj then
|
||||
obj:setvelocity({
|
||||
x = math.random(-1, 1),
|
||||
y = 6,
|
||||
z = math.random(-1, 1)
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.sounds.death ~= nil then
|
||||
minetest.sound_play(self.sounds.death,{
|
||||
object = self.object,
|
||||
max_hear_distance = self.sounds.distance
|
||||
})
|
||||
end
|
||||
if self.on_die then
|
||||
self.on_die(self, pos)
|
||||
end
|
||||
self.object:remove()
|
||||
return true
|
||||
end
|
||||
|
||||
-- from TNT mod
|
||||
function calc_velocity(pos1, pos2, old_vel, power)
|
||||
local vel = vector.direction(pos1, pos2)
|
||||
vel = vector.normalize(vel)
|
||||
vel = vector.multiply(vel, power)
|
||||
local dist = vector.distance(pos1, pos2)
|
||||
dist = math.max(dist, 1)
|
||||
vel = vector.divide(vel, dist)
|
||||
vel = vector.add(vel, old_vel)
|
||||
return vel
|
||||
end
|
||||
|
||||
-- modified from TNT mod
|
||||
function entity_physics(pos, radius)
|
||||
radius = radius * 2
|
||||
local objs = minetest.get_objects_inside_radius(pos, radius)
|
||||
local obj_pos, obj_vel, dist
|
||||
for _, obj in pairs(objs) do
|
||||
obj_pos = obj:getpos()
|
||||
obj_vel = obj:getvelocity()
|
||||
dist = math.max(1, vector.distance(pos, obj_pos))
|
||||
if obj_vel ~= nil then
|
||||
obj:setvelocity(calc_velocity(pos, obj_pos, obj_vel, radius * 10))
|
||||
end
|
||||
local damage = math.floor((4 / dist) * radius)
|
||||
obj:set_hp(obj:get_hp() - damage)
|
||||
end
|
||||
end
|
||||
|
||||
-- register arrow for shoot attack
|
||||
function mobs:register_arrow(name, def)
|
||||
if not name or not def then return end -- errorcheck
|
||||
|
@ -1569,28 +1629,6 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso,
|
|||
end
|
||||
end
|
||||
|
||||
-- should mob follow what I'm holding ?
|
||||
function follow_holding(self, clicker)
|
||||
local item = clicker:get_wielded_item()
|
||||
local t = type(self.follow)
|
||||
|
||||
-- single item
|
||||
if t == "string"
|
||||
and item:get_name() == self.follow then
|
||||
return true
|
||||
|
||||
-- multiple items
|
||||
elseif t == "table" then
|
||||
for no = 1, #self.follow do
|
||||
if self.follow[no] == item:get_name() then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- feeding, taming and breeding (thanks blert2112)
|
||||
function mobs:feed_tame(self, clicker, feed_count, breed, tame)
|
||||
|
||||
|
@ -1654,29 +1692,3 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
|
|||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- check if within map limits (-30911 to 30927)
|
||||
function within_limits(pos, radius)
|
||||
if (pos.x - radius) > -30913
|
||||
and (pos.x + radius) < 30928
|
||||
and (pos.y - radius) > -30913
|
||||
and (pos.y + radius) < 30928
|
||||
and (pos.z - radius) > -30913
|
||||
and (pos.z + radius) < 30928 then
|
||||
return true -- within limits
|
||||
end
|
||||
return false -- beyond limits
|
||||
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
|
||||
|
|
|
@ -5,6 +5,7 @@ mobs:register_mob("mobs:pumba", {
|
|||
type = "animal",
|
||||
passive = false,
|
||||
attack_type = "dogfight",
|
||||
group_attack = true,
|
||||
reach = 2,
|
||||
damage = 2,
|
||||
hp_min = 5,
|
||||
|
|
Loading…
Reference in New Issue