Part 2
This commit is contained in:
parent
5d393e912b
commit
099b793c63
|
@ -101,7 +101,8 @@ end
|
||||||
|
|
||||||
function boat.on_activate(self, staticdata, dtime_s)
|
function boat.on_activate(self, staticdata, dtime_s)
|
||||||
|
|
||||||
if mobs and mobs.entity and mobs.entity == false then
|
if (mobs and mobs.entity and mobs.entity == false)
|
||||||
|
or not self then
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
|
@ -91,8 +91,8 @@ for _, col in pairs(all_colours) do
|
||||||
if itemname == "mobs:shears" then
|
if itemname == "mobs:shears" then
|
||||||
|
|
||||||
if self.gotten ~= false
|
if self.gotten ~= false
|
||||||
and self.child ~= false
|
or self.child ~= false
|
||||||
and not minetest.get_modpath("wool") then
|
or not minetest.get_modpath("wool") then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
|
||||||
-- Mobs Api (23rd May 2016)
|
-- Mobs Api (5th August 2016)
|
||||||
|
|
||||||
mobs = {}
|
mobs = {}
|
||||||
mobs.mod = "redo"
|
mobs.mod = "redo"
|
||||||
|
|
||||||
|
-- Invisibility mod
|
||||||
|
local invisibility = invisibility or {}
|
||||||
|
|
||||||
-- Load settings
|
-- Load settings
|
||||||
local damage_enabled = minetest.setting_getbool("enable_damage")
|
local damage_enabled = minetest.setting_getbool("enable_damage")
|
||||||
local peaceful_only = minetest.setting_getbool("only_peaceful_mobs")
|
local peaceful_only = minetest.setting_getbool("only_peaceful_mobs")
|
||||||
|
@ -18,18 +21,23 @@ local enable_pathfinding = true
|
||||||
local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching
|
local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching
|
||||||
local stuck_path_timeout = 10 -- how long will mob follow path before giving up
|
local stuck_path_timeout = 10 -- how long will mob follow path before giving up
|
||||||
|
|
||||||
-- internal functions
|
-- localize functions
|
||||||
|
|
||||||
local pi = math.pi
|
local pi = math.pi
|
||||||
local square = math.sqrt
|
local square = math.sqrt
|
||||||
|
local sin = math.sin
|
||||||
|
local cos = math.cos
|
||||||
|
local abs = math.abs
|
||||||
|
local atann = math.atan
|
||||||
|
local random = math.random
|
||||||
|
local floor = math.floor
|
||||||
local atan = function(x)
|
local atan = function(x)
|
||||||
|
|
||||||
if x ~= x then
|
if x ~= x then
|
||||||
--error("atan bassed NaN")
|
--error("atan bassed NaN")
|
||||||
print ("atan based NaN")
|
--print ("atan based NaN")
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
return math.atan(x)
|
return atann(x)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -37,7 +45,7 @@ do_attack = function(self, player)
|
||||||
|
|
||||||
if self.state ~= "attack" then
|
if self.state ~= "attack" then
|
||||||
|
|
||||||
if math.random(0,100) < 90
|
if random(0,100) < 90
|
||||||
and self.sounds.war_cry then
|
and self.sounds.war_cry then
|
||||||
|
|
||||||
minetest.sound_play(self.sounds.war_cry,{
|
minetest.sound_play(self.sounds.war_cry,{
|
||||||
|
@ -53,14 +61,12 @@ end
|
||||||
|
|
||||||
set_velocity = function(self, v)
|
set_velocity = function(self, v)
|
||||||
|
|
||||||
v = v or 0
|
local yaw = self.object:getyaw() + self.rotate or 0
|
||||||
|
|
||||||
local yaw = (self.object:getyaw() + self.rotate) or 0
|
|
||||||
|
|
||||||
self.object:setvelocity({
|
self.object:setvelocity({
|
||||||
x = math.sin(yaw) * -v,
|
x = sin(yaw) * -v,
|
||||||
y = self.object:getvelocity().y,
|
y = self.object:getvelocity().y,
|
||||||
z = math.cos(yaw) * v
|
z = cos(yaw) * v
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -161,7 +167,7 @@ set_animation = function(self, type)
|
||||||
(self.animation.speed_shoot or self.animation.speed_normal), 0)
|
(self.animation.speed_shoot or self.animation.speed_normal), 0)
|
||||||
|
|
||||||
self.animation.current = "shoot"
|
self.animation.current = "shoot"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -187,6 +193,17 @@ function line_of_sight_water(self, pos1, pos2, stepsize)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- just incase we have a special node for flying/swimming mobs
|
||||||
|
elseif s == false
|
||||||
|
and self.fly
|
||||||
|
and self.fly_in then
|
||||||
|
|
||||||
|
local nod = minetest.get_node(pos_w).name
|
||||||
|
|
||||||
|
if nod == self.fly_in then
|
||||||
|
return true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -221,15 +238,15 @@ function update_tag(self)
|
||||||
local col = "#00FF00"
|
local col = "#00FF00"
|
||||||
local qua = self.hp_max / 4
|
local qua = self.hp_max / 4
|
||||||
|
|
||||||
if self.health <= math.floor(qua * 3) then
|
if self.health <= floor(qua * 3) then
|
||||||
col = "#FFFF00"
|
col = "#FFFF00"
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.health <= math.floor(qua * 2) then
|
if self.health <= floor(qua * 2) then
|
||||||
col = "#FF6600"
|
col = "#FF6600"
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.health <= math.floor(qua) then
|
if self.health <= floor(qua) then
|
||||||
col = "#FF0000"
|
col = "#FF0000"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -267,6 +284,15 @@ function check_for_death(self)
|
||||||
self.health = self.hp_max
|
self.health = self.hp_max
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- backup nametag so we can show health stats
|
||||||
|
if not self.nametag2 then
|
||||||
|
self.nametag2 = self.nametag or ""
|
||||||
|
end
|
||||||
|
|
||||||
|
self.htimer = 2
|
||||||
|
|
||||||
|
self.nametag = "health: " .. self.health .. " of " .. self.hp_max
|
||||||
|
|
||||||
update_tag(self)
|
update_tag(self)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -276,20 +302,20 @@ function check_for_death(self)
|
||||||
local obj
|
local obj
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:getpos()
|
||||||
|
|
||||||
for _,drop in pairs(self.drops) do
|
for n = 1, #self.drops do
|
||||||
|
|
||||||
if math.random(1, drop.chance) == 1 then
|
if random(1, self.drops[n].chance) == 1 then
|
||||||
|
|
||||||
obj = minetest.add_item(pos,
|
obj = minetest.add_item(pos,
|
||||||
ItemStack(drop.name .. " "
|
ItemStack(self.drops[n].name .. " "
|
||||||
.. math.random(drop.min, drop.max)))
|
.. random(self.drops[n].min, self.drops[n].max)))
|
||||||
|
|
||||||
if obj then
|
if obj then
|
||||||
|
|
||||||
obj:setvelocity({
|
obj:setvelocity({
|
||||||
x = math.random(-1, 1),
|
x = random(-10, 10) / 9,
|
||||||
y = 6,
|
y = 5,
|
||||||
z = math.random(-1, 1)
|
z = random(-10, 10) / 9,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -333,13 +359,13 @@ end
|
||||||
-- is mob facing a cliff
|
-- is mob facing a cliff
|
||||||
local function is_at_cliff(self)
|
local function is_at_cliff(self)
|
||||||
|
|
||||||
if self.fear_height == 0 then -- if 0, no falling protection!
|
if self.fear_height == 0 then -- 0 for no falling protection!
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local yaw = self.object:getyaw()
|
local yaw = self.object:getyaw()
|
||||||
local dir_x = -math.sin(yaw) * (self.collisionbox[4] + 0.5)
|
local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5)
|
||||||
local dir_z = math.cos(yaw) * (self.collisionbox[4] + 0.5)
|
local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5)
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:getpos()
|
||||||
local ypos = pos.y + self.collisionbox[2] -- just above floor
|
local ypos = pos.y + self.collisionbox[2] -- just above floor
|
||||||
|
|
||||||
|
@ -380,6 +406,15 @@ do_env_damage = function(self)
|
||||||
self.htimer = self.htimer - 1
|
self.htimer = self.htimer - 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- reset nametag after showing health stats
|
||||||
|
if self.htimer < 1 and self.nametag2 then
|
||||||
|
|
||||||
|
self.nametag = self.nametag2
|
||||||
|
self.nametag2 = nil
|
||||||
|
|
||||||
|
update_tag(self)
|
||||||
|
end
|
||||||
|
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:getpos()
|
||||||
|
|
||||||
self.time_of_day = minetest.get_timeofday()
|
self.time_of_day = minetest.get_timeofday()
|
||||||
|
@ -461,8 +496,8 @@ do_jump = function(self)
|
||||||
|
|
||||||
-- where is front
|
-- where is front
|
||||||
local yaw = self.object:getyaw()
|
local yaw = self.object:getyaw()
|
||||||
local dir_x = -math.sin(yaw) * (self.collisionbox[4] + 0.5)
|
local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5)
|
||||||
local dir_z = math.cos(yaw) * (self.collisionbox[4] + 0.5)
|
local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5)
|
||||||
|
|
||||||
-- what is in front of mob?
|
-- what is in front of mob?
|
||||||
local nod = node_ok({
|
local nod = node_ok({
|
||||||
|
@ -486,8 +521,6 @@ do_jump = function(self)
|
||||||
local v = self.object:getvelocity()
|
local v = self.object:getvelocity()
|
||||||
|
|
||||||
v.y = self.jump_height + 1
|
v.y = self.jump_height + 1
|
||||||
v.x = v.x * 2.2
|
|
||||||
v.z = v.z * 2.2
|
|
||||||
|
|
||||||
self.object:setvelocity(v)
|
self.object:setvelocity(v)
|
||||||
|
|
||||||
|
@ -523,21 +556,22 @@ function entity_physics(pos, radius)
|
||||||
local objs = minetest.get_objects_inside_radius(pos, radius)
|
local objs = minetest.get_objects_inside_radius(pos, radius)
|
||||||
local obj_pos, dist
|
local obj_pos, dist
|
||||||
|
|
||||||
for _, obj in pairs(objs) do
|
for n = 1, #objs do
|
||||||
|
|
||||||
obj_pos = obj:getpos()
|
obj_pos = objs[n]:getpos()
|
||||||
|
|
||||||
dist = math.max(1, get_distance(pos, obj_pos))
|
dist = get_distance(pos, obj_pos)
|
||||||
|
if dist < 1 then dist = 1 end
|
||||||
|
|
||||||
local damage = math.floor((4 / dist) * radius)
|
local damage = floor((4 / dist) * radius)
|
||||||
local ent = obj:get_luaentity()
|
local ent = objs[n]:get_luaentity()
|
||||||
|
|
||||||
if obj:is_player() then
|
if objs[n]:is_player() then
|
||||||
obj:set_hp(obj:get_hp() - damage)
|
objs[n]:set_hp(objs[n]:get_hp() - damage)
|
||||||
|
|
||||||
else --if ent.health then
|
else --if ent.health then
|
||||||
|
|
||||||
obj:punch(obj, 1.0, {
|
objs[n]:punch(objs[n], 1.0, {
|
||||||
full_punch_interval = 1.0,
|
full_punch_interval = 1.0,
|
||||||
damage_groups = {fleshy = damage},
|
damage_groups = {fleshy = damage},
|
||||||
}, nil)
|
}, nil)
|
||||||
|
@ -549,6 +583,10 @@ end
|
||||||
-- should mob follow what I'm holding ?
|
-- should mob follow what I'm holding ?
|
||||||
function follow_holding(self, clicker)
|
function follow_holding(self, clicker)
|
||||||
|
|
||||||
|
if invisibility[clicker:get_player_name()] then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
local item = clicker:get_wielded_item()
|
local item = clicker:get_wielded_item()
|
||||||
local t = type(self.follow)
|
local t = type(self.follow)
|
||||||
|
|
||||||
|
@ -621,15 +659,15 @@ local function breed(self)
|
||||||
|
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:getpos()
|
||||||
|
|
||||||
--effect({x = pos.x, y = pos.y + 1, z = pos.z}, 4, "heart.png")
|
effect({x = pos.x, y = pos.y + 1, z = pos.z}, 4, "heart.png")
|
||||||
|
|
||||||
local ents = minetest.get_objects_inside_radius(pos, 3)
|
local objs = minetest.get_objects_inside_radius(pos, 3)
|
||||||
local num = 0
|
local num = 0
|
||||||
local ent = nil
|
local ent = nil
|
||||||
|
|
||||||
for i, obj in pairs(ents) do
|
for n = 1, #objs do
|
||||||
|
|
||||||
ent = obj:get_luaentity()
|
ent = objs[n]:get_luaentity()
|
||||||
|
|
||||||
-- check for same animal with different colour
|
-- check for same animal with different colour
|
||||||
local canmate = false
|
local canmate = false
|
||||||
|
@ -680,16 +718,16 @@ local function breed(self)
|
||||||
mob:set_properties({
|
mob:set_properties({
|
||||||
textures = textures,
|
textures = textures,
|
||||||
visual_size = {
|
visual_size = {
|
||||||
x = self.base_size.x / 2,
|
x = self.base_size.x * .5,
|
||||||
y = self.base_size.y / 2
|
y = self.base_size.y * .5,
|
||||||
},
|
},
|
||||||
collisionbox = {
|
collisionbox = {
|
||||||
self.base_colbox[1] / 2,
|
self.base_colbox[1] * .5,
|
||||||
self.base_colbox[2] / 2,
|
self.base_colbox[2] * .5,
|
||||||
self.base_colbox[3] / 2,
|
self.base_colbox[3] * .5,
|
||||||
self.base_colbox[4] / 2,
|
self.base_colbox[4] * .5,
|
||||||
self.base_colbox[5] / 2,
|
self.base_colbox[5] * .5,
|
||||||
self.base_colbox[6] / 2
|
self.base_colbox[6] * .5,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
ent2.child = true
|
ent2.child = true
|
||||||
|
@ -710,7 +748,7 @@ function replace(self, pos)
|
||||||
|
|
||||||
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 random(1, self.replace_rate) == 1 then
|
||||||
|
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:getpos()
|
||||||
|
|
||||||
|
@ -755,7 +793,7 @@ function smart_mobs(self, s, p, dist, dtime)
|
||||||
local s1 = self.path.lastpos
|
local s1 = self.path.lastpos
|
||||||
|
|
||||||
-- is it becoming stuck?
|
-- is it becoming stuck?
|
||||||
if math.abs(s1.x - s.x) + math.abs(s1.z - s.z) < 1.5 then
|
if abs(s1.x - s.x) + abs(s1.z - s.z) < 1.5 then
|
||||||
self.path.stuck_timer = self.path.stuck_timer + dtime
|
self.path.stuck_timer = self.path.stuck_timer + dtime
|
||||||
else
|
else
|
||||||
self.path.stuck_timer = 0
|
self.path.stuck_timer = 0
|
||||||
|
@ -776,9 +814,9 @@ function smart_mobs(self, s, p, dist, dtime)
|
||||||
|
|
||||||
-- round position to center of node to avoid stuck in walls
|
-- round position to center of node to avoid stuck in walls
|
||||||
-- also adjust height for player models!
|
-- also adjust height for player models!
|
||||||
s.x = math.floor(s.x + 0.5)
|
s.x = floor(s.x + 0.5)
|
||||||
s.y = math.floor(s.y + 0.5) - sheight
|
s.y = floor(s.y + 0.5) - sheight
|
||||||
s.z = math.floor(s.z + 0.5)
|
s.z = floor(s.z + 0.5)
|
||||||
|
|
||||||
local ssight, sground
|
local ssight, sground
|
||||||
ssight, sground = minetest.line_of_sight(s, {
|
ssight, sground = minetest.line_of_sight(s, {
|
||||||
|
@ -791,17 +829,17 @@ function smart_mobs(self, s, p, dist, dtime)
|
||||||
|
|
||||||
local p1 = self.attack:getpos()
|
local p1 = self.attack:getpos()
|
||||||
|
|
||||||
p1.x = math.floor(p1.x + 0.5)
|
p1.x = floor(p1.x + 0.5)
|
||||||
p1.y = math.floor(p1.y + 0.5)
|
p1.y = floor(p1.y + 0.5)
|
||||||
p1.z = math.floor(p1.z + 0.5)
|
p1.z = floor(p1.z + 0.5)
|
||||||
|
|
||||||
self.path.way = minetest.find_path(s, p1, 16, 2, 6, "Dijkstra") --"A*_noprefetch")
|
self.path.way = minetest.find_path(s, p1, 16, 2, 6, "Dijkstra") --"A*_noprefetch")
|
||||||
|
|
||||||
-- attempt to unstick mob that is "daydreaming"
|
-- attempt to unstick mob that is "daydreaming"
|
||||||
self.object:setpos({
|
self.object:setpos({
|
||||||
x = s.x + 0.1 * (math.random() * 2 - 1),
|
x = s.x + 0.1 * (random() * 2 - 1),
|
||||||
y = s.y + 1,
|
y = s.y + 1,
|
||||||
z = s.z + 0.1 * (math.random() * 2 - 1)
|
z = s.z + 0.1 * (random() * 2 - 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
self.state = ""
|
self.state = ""
|
||||||
|
@ -847,9 +885,9 @@ function smart_mobs(self, s, p, dist, dtime)
|
||||||
local yaw1 = self.object:getyaw() + pi / 2
|
local yaw1 = self.object:getyaw() + pi / 2
|
||||||
|
|
||||||
local p1 = {
|
local p1 = {
|
||||||
x = s.x + math.cos(yaw1),
|
x = s.x + cos(yaw1),
|
||||||
y = s.y,
|
y = s.y,
|
||||||
z = s.z + math.sin(yaw1)
|
z = s.z + sin(yaw1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if not minetest.is_protected(p1, "") then
|
if not minetest.is_protected(p1, "") then
|
||||||
|
@ -919,15 +957,21 @@ local monster_attack = function(self)
|
||||||
local p, sp, dist
|
local p, sp, dist
|
||||||
local player, type, obj, min_player = nil, nil, nil, nil
|
local player, type, obj, min_player = nil, nil, nil, nil
|
||||||
local min_dist = self.view_range + 1
|
local min_dist = self.view_range + 1
|
||||||
|
local objs = minetest.get_objects_inside_radius(s, self.view_range)
|
||||||
|
|
||||||
for _,oir in pairs(minetest.get_objects_inside_radius(s, self.view_range)) do
|
for n = 1, #objs do
|
||||||
|
|
||||||
if oir:is_player() then
|
if objs[n]:is_player() then
|
||||||
|
|
||||||
player = oir
|
if invisibility[ objs[n]:get_player_name() ] then
|
||||||
type = "player"
|
|
||||||
|
type = ""
|
||||||
|
else
|
||||||
|
player = objs[n]
|
||||||
|
type = "player"
|
||||||
|
end
|
||||||
else
|
else
|
||||||
obj = oir:get_luaentity()
|
obj = objs[n]:get_luaentity()
|
||||||
|
|
||||||
if obj then
|
if obj then
|
||||||
player = obj.object
|
player = obj.object
|
||||||
|
@ -952,7 +996,6 @@ local monster_attack = function(self)
|
||||||
-- field of view check goes here
|
-- field of view check goes here
|
||||||
|
|
||||||
-- choose closest player to attack
|
-- choose closest player to attack
|
||||||
--if minetest.line_of_sight(sp, p, 2) == true
|
|
||||||
if line_of_sight_water(self, sp, p, 2) == true
|
if line_of_sight_water(self, sp, p, 2) == true
|
||||||
and dist < min_dist then
|
and dist < min_dist then
|
||||||
min_dist = dist
|
min_dist = dist
|
||||||
|
@ -980,10 +1023,11 @@ local npc_attack = function(self)
|
||||||
local s = self.object:getpos()
|
local s = self.object:getpos()
|
||||||
local min_dist = self.view_range + 1
|
local min_dist = self.view_range + 1
|
||||||
local obj, min_player = nil, nil
|
local obj, min_player = nil, nil
|
||||||
|
local objs = minetest.get_objects_inside_radius(s, self.view_range)
|
||||||
|
|
||||||
for _, oir in pairs(minetest.get_objects_inside_radius(s, self.view_range)) do
|
for n = 1, #objs do
|
||||||
|
|
||||||
obj = oir:get_luaentity()
|
obj = objs[n]:get_luaentity()
|
||||||
|
|
||||||
if obj
|
if obj
|
||||||
and obj.type == "monster" then
|
and obj.type == "monster" then
|
||||||
|
@ -1014,16 +1058,16 @@ local follow_flop = function(self)
|
||||||
and self.state ~= "attack"
|
and self.state ~= "attack"
|
||||||
and self.state ~= "runaway" then
|
and self.state ~= "runaway" then
|
||||||
|
|
||||||
local s, p, dist
|
local s = self.object:getpos()
|
||||||
|
local players = minetest.get_connected_players()
|
||||||
|
|
||||||
for _,player in pairs(minetest.get_connected_players()) do
|
for n = 1, #players do
|
||||||
|
|
||||||
s = self.object:getpos()
|
if get_distance(players[n]:getpos(), s) < self.view_range
|
||||||
p = player:getpos()
|
and not invisibility[ players[n]:get_player_name() ] then
|
||||||
dist = get_distance(p, s)
|
|
||||||
|
self.following = players[n]
|
||||||
|
|
||||||
if dist < self.view_range then
|
|
||||||
self.following = player
|
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1079,18 +1123,14 @@ local follow_flop = function(self)
|
||||||
z = p.z - s.z
|
z = p.z - s.z
|
||||||
}
|
}
|
||||||
|
|
||||||
if vec.x ~= 0
|
local yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate
|
||||||
and vec.z ~= 0 then
|
|
||||||
|
|
||||||
yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate
|
if p.x > s.x then
|
||||||
|
yaw = yaw + pi
|
||||||
if p.x > s.x then
|
|
||||||
yaw = yaw + pi
|
|
||||||
end
|
|
||||||
|
|
||||||
self.object:setyaw(yaw)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self.object:setyaw(yaw)
|
||||||
|
|
||||||
-- anyone but standing npc's can move along
|
-- anyone but standing npc's can move along
|
||||||
if dist > self.reach
|
if dist > self.reach
|
||||||
and self.order ~= "stand" then
|
and self.order ~= "stand" then
|
||||||
|
@ -1165,19 +1205,19 @@ local do_states = function(self, dtime)
|
||||||
|
|
||||||
if self.state == "stand" then
|
if self.state == "stand" then
|
||||||
|
|
||||||
if math.random(1, 4) == 1 then
|
if random(1, 4) == 1 then
|
||||||
|
|
||||||
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 objs = minetest.get_objects_inside_radius(s, 3)
|
||||||
|
|
||||||
for _,o in pairs(o) do
|
for n = 1, #objs do
|
||||||
|
|
||||||
if o:is_player() then
|
if objs[n]:is_player() then
|
||||||
lp = o:getpos()
|
lp = objs[n]:getpos()
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1192,17 +1232,13 @@ local do_states = function(self, dtime)
|
||||||
z = lp.z - s.z
|
z = lp.z - s.z
|
||||||
}
|
}
|
||||||
|
|
||||||
if vec.x ~= 0
|
yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate
|
||||||
and vec.z ~= 0 then
|
|
||||||
|
|
||||||
yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate
|
if lp.x > s.x then
|
||||||
|
yaw = yaw + pi
|
||||||
if lp.x > s.x then
|
|
||||||
yaw = yaw + pi
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
yaw = (math.random(0, 360) - 180) / 180 * pi
|
yaw = (random(0, 360) - 180) / 180 * pi
|
||||||
end
|
end
|
||||||
|
|
||||||
self.object:setyaw(yaw)
|
self.object:setyaw(yaw)
|
||||||
|
@ -1216,7 +1252,7 @@ local do_states = function(self, dtime)
|
||||||
or self.order ~= "stand" then
|
or self.order ~= "stand" then
|
||||||
|
|
||||||
if self.walk_chance ~= 0
|
if self.walk_chance ~= 0
|
||||||
and math.random(1, 100) <= self.walk_chance
|
and random(1, 100) <= self.walk_chance
|
||||||
and is_at_cliff(self) == false then
|
and is_at_cliff(self) == false then
|
||||||
|
|
||||||
set_velocity(self, self.walk_velocity)
|
set_velocity(self, self.walk_velocity)
|
||||||
|
@ -1228,9 +1264,24 @@ local do_states = function(self, dtime)
|
||||||
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 = nil
|
||||||
|
|
||||||
-- if water nearby then turn away
|
-- is there something I need to avoid?
|
||||||
|
if self.water_damage > 0
|
||||||
|
and self.lava_damage > 0 then
|
||||||
|
|
||||||
|
lp = minetest.find_node_near(s, 1, {"group:water", "group:lava"})
|
||||||
|
|
||||||
|
elseif self.water_damage > 0 then
|
||||||
|
|
||||||
|
lp = minetest.find_node_near(s, 1, {"group:water"})
|
||||||
|
|
||||||
|
elseif self.lava_damage > 0 then
|
||||||
|
|
||||||
|
lp = minetest.find_node_near(s, 1, {"group:lava"})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- if something then avoid
|
||||||
if lp then
|
if lp then
|
||||||
|
|
||||||
local vec = {
|
local vec = {
|
||||||
|
@ -1239,22 +1290,18 @@ local do_states = function(self, dtime)
|
||||||
z = lp.z - s.z
|
z = lp.z - s.z
|
||||||
}
|
}
|
||||||
|
|
||||||
if vec.x ~= 0
|
yaw = atan(vec.z / vec.x) + 3 * pi / 2 - self.rotate
|
||||||
and vec.z ~= 0 then
|
|
||||||
|
|
||||||
yaw = atan(vec.z / vec.x) + 3 * pi / 2 - self.rotate
|
if lp.x > s.x then
|
||||||
|
yaw = yaw + pi
|
||||||
if lp.x > s.x then
|
|
||||||
yaw = yaw + pi
|
|
||||||
end
|
|
||||||
|
|
||||||
self.object:setyaw(yaw)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- otherwise randomly turn
|
self.object:setyaw(yaw)
|
||||||
elseif math.random(1, 100) <= 30 then
|
|
||||||
|
|
||||||
local yaw = (math.random(0, 360) - 180) / 180 * pi
|
-- otherwise randomly turn
|
||||||
|
elseif random(1, 100) <= 30 then
|
||||||
|
|
||||||
|
local yaw = (random(0, 360) - 180) / 180 * pi
|
||||||
|
|
||||||
self.object:setyaw(yaw)
|
self.object:setyaw(yaw)
|
||||||
end
|
end
|
||||||
|
@ -1272,7 +1319,7 @@ local do_states = function(self, dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
if temp_is_cliff
|
if temp_is_cliff
|
||||||
or math.random(1, 100) <= 30 then
|
or random(1, 100) <= 30 then
|
||||||
|
|
||||||
set_velocity(self, 0)
|
set_velocity(self, 0)
|
||||||
self.state = "stand"
|
self.state = "stand"
|
||||||
|
@ -1319,7 +1366,8 @@ local do_states = function(self, dtime)
|
||||||
if dist > self.view_range
|
if dist > self.view_range
|
||||||
or not self.attack
|
or not self.attack
|
||||||
or not self.attack:getpos()
|
or not self.attack:getpos()
|
||||||
or self.attack:get_hp() <= 0 then
|
or self.attack:get_hp() <= 0
|
||||||
|
or (self.attack:is_player() and invisibility[ self.attack:get_player_name() ]) then
|
||||||
|
|
||||||
--print(" ** stop attacking **", dist, self.view_range)
|
--print(" ** stop attacking **", dist, self.view_range)
|
||||||
self.state = "stand"
|
self.state = "stand"
|
||||||
|
@ -1341,18 +1389,14 @@ local do_states = function(self, dtime)
|
||||||
z = p.z - s.z
|
z = p.z - s.z
|
||||||
}
|
}
|
||||||
|
|
||||||
if vec.x ~= 0
|
yaw = atan(vec.z / vec.x) + pi / 2 - self.rotate
|
||||||
and vec.z ~= 0 then
|
|
||||||
|
|
||||||
yaw = atan(vec.z / vec.x) + pi / 2 - self.rotate
|
if p.x > s.x then
|
||||||
|
yaw = yaw + pi
|
||||||
if p.x > s.x then
|
|
||||||
yaw = yaw + pi
|
|
||||||
end
|
|
||||||
|
|
||||||
self.object:setyaw(yaw)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self.object:setyaw(yaw)
|
||||||
|
|
||||||
if dist > self.reach then
|
if dist > self.reach then
|
||||||
|
|
||||||
if not self.v_start then
|
if not self.v_start then
|
||||||
|
@ -1444,9 +1488,9 @@ local do_states = function(self, dtime)
|
||||||
|
|
||||||
local nod = node_ok(s)
|
local nod = node_ok(s)
|
||||||
local p1 = s
|
local p1 = s
|
||||||
local me_y = math.floor(p1.y)
|
local me_y = floor(p1.y)
|
||||||
local p2 = p
|
local p2 = p
|
||||||
local p_y = math.floor(p2.y + 1)
|
local p_y = floor(p2.y + 1)
|
||||||
local v = self.object:getvelocity()
|
local v = self.object:getvelocity()
|
||||||
|
|
||||||
if nod.name == self.fly_in then
|
if nod.name == self.fly_in then
|
||||||
|
@ -1507,7 +1551,7 @@ local do_states = function(self, dtime)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if math.abs(p1.x-s.x) + math.abs(p1.z - s.z) < 0.6 then
|
if abs(p1.x-s.x) + abs(p1.z - s.z) < 0.6 then
|
||||||
-- reached waypoint, remove it from queue
|
-- reached waypoint, remove it from queue
|
||||||
table.remove(self.path.way, 1)
|
table.remove(self.path.way, 1)
|
||||||
end
|
end
|
||||||
|
@ -1522,18 +1566,14 @@ local do_states = function(self, dtime)
|
||||||
z = p.z - s.z
|
z = p.z - s.z
|
||||||
}
|
}
|
||||||
|
|
||||||
if vec.x ~= 0
|
yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate
|
||||||
and vec.z ~= 0 then
|
|
||||||
|
|
||||||
yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate
|
if p.x > s.x then
|
||||||
|
yaw = yaw + pi
|
||||||
if p.x > s.x then
|
|
||||||
yaw = yaw + pi
|
|
||||||
end
|
|
||||||
|
|
||||||
self.object:setyaw(yaw)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self.object:setyaw(yaw)
|
||||||
|
|
||||||
-- move towards enemy if beyond mob reach
|
-- move towards enemy if beyond mob reach
|
||||||
if dist > self.reach then
|
if dist > self.reach then
|
||||||
|
|
||||||
|
@ -1584,7 +1624,7 @@ local do_states = function(self, dtime)
|
||||||
self.timer = 0
|
self.timer = 0
|
||||||
|
|
||||||
if self.double_melee_attack
|
if self.double_melee_attack
|
||||||
and math.random(1, 2) == 1 then
|
and random(1, 2) == 1 then
|
||||||
set_animation(self, "punch2")
|
set_animation(self, "punch2")
|
||||||
else
|
else
|
||||||
set_animation(self, "punch")
|
set_animation(self, "punch")
|
||||||
|
@ -1596,7 +1636,6 @@ local do_states = function(self, dtime)
|
||||||
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 line_of_sight_water(self, p2, s2) == true then
|
if line_of_sight_water(self, p2, s2) == true then
|
||||||
|
|
||||||
-- play attack sound
|
-- play attack sound
|
||||||
|
@ -1609,7 +1648,7 @@ local do_states = function(self, dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- punch player
|
-- punch player
|
||||||
self.attack:punch(self.object, 1.0, {
|
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}
|
||||||
}, nil)
|
}, nil)
|
||||||
|
@ -1620,7 +1659,7 @@ local do_states = function(self, dtime)
|
||||||
and self.timer > 1 then
|
and self.timer > 1 then
|
||||||
|
|
||||||
self.timer = 0
|
self.timer = 0
|
||||||
|
|
||||||
self.custom_attack(self, p)
|
self.custom_attack(self, p)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1640,23 +1679,19 @@ local do_states = function(self, dtime)
|
||||||
z = p.z - s.z
|
z = p.z - s.z
|
||||||
}
|
}
|
||||||
|
|
||||||
if vec.x ~= 0
|
yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate
|
||||||
and vec.z ~= 0 then
|
|
||||||
|
|
||||||
yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate
|
if p.x > s.x then
|
||||||
|
yaw = yaw + pi
|
||||||
if p.x > s.x then
|
|
||||||
yaw = yaw + pi
|
|
||||||
end
|
|
||||||
|
|
||||||
self.object:setyaw(yaw)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self.object:setyaw(yaw)
|
||||||
|
|
||||||
set_velocity(self, 0)
|
set_velocity(self, 0)
|
||||||
|
|
||||||
if self.shoot_interval
|
if self.shoot_interval
|
||||||
and self.timer > self.shoot_interval
|
and self.timer > self.shoot_interval
|
||||||
and math.random(1, 100) <= 60 then
|
and random(1, 100) <= 60 then
|
||||||
|
|
||||||
self.timer = 0
|
self.timer = 0
|
||||||
set_animation(self, "shoot")
|
set_animation(self, "shoot")
|
||||||
|
@ -1739,8 +1774,7 @@ local falling = function(self, pos)
|
||||||
|
|
||||||
if d > 5 then
|
if d > 5 then
|
||||||
|
|
||||||
--self.object:set_hp(self.object:get_hp() - math.floor(d - 5))
|
self.health = self.health - floor(d - 5)
|
||||||
self.health = self.health - math.floor(d - 5)
|
|
||||||
|
|
||||||
effect(pos, 5, "tnt_smoke.png")
|
effect(pos, 5, "tnt_smoke.png")
|
||||||
|
|
||||||
|
@ -1794,12 +1828,11 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- check for tool immunity or special damage
|
-- check for tool immunity or special damage
|
||||||
for _, no in pairs(self.immune_to) do
|
for n = 1, #self.immune_to do
|
||||||
|
|
||||||
if no[1] == weapon:get_name() then
|
if self.immune_to[n][1] == weapon:get_name() then
|
||||||
|
|
||||||
damage = no[2] or 0
|
|
||||||
|
|
||||||
|
damage = self.immune_to[n][2] or 0
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1814,14 +1847,14 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
if weapon:get_definition()
|
if weapon:get_definition()
|
||||||
and weapon:get_definition().tool_capabilities then
|
and weapon:get_definition().tool_capabilities then
|
||||||
|
|
||||||
weapon:add_wear(math.floor((punch_interval / 75) * 9000))
|
weapon:add_wear(floor((punch_interval / 75) * 9000))
|
||||||
hitter:set_wielded_item(weapon)
|
hitter:set_wielded_item(weapon)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- weapon sounds
|
-- weapon sounds
|
||||||
if weapon:get_definition().sounds ~= nil then
|
if weapon:get_definition().sounds ~= nil then
|
||||||
|
|
||||||
local s = math.random(0, #weapon:get_definition().sounds)
|
local s = random(0, #weapon:get_definition().sounds)
|
||||||
|
|
||||||
minetest.sound_play(weapon:get_definition().sounds[s], {
|
minetest.sound_play(weapon:get_definition().sounds[s], {
|
||||||
object = hitter,
|
object = hitter,
|
||||||
|
@ -1835,7 +1868,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- do damage
|
-- do damage
|
||||||
self.health = self.health - math.floor(damage)
|
self.health = self.health - floor(damage)
|
||||||
|
|
||||||
-- exit here if dead
|
-- exit here if dead
|
||||||
if check_for_death(self) then
|
if check_for_death(self) then
|
||||||
|
@ -1898,18 +1931,13 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
z = lp.z - s.z
|
z = lp.z - s.z
|
||||||
}
|
}
|
||||||
|
|
||||||
if vec.x ~= 0
|
local yaw = atan(vec.z / vec.x) + 3 * pi / 2 - self.rotate
|
||||||
and vec.z ~= 0 then
|
|
||||||
|
|
||||||
local yaw = atan(vec.z / vec.x) + 3 * pi / 2 - self.rotate
|
if lp.x > s.x then
|
||||||
|
yaw = yaw + pi
|
||||||
if lp.x > s.x then
|
|
||||||
yaw = yaw + pi
|
|
||||||
end
|
|
||||||
|
|
||||||
self.object:setyaw(yaw)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self.object:setyaw(yaw)
|
||||||
self.state = "runaway"
|
self.state = "runaway"
|
||||||
self.runaway_timer = 0
|
self.runaway_timer = 0
|
||||||
self.following = nil
|
self.following = nil
|
||||||
|
@ -1919,18 +1947,20 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
if self.passive == false
|
if self.passive == false
|
||||||
and self.state ~= "flop"
|
and self.state ~= "flop"
|
||||||
and self.child == false
|
and self.child == false
|
||||||
and hitter:get_player_name() ~= self.owner then
|
and hitter:get_player_name() ~= self.owner
|
||||||
|
and not invisibility[ hitter:get_player_name() ] then
|
||||||
|
|
||||||
-- attack whoever punched mob
|
-- attack whoever punched mob
|
||||||
self.state = ""
|
self.state = ""
|
||||||
do_attack(self, hitter)
|
do_attack(self, hitter)
|
||||||
|
|
||||||
-- alert others to the attack
|
-- alert others to the attack
|
||||||
|
local objs = minetest.get_objects_inside_radius(hitter:getpos(), self.view_range)
|
||||||
local obj = nil
|
local obj = nil
|
||||||
|
|
||||||
for _, oir in pairs(minetest.get_objects_inside_radius(hitter:getpos(), 5)) do
|
for n = 1, #objs do
|
||||||
|
|
||||||
obj = oir:get_luaentity()
|
obj = objs[n]:get_luaentity()
|
||||||
|
|
||||||
if obj then
|
if obj then
|
||||||
|
|
||||||
|
@ -1967,7 +1997,7 @@ local mob_activate = function(self, staticdata, dtime_s, def)
|
||||||
-- select random texture, set model and size
|
-- select random texture, set model and size
|
||||||
if not self.base_texture then
|
if not self.base_texture then
|
||||||
|
|
||||||
self.base_texture = def.textures[math.random(1, #def.textures)]
|
self.base_texture = def.textures[random(1, #def.textures)]
|
||||||
self.base_mesh = def.mesh
|
self.base_mesh = def.mesh
|
||||||
self.base_size = self.visual_size
|
self.base_size = self.visual_size
|
||||||
self.base_colbox = self.collisionbox
|
self.base_colbox = self.collisionbox
|
||||||
|
@ -1995,8 +2025,8 @@ local mob_activate = function(self, staticdata, dtime_s, def)
|
||||||
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 * .5,
|
||||||
y = self.base_size.y / 2
|
y = self.base_size.y * .5,
|
||||||
}
|
}
|
||||||
|
|
||||||
if def.child_texture then
|
if def.child_texture then
|
||||||
|
@ -2004,17 +2034,17 @@ local mob_activate = function(self, staticdata, dtime_s, def)
|
||||||
end
|
end
|
||||||
|
|
||||||
colbox = {
|
colbox = {
|
||||||
self.base_colbox[1] / 2,
|
self.base_colbox[1] * .5,
|
||||||
self.base_colbox[2] / 2,
|
self.base_colbox[2] * .5,
|
||||||
self.base_colbox[3] / 2,
|
self.base_colbox[3] * .5,
|
||||||
self.base_colbox[4] / 2,
|
self.base_colbox[4] * .5,
|
||||||
self.base_colbox[5] / 2,
|
self.base_colbox[5] * .5,
|
||||||
self.base_colbox[6] / 2
|
self.base_colbox[6] * .5
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.health == 0 then
|
if self.health == 0 then
|
||||||
self.health = math.random (self.hp_min, self.hp_max)
|
self.health = random (self.hp_min, self.hp_max)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- rnd: pathfinding init
|
-- rnd: pathfinding init
|
||||||
|
@ -2029,7 +2059,7 @@ local mob_activate = function(self, staticdata, dtime_s, def)
|
||||||
self.object:set_armor_groups({immortal = 1, fleshy = self.armor})
|
self.object:set_armor_groups({immortal = 1, fleshy = self.armor})
|
||||||
self.old_y = self.object:getpos().y
|
self.old_y = self.object:getpos().y
|
||||||
self.old_health = self.health
|
self.old_health = self.health
|
||||||
self.object:setyaw((math.random(0, 360) - 180) / 180 * pi)
|
self.object:setyaw((random(0, 360) - 180) / 180 * pi)
|
||||||
self.sounds.distance = self.sounds.distance or 10
|
self.sounds.distance = self.sounds.distance or 10
|
||||||
self.textures = textures
|
self.textures = textures
|
||||||
self.mesh = mesh
|
self.mesh = mesh
|
||||||
|
@ -2051,7 +2081,8 @@ local mob_step = function(self, dtime)
|
||||||
if self.type ~= "npc"
|
if self.type ~= "npc"
|
||||||
and not self.tamed
|
and not self.tamed
|
||||||
and self.state ~= "attack"
|
and self.state ~= "attack"
|
||||||
and remove_far ~= true then
|
and remove_far ~= true
|
||||||
|
and self.lifetimer < 20000 then
|
||||||
|
|
||||||
self.lifetimer = self.lifetimer - dtime
|
self.lifetimer = self.lifetimer - dtime
|
||||||
|
|
||||||
|
@ -2060,9 +2091,9 @@ local mob_step = function(self, dtime)
|
||||||
-- only despawn away from player
|
-- only despawn away from player
|
||||||
local objs = minetest.get_objects_inside_radius(pos, 15)
|
local objs = minetest.get_objects_inside_radius(pos, 15)
|
||||||
|
|
||||||
for _,oir in pairs(objs) do
|
for n = 1, #objs do
|
||||||
|
|
||||||
if oir:is_player() then
|
if objs[n]:is_player() then
|
||||||
|
|
||||||
self.lifetimer = 20
|
self.lifetimer = 20
|
||||||
|
|
||||||
|
@ -2097,7 +2128,11 @@ local mob_step = function(self, dtime)
|
||||||
|
|
||||||
-- run custom function (defined in mob lua file)
|
-- run custom function (defined in mob lua file)
|
||||||
if self.do_custom then
|
if self.do_custom then
|
||||||
self.do_custom(self, dtime)
|
|
||||||
|
-- when false skip going any further
|
||||||
|
if self.do_custom(self, dtime) == false then
|
||||||
|
return
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- attack timer
|
-- attack timer
|
||||||
|
@ -2122,7 +2157,7 @@ local mob_step = function(self, dtime)
|
||||||
|
|
||||||
-- mob plays random sound at times
|
-- mob plays random sound at times
|
||||||
if self.sounds.random
|
if self.sounds.random
|
||||||
and math.random(1, 100) == 1 then
|
and random(1, 100) == 1 then
|
||||||
|
|
||||||
minetest.sound_play(self.sounds.random, {
|
minetest.sound_play(self.sounds.random, {
|
||||||
object = self.object,
|
object = self.object,
|
||||||
|
@ -2208,7 +2243,7 @@ minetest.register_entity(name, {
|
||||||
fall_damage = def.fall_damage or 1,
|
fall_damage = def.fall_damage or 1,
|
||||||
fall_speed = def.fall_speed or -10, -- must be lower than -2 (default: -10)
|
fall_speed = def.fall_speed or -10, -- must be lower than -2 (default: -10)
|
||||||
drops = def.drops or {},
|
drops = def.drops or {},
|
||||||
armor = def.armor,
|
armor = def.armor or 100,
|
||||||
on_rightclick = def.on_rightclick,
|
on_rightclick = def.on_rightclick,
|
||||||
arrow = def.arrow,
|
arrow = def.arrow,
|
||||||
shoot_interval = def.shoot_interval,
|
shoot_interval = def.shoot_interval,
|
||||||
|
@ -2316,7 +2351,7 @@ end -- END mobs:register_mob function
|
||||||
-- global functions
|
-- global functions
|
||||||
|
|
||||||
function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
|
function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
|
||||||
interval, chance, active_object_count, min_height, max_height, day_toggle)
|
interval, chance, aoc, min_height, max_height, day_toggle)
|
||||||
|
|
||||||
-- chance override in minetest.conf for registered mob
|
-- chance override in minetest.conf for registered mob
|
||||||
local new_chance = tonumber(minetest.setting_get(name .. "_chance"))
|
local new_chance = tonumber(minetest.setting_get(name .. "_chance"))
|
||||||
|
@ -2342,11 +2377,12 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
|
||||||
chance = chance,
|
chance = chance,
|
||||||
catch_up = false,
|
catch_up = false,
|
||||||
|
|
||||||
action = function(pos, node, aoc, active_object_count_wider)
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
|
|
||||||
-- do not spawn if too many active entities in area
|
-- do not spawn if too many active entities in area
|
||||||
if active_object_count_wider > active_object_count
|
if active_object_count_wider >= aoc
|
||||||
or not mobs.spawning_mobs[name] then
|
or not mobs.spawning_mobs[name] then
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2374,9 +2410,9 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
|
||||||
-- only spawn away from player
|
-- only spawn away from player
|
||||||
local objs = minetest.get_objects_inside_radius(pos, 10)
|
local objs = minetest.get_objects_inside_radius(pos, 10)
|
||||||
|
|
||||||
for _,oir in pairs(objs) do
|
for n = 1, #objs do
|
||||||
|
|
||||||
if oir:is_player() then
|
if objs[n]:is_player() then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2433,6 +2469,24 @@ function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_o
|
||||||
chance, active_object_count, -31000, max_height, day_toggle)
|
chance, active_object_count, -31000, max_height, day_toggle)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- MarkBu's spawn function
|
||||||
|
function mobs:spawn(def)
|
||||||
|
|
||||||
|
local name = def.name
|
||||||
|
local nodes = def.nodes or {"group:soil", "group:stone"}
|
||||||
|
local neighbors = def.neighbors or {"air"}
|
||||||
|
local min_light = def.min_light or 0
|
||||||
|
local max_light = def.max_light or 15
|
||||||
|
local interval = def.interval or 30
|
||||||
|
local chance = def.chance or 5000
|
||||||
|
local active_object_count = def.active_object_count or 1
|
||||||
|
local min_height = def.min_height or -31000
|
||||||
|
local max_height = def.max_height or 31000
|
||||||
|
local day_toggle = def.day_toggle or nil
|
||||||
|
|
||||||
|
mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, interval,
|
||||||
|
chance, active_object_count, min_height, max_height, day_toggle)
|
||||||
|
end
|
||||||
-- set content id's
|
-- set content id's
|
||||||
local c_air = minetest.get_content_id("air")
|
local c_air = minetest.get_content_id("air")
|
||||||
local c_ignore = minetest.get_content_id("ignore")
|
local c_ignore = minetest.get_content_id("ignore")
|
||||||
|
@ -2498,7 +2552,7 @@ function mobs:explosion(pos, radius, fire, smoke, sound)
|
||||||
-- after effects
|
-- after effects
|
||||||
if fire > 0
|
if fire > 0
|
||||||
and (minetest.registered_nodes[n].groups.flammable
|
and (minetest.registered_nodes[n].groups.flammable
|
||||||
or math.random(1, 100) <= 30) then
|
or random(1, 100) <= 30) then
|
||||||
|
|
||||||
minetest.set_node(p, {name = "fire:basic_flame"})
|
minetest.set_node(p, {name = "fire:basic_flame"})
|
||||||
else
|
else
|
||||||
|
@ -2743,7 +2797,7 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso,
|
||||||
if chance == 0 then return end
|
if chance == 0 then return end
|
||||||
|
|
||||||
-- calculate chance.. add to inventory if successful?
|
-- calculate chance.. add to inventory if successful?
|
||||||
if math.random(1, 100) <= chance then
|
if random(1, 100) <= chance then
|
||||||
|
|
||||||
clicker:get_inventory():add_item("main", mobname)
|
clicker:get_inventory():add_item("main", mobname)
|
||||||
|
|
||||||
|
@ -2861,12 +2915,12 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
|
||||||
|
|
||||||
local tag = self.nametag or ""
|
local tag = self.nametag or ""
|
||||||
|
|
||||||
local formspec = "size[8,4]"
|
minetest.show_formspec(name, "mobs_nametag", "size[8,4]"
|
||||||
.. default.gui_bg
|
.. default.gui_bg
|
||||||
.. default.gui_bg_img
|
.. default.gui_bg_img
|
||||||
.. "field[0.5,1;7.5,0;name;Enter name:;" .. tag .. "]"
|
.. "field[0.5,1;7.5,0;name;Enter name:;" .. tag .. "]"
|
||||||
.. "button_exit[2.5,3.5;3,1;mob_rename;Rename]"
|
.. "button_exit[2.5,3.5;3,1;mob_rename;Rename]")
|
||||||
minetest.show_formspec(name, "mobs_nametag", formspec)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -1,65 +1,107 @@
|
||||||
|
|
||||||
|
sethome = {}
|
||||||
|
|
||||||
local homes_file = minetest.get_worldpath() .. "/homes"
|
local homes_file = minetest.get_worldpath() .. "/homes"
|
||||||
local homepos = {}
|
local homepos = {}
|
||||||
|
|
||||||
local function loadhomes()
|
local function loadhomes()
|
||||||
local input = io.open(homes_file, "r")
|
-- local input = io.open(homes_file, "r")
|
||||||
if input then
|
-- if input then
|
||||||
repeat
|
-- repeat
|
||||||
local x = input:read("*n")
|
-- local x = input:read("*n")
|
||||||
if x == nil then
|
-- if x == nil then
|
||||||
break
|
-- break
|
||||||
end
|
-- end
|
||||||
local y = input:read("*n")
|
-- local y = input:read("*n")
|
||||||
local z = input:read("*n")
|
-- local z = input:read("*n")
|
||||||
local name = input:read("*l")
|
-- local name = input:read("*l")
|
||||||
homepos[name:sub(2)] = {x = x, y = y, z = z}
|
-- homepos[name:sub(2)] = {x = x, y = y, z = z}
|
||||||
until input:read(0) == nil
|
-- until input:read(0) == nil
|
||||||
io.close(input)
|
-- io.close(input)
|
||||||
else
|
-- end
|
||||||
homepos = {}
|
local input, err = io.open(homes_file, "r")
|
||||||
end
|
if not input then
|
||||||
|
return minetest.log("info", "Could not load player homes file: " .. err)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Iterate over all stored positions in the format "x y z player" each line
|
||||||
|
for pos, name in input:read("*a"):gmatch("(%S+ %S+ %S+)%s([%w_-]+)[\r\n]") do
|
||||||
|
homepos[name] = minetest.string_to_pos(pos)
|
||||||
|
end
|
||||||
|
input:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
loadhomes()
|
loadhomes()
|
||||||
|
|
||||||
|
sethome.set = function(name, pos)
|
||||||
|
local player = minetest.get_player_by_name(name)
|
||||||
|
if not player or not pos then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local data = {}
|
||||||
|
local output, err = io.open(homes_file, "w")
|
||||||
|
if output then
|
||||||
|
homepos[name] = pos
|
||||||
|
for i, v in pairs(homepos) do
|
||||||
|
table.insert(data, string.format("%.1f %.1f %.1f %s\n", v.x, v.y, v.z, i))
|
||||||
|
end
|
||||||
|
output:write(table.concat(data))
|
||||||
|
io.close(output)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
minetest.log("action", "Unable to write to player homes file: " .. err)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
sethome.get = function(name)
|
||||||
|
return homepos[name]
|
||||||
|
end
|
||||||
|
|
||||||
|
sethome.go = function(name)
|
||||||
|
local player = minetest.get_player_by_name(name)
|
||||||
|
if player and homepos[name] then
|
||||||
|
player:setpos(homepos[name])
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
minetest.register_privilege("home", "Can use /sethome and /home")
|
minetest.register_privilege("home", "Can use /sethome and /home")
|
||||||
|
|
||||||
local changed = false
|
|
||||||
|
|
||||||
minetest.register_chatcommand("home", {
|
minetest.register_chatcommand("home", {
|
||||||
description = "Teleport you to your home point",
|
description = "Teleport you to your home point",
|
||||||
privs = {home=true},
|
privs = {home = true},
|
||||||
func = function(name)
|
func = function(name)
|
||||||
local player = minetest.get_player_by_name(name)
|
if sethome.go(name) then
|
||||||
if player == nil then
|
return true, "Teleported to home!"
|
||||||
-- just a check to prevent the server crashing
|
end
|
||||||
return false
|
return false, "Set a home using /sethome"
|
||||||
end
|
end,
|
||||||
if homepos[player:get_player_name()] then
|
|
||||||
player:setpos(homepos[player:get_player_name()])
|
|
||||||
minetest.chat_send_player(name, "Teleported to home!")
|
|
||||||
else
|
|
||||||
minetest.chat_send_player(name, "Set a home using /sethome")
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand("sethome", {
|
minetest.register_chatcommand("sethome", {
|
||||||
description = "Set your home point",
|
description = "Set your home point",
|
||||||
privs = {home=true},
|
privs = {home = true},
|
||||||
func = function(name)
|
func = function(name)
|
||||||
local player = minetest.get_player_by_name(name)
|
name = name or "" -- fallback to blank name if nil
|
||||||
local pos = player:getpos()
|
local player = minetest.get_player_by_name(name)
|
||||||
homepos[player:get_player_name()] = pos
|
if player and sethome.set(name, player:getpos()) then
|
||||||
minetest.chat_send_player(name, "Home set!")
|
return true, "Home set!"
|
||||||
changed = true
|
end
|
||||||
if changed then
|
return false, "Player not found!"
|
||||||
local output = io.open(homes_file, "w")
|
end,
|
||||||
for i, v in pairs(homepos) do
|
})
|
||||||
output:write(v.x.." "..v.y.." "..v.z.." "..i.."\n")
|
|
||||||
end
|
minetest.register_chatcommand("home set", {
|
||||||
io.close(output)
|
description = "Set your home point",
|
||||||
changed = false
|
privs = {home = true},
|
||||||
end
|
func = function(name)
|
||||||
end,
|
name = name or "" -- fallback to blank name if nil
|
||||||
|
local player = minetest.get_player_by_name(name)
|
||||||
|
if player and sethome.set(name, player:getpos()) then
|
||||||
|
return true, "Home set!"
|
||||||
|
end
|
||||||
|
return false, "Player not found!"
|
||||||
|
end,
|
||||||
})
|
})
|
Loading…
Reference in New Issue