luacheck and other improvements
This commit is contained in:
parent
a5cfaed843
commit
98600c87de
|
@ -1,5 +1,4 @@
|
||||||
local mob_class = mcl_mobs.mob_class
|
local mob_class = mcl_mobs.mob_class
|
||||||
local mob_class_meta = {__index = mcl_mobs.mob_class}
|
|
||||||
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
|
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
|
||||||
|
|
||||||
local PATHFINDING = "gowp"
|
local PATHFINDING = "gowp"
|
||||||
|
@ -152,19 +151,17 @@ function mob_class:mob_activate(staticdata, def, dtime)
|
||||||
|
|
||||||
self.base_selbox = self.base_selbox or self.selectionbox or self.base_colbox
|
self.base_selbox = self.base_selbox or self.selectionbox or self.base_colbox
|
||||||
|
|
||||||
local textures = self.base_texture
|
self.textures = self.gotten and def.gotten_texture or self.base_texture
|
||||||
local mesh = self.base_mesh
|
self.mesh = self.gotten and def.gotten_mesh or self.base_mesh
|
||||||
local vis_size = self.base_size
|
self.visual_size = self.base_size
|
||||||
local colbox = self.base_colbox
|
self.collisionbox = self.base_colbox
|
||||||
local selbox = self.base_selbox
|
self.selectionbox = self.base_selbox
|
||||||
|
|
||||||
if self.gotten == true and def.gotten_texture then textures = def.gotten_texture end
|
if self.child then
|
||||||
if self.gotten == true and def.gotten_mesh then mesh = def.gotten_mesh end
|
self.visual_size = { x = self.base_size.x * .5, y = self.base_size.y * .5 }
|
||||||
if self.child == true then
|
self.textures = def.child_texture and def.child_texture[1] or self.textures
|
||||||
vis_size = { x = self.base_size.x * .5, y = self.base_size.y * .5 }
|
|
||||||
if def.child_texture then textures = def.child_texture[1] end
|
|
||||||
|
|
||||||
colbox = {
|
self.collisionbox = {
|
||||||
self.base_colbox[1] * .5,
|
self.base_colbox[1] * .5,
|
||||||
self.base_colbox[2] * .5,
|
self.base_colbox[2] * .5,
|
||||||
self.base_colbox[3] * .5,
|
self.base_colbox[3] * .5,
|
||||||
|
@ -172,7 +169,7 @@ function mob_class:mob_activate(staticdata, def, dtime)
|
||||||
self.base_colbox[5] * .5,
|
self.base_colbox[5] * .5,
|
||||||
self.base_colbox[6] * .5
|
self.base_colbox[6] * .5
|
||||||
}
|
}
|
||||||
selbox = {
|
self.selectionbox = {
|
||||||
self.base_selbox[1] * .5,
|
self.base_selbox[1] * .5,
|
||||||
self.base_selbox[2] * .5,
|
self.base_selbox[2] * .5,
|
||||||
self.base_selbox[3] * .5,
|
self.base_selbox[3] * .5,
|
||||||
|
@ -182,8 +179,8 @@ function mob_class:mob_activate(staticdata, def, dtime)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.health == 0 then self.health = math.random(self.hp_min, self.hp_max) end
|
self.health = (self.health and self.health > 0 and self.health) or math.random(self.hp_min, self.hp_max)
|
||||||
if self.breath == nil then self.breath = self.breath_max end
|
self.breath = self.breath or self.breath_max
|
||||||
|
|
||||||
self.path = {}
|
self.path = {}
|
||||||
self.path.way = {} -- path to follow, table of positions
|
self.path.way = {} -- path to follow, table of positions
|
||||||
|
@ -206,14 +203,9 @@ function mob_class:mob_activate(staticdata, def, dtime)
|
||||||
self.old_y = self.object:get_pos().y
|
self.old_y = self.object:get_pos().y
|
||||||
self.old_health = self.health
|
self.old_health = self.health
|
||||||
self.sounds.distance = self.sounds.distance or 10
|
self.sounds.distance = self.sounds.distance or 10
|
||||||
self.textures = textures
|
self.standing_in = mcl_mobs.NODE_IGNORE
|
||||||
self.mesh = mesh
|
self.standing_on = mcl_mobs.NODE_IGNORE
|
||||||
self.collisionbox = colbox
|
self.standing_under = mcl_mobs.NODE_IGNORE
|
||||||
self.selectionbox = selbox
|
|
||||||
self.visual_size = vis_size
|
|
||||||
self.standing_in = NODE_IGNORE
|
|
||||||
self.standing_on = NODE_IGNORE
|
|
||||||
self.standing_under = NODE_IGNORE
|
|
||||||
self.standing_depth = 0
|
self.standing_depth = 0
|
||||||
self.state = self.state or "stand"
|
self.state = self.state or "stand"
|
||||||
self.jump_sound_cooloff = 0 -- used to prevent jump sound from being played too often in short time
|
self.jump_sound_cooloff = 0 -- used to prevent jump sound from being played too often in short time
|
||||||
|
@ -317,6 +309,7 @@ local function on_step_work(self, dtime, moveresult)
|
||||||
local player_in_active_range = self:player_in_active_range()
|
local player_in_active_range = self:player_in_active_range()
|
||||||
-- The following functions return true when the mob died and we should stop processing
|
-- The following functions return true when the mob died and we should stop processing
|
||||||
if self:check_suspend(player_in_active_range) then return end
|
if self:check_suspend(player_in_active_range) then return end
|
||||||
|
-- initializes self.acceleration:
|
||||||
if self:gravity_and_floating(pos, dtime, moveresult) then return end -- keep early, for gravity!
|
if self:gravity_and_floating(pos, dtime, moveresult) then return end -- keep early, for gravity!
|
||||||
if self:check_dying() then return end
|
if self:check_dying() then return end
|
||||||
if self:step_damage(dtime, pos) then return end
|
if self:step_damage(dtime, pos) then return end
|
||||||
|
@ -360,7 +353,7 @@ local function on_step_work(self, dtime, moveresult)
|
||||||
self:smooth_acceleration(dtime)
|
self:smooth_acceleration(dtime)
|
||||||
local cx, cz = self:collision()
|
local cx, cz = self:collision()
|
||||||
self.object:add_velocity(vector.new(cx, 0, cz))
|
self.object:add_velocity(vector.new(cx, 0, cz))
|
||||||
self:update_vel_acc(dtime)
|
self:update_vel_acc(dtime) -- applies self.acceleration
|
||||||
if mobs_debug then self:update_tag() end
|
if mobs_debug then self:update_tag() end
|
||||||
if not self.object:get_luaentity() then return false end
|
if not self.object:get_luaentity() then return false end
|
||||||
end
|
end
|
||||||
|
@ -398,8 +391,12 @@ function mob_class:on_step(dtime, moveresult)
|
||||||
-- allow crash in development mode
|
-- allow crash in development mode
|
||||||
if DEVELOPMENT then return on_step_work(self, dtime, moveresult) end
|
if DEVELOPMENT then return on_step_work(self, dtime, moveresult) end
|
||||||
-- Removed as bundled Lua (5.1 doesn't support xpcall)
|
-- Removed as bundled Lua (5.1 doesn't support xpcall)
|
||||||
--local status, retVal = xpcall(on_step_work, on_step_error_handler, self, dtime)
|
local status, retVal
|
||||||
local status, retVal = pcall(on_step_work, self, dtime, moveresult)
|
if xpcall then
|
||||||
|
status, retVal = xpcall(on_step_work, on_step_error_handler, self, dtime, moveresult)
|
||||||
|
else
|
||||||
|
status, retVal = pcall(on_step_work, self, dtime, moveresult)
|
||||||
|
end
|
||||||
if status then return retVal end
|
if status then return retVal end
|
||||||
warn_user_error()
|
warn_user_error()
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
@ -488,16 +485,16 @@ minetest.register_chatcommand("clearmobs", {
|
||||||
elseif mob_type == "passive" and o.type ~= "monster" and o.type ~= "npc" then
|
elseif mob_type == "passive" and o.type ~= "monster" and o.type ~= "npc" then
|
||||||
--minetest.log("Match - passive")
|
--minetest.log("Match - passive")
|
||||||
mob_match = true
|
mob_match = true
|
||||||
else
|
--else
|
||||||
--minetest.log("No match for type.")
|
-- minetest.log("No match for type.")
|
||||||
end
|
end
|
||||||
elseif mob_name and (o.name == mob_name or string.find(o.name, mob_name)) then
|
elseif mob_name and (o.name == mob_name or string.find(o.name, mob_name)) then
|
||||||
--minetest.log("Match - mob_name = ".. tostring(o.name))
|
--minetest.log("Match - mob_name = ".. tostring(o.name))
|
||||||
mob_match = true
|
mob_match = true
|
||||||
else
|
--else
|
||||||
--minetest.log("No match - o.type = ".. tostring(o.type))
|
-- minetest.log("No match - o.type = ".. tostring(o.type))
|
||||||
--minetest.log("No match - mob_name = ".. tostring(o.name))
|
-- minetest.log("No match - mob_name = ".. tostring(o.name))
|
||||||
--minetest.log("No match - mob_type = ".. tostring(mob_name))
|
-- minetest.log("No match - mob_type = ".. tostring(mob_name))
|
||||||
end
|
end
|
||||||
|
|
||||||
if mob_match then
|
if mob_match then
|
||||||
|
|
|
@ -5,7 +5,7 @@ local HORNY_TIME = 30
|
||||||
local HORNY_AGAIN_TIME = 30 -- was 300 or 15*20
|
local HORNY_AGAIN_TIME = 30 -- was 300 or 15*20
|
||||||
local CHILD_GROW_TIME = 60
|
local CHILD_GROW_TIME = 60
|
||||||
|
|
||||||
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false)
|
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager", false)
|
||||||
|
|
||||||
local LOG_MODULE = "[mcl_mobs]"
|
local LOG_MODULE = "[mcl_mobs]"
|
||||||
local function mcl_log (message)
|
local function mcl_log (message)
|
||||||
|
@ -29,18 +29,13 @@ end
|
||||||
|
|
||||||
-- feeding, taming and breeding (thanks blert2112)
|
-- feeding, taming and breeding (thanks blert2112)
|
||||||
function mob_class:feed_tame(clicker, feed_count, breed, tame, notake)
|
function mob_class:feed_tame(clicker, feed_count, breed, tame, notake)
|
||||||
if not self.follow then
|
if not self.follow then return false end
|
||||||
return false
|
if clicker:get_wielded_item():get_definition()._mcl_not_consumable then return false end
|
||||||
end
|
|
||||||
if clicker:get_wielded_item():get_definition()._mcl_not_consumable then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
-- can eat/tame with item in hand
|
-- can eat/tame with item in hand
|
||||||
if self.nofollow or self:follow_holding(clicker) then
|
if self.nofollow or self:follow_holding(clicker) then
|
||||||
local consume_food = false
|
local consume_food = false
|
||||||
|
|
||||||
-- tame if not still a baby
|
-- tame if not still a baby
|
||||||
|
|
||||||
if tame and not self.child then
|
if tame and not self.child then
|
||||||
if not self.owner or self.owner == "" then
|
if not self.owner or self.owner == "" then
|
||||||
self.tamed = true
|
self.tamed = true
|
||||||
|
@ -50,7 +45,6 @@ function mob_class:feed_tame(clicker, feed_count, breed, tame, notake)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- increase health
|
-- increase health
|
||||||
|
|
||||||
if self.health < self.hp_max and not consume_food then
|
if self.health < self.hp_max and not consume_food then
|
||||||
consume_food = true
|
consume_food = true
|
||||||
self.health = math.min(self.health + 4, self.hp_max)
|
self.health = math.min(self.health + 4, self.hp_max)
|
||||||
|
@ -58,15 +52,13 @@ function mob_class:feed_tame(clicker, feed_count, breed, tame, notake)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- make children grow quicker
|
-- make children grow quicker
|
||||||
|
if not consume_food and self.child then
|
||||||
if not consume_food and self.child == true then
|
|
||||||
consume_food = true
|
consume_food = true
|
||||||
-- deduct 10% of the time to adulthood
|
-- deduct 10% of the time to adulthood
|
||||||
self.hornytimer = self.hornytimer + ((CHILD_GROW_TIME - self.hornytimer) * 0.1)
|
self.hornytimer = self.hornytimer + ((CHILD_GROW_TIME - self.hornytimer) * 0.1)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- breed animals
|
-- breed animals
|
||||||
|
|
||||||
if breed and not consume_food and self.hornytimer == 0 and not self.horny then
|
if breed and not consume_food and self.hornytimer == 0 and not self.horny then
|
||||||
self.food = (self.food or 0) + 1
|
self.food = (self.food or 0) + 1
|
||||||
consume_food = true
|
consume_food = true
|
||||||
|
@ -102,24 +94,15 @@ end
|
||||||
-- Spawn a child
|
-- Spawn a child
|
||||||
function mcl_mobs.spawn_child(pos, mob_type)
|
function mcl_mobs.spawn_child(pos, mob_type)
|
||||||
local child = minetest.add_entity(pos, mob_type)
|
local child = minetest.add_entity(pos, mob_type)
|
||||||
if not child then
|
if not child then return end
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local ent = child:get_luaentity()
|
local ent = child:get_luaentity()
|
||||||
mcl_mobs.effect(pos, 15, "mcl_particles_smoke.png", 1, 2, 2, 15, 5)
|
|
||||||
|
|
||||||
ent.child = true
|
ent.child = true
|
||||||
|
mcl_mobs.effect(pos, 15, "mcl_particles_smoke.png", 1, 2, 2, 15, 5)
|
||||||
local textures
|
|
||||||
-- using specific child texture (if found)
|
|
||||||
if ent.child_texture then
|
|
||||||
textures = ent.child_texture[1]
|
|
||||||
end
|
|
||||||
|
|
||||||
-- and resize to half height
|
-- and resize to half height
|
||||||
child:set_properties({
|
child:set_properties({
|
||||||
textures = textures,
|
textures = ent.child_texture and ent.child_texture[1],
|
||||||
visual_size = {
|
visual_size = {
|
||||||
x = ent.base_size.x * .5,
|
x = ent.base_size.x * .5,
|
||||||
y = ent.base_size.y * .5,
|
y = ent.base_size.y * .5,
|
||||||
|
@ -151,16 +134,12 @@ end
|
||||||
|
|
||||||
-- find two animals of same type and breed if nearby and horny
|
-- find two animals of same type and breed if nearby and horny
|
||||||
function mob_class:check_breeding()
|
function mob_class:check_breeding()
|
||||||
|
|
||||||
--mcl_log("In breed function")
|
--mcl_log("In breed function")
|
||||||
-- child takes a long time before growing into adult
|
-- child takes a long time before growing into adult
|
||||||
if self.child == true then
|
if self.child == true then
|
||||||
|
|
||||||
-- When a child, hornytimer is used to count age until adulthood
|
-- When a child, hornytimer is used to count age until adulthood
|
||||||
self.hornytimer = self.hornytimer + 1
|
self.hornytimer = self.hornytimer + 1
|
||||||
|
|
||||||
if self.hornytimer >= CHILD_GROW_TIME then
|
if self.hornytimer >= CHILD_GROW_TIME then
|
||||||
|
|
||||||
self.child = false
|
self.child = false
|
||||||
self.hornytimer = 0
|
self.hornytimer = 0
|
||||||
|
|
||||||
|
@ -177,11 +156,7 @@ function mob_class:check_breeding()
|
||||||
self.on_grown(self)
|
self.on_grown(self)
|
||||||
else
|
else
|
||||||
-- jump when fully grown so as not to fall into ground
|
-- jump when fully grown so as not to fall into ground
|
||||||
self.object:set_velocity({
|
self.object:set_velocity(vector.new(0, self.jump_height, 0))
|
||||||
x = 0,
|
|
||||||
y = self.jump_height,
|
|
||||||
z = 0
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
self.animation = nil
|
self.animation = nil
|
||||||
|
@ -189,121 +164,79 @@ function mob_class:check_breeding()
|
||||||
self._current_animation = nil -- Mobs Redo does nothing otherwise
|
self._current_animation = nil -- Mobs Redo does nothing otherwise
|
||||||
self:set_animation(anim)
|
self:set_animation(anim)
|
||||||
end
|
end
|
||||||
|
|
||||||
return
|
return
|
||||||
else
|
end
|
||||||
-- horny animal can mate for HORNY_TIME seconds,
|
-- horny animal can mate for HORNY_TIME seconds,
|
||||||
-- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds
|
-- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds
|
||||||
if self.horny == true then
|
if self.horny == true then
|
||||||
self.hornytimer = self.hornytimer + 1
|
self.hornytimer = self.hornytimer + 1
|
||||||
|
|
||||||
if self.hornytimer >= HORNY_TIME + HORNY_AGAIN_TIME then
|
if self.hornytimer >= HORNY_TIME + HORNY_AGAIN_TIME then
|
||||||
self.hornytimer = 0
|
self.hornytimer = 0
|
||||||
self.horny = false
|
self.horny = false
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- find another same animal who is also horny and mate if nearby
|
-- find another same animal who is also horny and mate if nearby
|
||||||
if self.horny == true
|
if self.horny and self.hornytimer <= HORNY_TIME then
|
||||||
and self.hornytimer <= HORNY_TIME then
|
|
||||||
|
|
||||||
mcl_log("In breed function. All good. Do the magic.")
|
mcl_log("In breed function. All good. Do the magic.")
|
||||||
|
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
mcl_mobs.effect(vector.new(pos.x, pos.y + 1, pos.z), 8, "heart.png", 3, 4, 1, 0.1)
|
||||||
mcl_mobs.effect({x = pos.x, y = pos.y + 1, z = pos.z}, 8, "heart.png", 3, 4, 1, 0.1)
|
|
||||||
|
|
||||||
local objs = 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
|
|
||||||
|
|
||||||
for n = 1, #objs do
|
for n = 1, #objs do
|
||||||
|
local ent = objs[n]: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
|
||||||
|
|
||||||
if ent then
|
if ent then
|
||||||
|
|
||||||
if ent.name == self.name then
|
if ent.name == self.name then
|
||||||
canmate = true
|
canmate = true
|
||||||
else
|
else
|
||||||
local entname = string.split(ent.name,":")
|
local entname = string.split(ent.name,":")
|
||||||
local selfname = string.split(self.name,":")
|
local selfname = string.split(self.name,":")
|
||||||
|
|
||||||
if entname[1] == selfname[1] then
|
if entname[1] == selfname[1] then
|
||||||
entname = string.split(entname[2],"_")
|
entname = string.split(entname[2],"_")
|
||||||
selfname = string.split(selfname[2],"_")
|
selfname = string.split(selfname[2],"_")
|
||||||
|
|
||||||
if entname[1] == selfname[1] then
|
if entname[1] == selfname[1] then canmate = true end
|
||||||
canmate = true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if canmate then mcl_log("In breed function. Can mate.") end
|
if canmate then mcl_log("In breed function. Can mate.") end
|
||||||
|
if ent and canmate and ent.horny and ent.hornytimer <= HORNY_TIME then
|
||||||
if ent
|
|
||||||
and canmate == true
|
|
||||||
and ent.horny == true
|
|
||||||
and ent.hornytimer <= HORNY_TIME then
|
|
||||||
num = num + 1
|
num = num + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- found your mate? then have a baby
|
-- found your mate? then have a baby
|
||||||
if num > 1 then
|
if num > 1 then
|
||||||
|
|
||||||
self.hornytimer = HORNY_TIME + 1
|
self.hornytimer = HORNY_TIME + 1
|
||||||
ent.hornytimer = HORNY_TIME + 1
|
ent.hornytimer = HORNY_TIME + 1
|
||||||
|
|
||||||
-- spawn baby
|
-- spawn baby
|
||||||
|
|
||||||
|
|
||||||
minetest.after(5, function(parent1, parent2, pos)
|
minetest.after(5, function(parent1, parent2, pos)
|
||||||
if not parent1.object:get_luaentity() then
|
if not parent1.object:get_luaentity() then return end
|
||||||
return
|
if not parent2.object:get_luaentity() then return end
|
||||||
end
|
|
||||||
if not parent2.object:get_luaentity() then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
mcl_experience.throw_xp(pos, math.random(1, 7) + (parent1._luck or 0) + (parent2._luck or 0))
|
mcl_experience.throw_xp(pos, math.random(1, 7) + (parent1._luck or 0) + (parent2._luck or 0))
|
||||||
|
|
||||||
-- custom breed function
|
if parent1.on_breed and not parent1.on_breed(parent1, parent2) then return end
|
||||||
if parent1.on_breed then
|
pos = vector.round(pos)
|
||||||
-- when false, skip going any further
|
|
||||||
if parent1.on_breed(parent1, parent2) == false then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local child = mcl_mobs.spawn_child(pos, parent1.name)
|
local child = mcl_mobs.spawn_child(pos, parent1.name)
|
||||||
if not child then return end
|
if not child then return end
|
||||||
|
|
||||||
local ent_c = child:get_luaentity()
|
local ent_c = child:get_luaentity()
|
||||||
|
|
||||||
|
|
||||||
-- Use texture of one of the parents
|
-- Use texture of one of the parents
|
||||||
local p = math.random(1, 2)
|
ent_c.base_texture = math.random(1, 2) == 1 and parent1.base_texture or parent2.base_texture
|
||||||
if p == 1 then
|
child:set_properties({ textures = ent_c.base_texture })
|
||||||
ent_c.base_texture = parent1.base_texture
|
|
||||||
else
|
|
||||||
ent_c.base_texture = parent2.base_texture
|
|
||||||
end
|
|
||||||
child:set_properties({
|
|
||||||
textures = ent_c.base_texture
|
|
||||||
})
|
|
||||||
|
|
||||||
-- tamed and owned by parents' owner
|
-- tamed and owned by parents' owner
|
||||||
ent_c.tamed = true
|
ent_c.tamed = true
|
||||||
ent_c.owner = parent1.owner
|
ent_c.owner = parent1.owner
|
||||||
end, self, ent, pos)
|
end, self, ent, pos)
|
||||||
|
|
||||||
num = 0
|
|
||||||
|
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -311,9 +244,7 @@ function mob_class:check_breeding()
|
||||||
end
|
end
|
||||||
|
|
||||||
function mob_class:toggle_sit(clicker,p)
|
function mob_class:toggle_sit(clicker,p)
|
||||||
if not self.tamed or self.child or self.owner ~= clicker:get_player_name() then
|
if not self.tamed or self.child or self.owner ~= clicker:get_player_name() then return end
|
||||||
return
|
|
||||||
end
|
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
local particle
|
local particle
|
||||||
if not self.order or self.order == "" or self.order == "sit" then
|
if not self.order or self.order == "" or self.order == "sit" then
|
||||||
|
@ -341,7 +272,7 @@ function mob_class:toggle_sit(clicker,p)
|
||||||
-- Display icon to show current order (sit or roam)
|
-- Display icon to show current order (sit or roam)
|
||||||
minetest.add_particle({
|
minetest.add_particle({
|
||||||
pos = vector.add(pos, pp),
|
pos = vector.add(pos, pp),
|
||||||
velocity = {x=0,y=0.2,z=0},
|
velocity = vector.new(0, 0.2, 0),
|
||||||
expirationtime = 1,
|
expirationtime = 1,
|
||||||
size = 4,
|
size = 4,
|
||||||
texture = particle,
|
texture = particle,
|
||||||
|
|
|
@ -27,10 +27,12 @@ local vector_offset = vector.offset
|
||||||
local vector_new = vector.new
|
local vector_new = vector.new
|
||||||
local vector_copy = vector.copy
|
local vector_copy = vector.copy
|
||||||
local vector_distance = vector.distance
|
local vector_distance = vector.distance
|
||||||
|
local vector_zero = vector.zero
|
||||||
|
local node_ok = mcl_mobs.node_ok -- TODO: remove
|
||||||
|
|
||||||
-- check if daytime and also if mob is docile during daylight hours
|
-- check if daytime and also if mob is docile during daylight hours
|
||||||
function mob_class:day_docile()
|
function mob_class:day_docile()
|
||||||
return self.docile_by_day == true and self.time_of_day > 0.2 and self.time_of_day < 0.8
|
return self.docile_by_day and self.time_of_day > 0.2 and self.time_of_day < 0.8
|
||||||
end
|
end
|
||||||
|
|
||||||
-- get this mob to attack the object
|
-- get this mob to attack the object
|
||||||
|
@ -60,7 +62,7 @@ local function entity_physics(pos, radius)
|
||||||
if dist < 1 then dist = 1 end
|
if dist < 1 then dist = 1 end
|
||||||
|
|
||||||
local damage = floor((4 / dist) * radius)
|
local damage = floor((4 / dist) * radius)
|
||||||
local ent = objs[n]:get_luaentity()
|
--local ent = objs[n]:get_luaentity()
|
||||||
|
|
||||||
-- punches work on entities AND players
|
-- punches work on entities AND players
|
||||||
objs[n]:punch(objs[n], 1.0, {
|
objs[n]:punch(objs[n], 1.0, {
|
||||||
|
@ -143,7 +145,7 @@ function mob_class:smart_mobs(s, p, dist, dtime)
|
||||||
if use_pathfind then
|
if use_pathfind then
|
||||||
-- lets try find a path, first take care of positions
|
-- lets try find a path, first take care of positions
|
||||||
-- since pathfinder is very sensitive
|
-- since pathfinder is very sensitive
|
||||||
local sheight = self.collisionbox[5] - self.collisionbox[2]
|
--local sheight = self.collisionbox[5] - self.collisionbox[2]
|
||||||
|
|
||||||
-- 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!
|
||||||
|
@ -381,7 +383,7 @@ function mob_class:npc_attack()
|
||||||
p.y = p.y + 1
|
p.y = p.y + 1
|
||||||
sp.y = sp.y + 1
|
sp.y = sp.y + 1
|
||||||
|
|
||||||
if dist < min_dist and self:line_of_sight( sp, p, 2) == true then
|
if dist < min_dist and self:line_of_sight(sp, p, 2) == true then
|
||||||
min_dist = dist
|
min_dist = dist
|
||||||
min_player = obj.object
|
min_player = obj.object
|
||||||
end
|
end
|
||||||
|
@ -605,7 +607,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
||||||
local v = self.object:get_velocity()
|
local v = self.object:get_velocity()
|
||||||
if not v then return end
|
if not v then return end
|
||||||
local r = 1.4 - min(punch_interval, 1.4)
|
local r = 1.4 - min(punch_interval, 1.4)
|
||||||
local kb = r * (abs(v.x)+abs(v.z))
|
local kb = r * sqrt(v.x*v.x+v.z*v.z)
|
||||||
local up = 2.625
|
local up = 2.625
|
||||||
|
|
||||||
if die then kb = kb * 1.25 end
|
if die then kb = kb * 1.25 end
|
||||||
|
@ -633,7 +635,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
||||||
kb = kb + (abs(hv.x) + abs(hv.z)) * r
|
kb = kb + (abs(hv.x) + abs(hv.z)) * r
|
||||||
end
|
end
|
||||||
elseif luaentity and luaentity._knockback and die == false then
|
elseif luaentity and luaentity._knockback and die == false then
|
||||||
kb = kb + luaentity._knockback
|
kb = kb + luaentity._knockback * 0.25
|
||||||
elseif luaentity and luaentity._knockback and die == true then
|
elseif luaentity and luaentity._knockback and die == true then
|
||||||
kb = kb + luaentity._knockback * 0.25
|
kb = kb + luaentity._knockback * 0.25
|
||||||
end
|
end
|
||||||
|
@ -695,11 +697,8 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
||||||
local alert_pos = hitter:get_pos()
|
local alert_pos = hitter:get_pos()
|
||||||
if alert_pos then
|
if alert_pos then
|
||||||
local objs = minetest.get_objects_inside_radius(alert_pos, self.view_range)
|
local objs = minetest.get_objects_inside_radius(alert_pos, self.view_range)
|
||||||
local obj = nil
|
|
||||||
|
|
||||||
for n = 1, #objs do
|
for n = 1, #objs do
|
||||||
obj = objs[n]:get_luaentity()
|
local obj = objs[n]:get_luaentity()
|
||||||
|
|
||||||
if obj then
|
if obj then
|
||||||
-- only alert members of same mob or friends
|
-- only alert members of same mob or friends
|
||||||
if obj.group_attack
|
if obj.group_attack
|
||||||
|
@ -768,17 +767,16 @@ function mob_class:do_states_attack(dtime)
|
||||||
if self.timer > 100 then self.timer = 1 end
|
if self.timer > 100 then self.timer = 1 end
|
||||||
|
|
||||||
local s = self.object:get_pos()
|
local s = self.object:get_pos()
|
||||||
if not s then return end
|
local p = self.attack:get_pos()
|
||||||
|
if not s or not p then return end
|
||||||
|
|
||||||
local p = self.attack:get_pos() or s
|
|
||||||
local yaw = self.object:get_yaw() or 0
|
|
||||||
|
|
||||||
-- stop attacking if player invisible or out of range
|
-- stop attacking if player invisible or out of range
|
||||||
if not self.attack
|
if not self.attack
|
||||||
or not self.attack:get_pos()
|
or not self.attack:get_pos()
|
||||||
or not self:object_in_range(self.attack)
|
or not self:object_in_range(self.attack)
|
||||||
or self.attack:get_hp() <= 0
|
or self.attack:get_hp() <= 0
|
||||||
or (self.attack:is_player() and mcl_mobs.invis[ self.attack:get_player_name() ]) then
|
or (self.attack:is_player() and mcl_mobs.invis[self.attack:get_player_name()]) then
|
||||||
|
|
||||||
clear_aggro(self)
|
clear_aggro(self)
|
||||||
return
|
return
|
||||||
|
@ -955,7 +953,7 @@ function mob_class:do_states_attack(dtime)
|
||||||
self.path.stuck_timer = 0
|
self.path.stuck_timer = 0
|
||||||
self.path.following = false -- not stuck anymore
|
self.path.following = false -- not stuck anymore
|
||||||
|
|
||||||
self:set_velocity( 0)
|
self:set_velocity(0)
|
||||||
|
|
||||||
local attack_frequency = self.attack_frequency or 1
|
local attack_frequency = self.attack_frequency or 1
|
||||||
|
|
||||||
|
@ -997,21 +995,23 @@ function mob_class:do_states_attack(dtime)
|
||||||
or (self.attack_type == "dogshoot" and (dist > self.reach or dist < self.avoid_distance and self.shooter_avoid_enemy) and self:dogswitch() == 0) then
|
or (self.attack_type == "dogshoot" and (dist > self.reach or dist < self.avoid_distance and self.shooter_avoid_enemy) and self:dogswitch() == 0) then
|
||||||
local vec = vector_new(p.x - s.x, p.y - s.y - 1, p.z - s.z)
|
local vec = vector_new(p.x - s.x, p.y - s.y - 1, p.z - s.z)
|
||||||
local dist = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z)
|
local dist = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z)
|
||||||
self:turn_in_direction(vec.x, vec.z, 1)
|
local dir = -atan2(p.x - s.x, p.z - s.z)
|
||||||
|
self:set_yaw(dir, 4)
|
||||||
|
|
||||||
if self.strafes then
|
if self.strafes then
|
||||||
if not self.strafe_direction then self.strafe_direction = HALFPI end
|
if not self.strafe_direction then self.strafe_direction = math.random(0, 1) * 2 - 1 end
|
||||||
if random(40) == 1 then self.strafe_direction = self.strafe_direction * -1 end
|
if random(50) == 1 then self.strafe_direction = -self.strafe_direction end
|
||||||
|
|
||||||
local dir = -atan2(p.x - s.x, p.z - s.z)
|
|
||||||
self.acceleration.x = self.acceleration.x - sin(dir + self.strafe_direction) * 8
|
|
||||||
self.acceleration.z = self.acceleration.z + cos(dir + self.strafe_direction) * 8
|
|
||||||
--stay away from player so as to shoot them
|
--stay away from player so as to shoot them
|
||||||
if self.avoid_distance and dist < self.avoid_distance and self.shooter_avoid_enemy then
|
if self.avoid_distance and self.shooter_avoid_enemy then
|
||||||
local f = (self.avoid_distance - dist) / self.avoid_distance
|
local f = (dist - self.avoid_distance) / self.avoid_distance
|
||||||
--self:set_velocity(f * self.walk_velocity) --self.object:add_velocity(vector_new(-sin(dir) * f, 0, cos(dir) * f))
|
f = math.max(-1, math.min(1, f))
|
||||||
self.acceleration.x = self.acceleration.x - sin(dir) * f * 8
|
f = f * math.abs(f)
|
||||||
self.acceleration.z = self.acceleration.z + cos(dir) * f * 8
|
self:set_velocity(f * self.walk_velocity, (1 - math.abs(f)) * self.strafe_direction * self.walk_velocity * 1.5)
|
||||||
|
elseif dist > 1 then
|
||||||
|
self:set_velocity(self.walk_velocity)
|
||||||
|
else
|
||||||
|
self:set_velocity(0)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:set_velocity(0)
|
self:set_velocity(0)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
local math, tonumber, vector, minetest, mcl_mobs = math, tonumber, vector, minetest, mcl_mobs
|
local math, tonumber, vector, minetest, mcl_mobs = math, tonumber, vector, minetest, mcl_mobs
|
||||||
local mob_class = mcl_mobs.mob_class
|
local mob_class = mcl_mobs.mob_class
|
||||||
local validate_vector = mcl_util.validate_vector
|
--local validate_vector = mcl_util.validate_vector
|
||||||
|
|
||||||
local active_particlespawners = {}
|
local active_particlespawners = {}
|
||||||
local disable_blood = minetest.settings:get_bool("mobs_disable_blood")
|
local disable_blood = minetest.settings:get_bool("mobs_disable_blood")
|
||||||
|
@ -128,7 +128,7 @@ function mob_class:remove_texture_mod(mod)
|
||||||
table.insert(remove, i)
|
table.insert(remove, i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for i=#remove, 1 do
|
for i=#remove, 1, -1 do
|
||||||
table.remove(self.texture_mods, remove[i])
|
table.remove(self.texture_mods, remove[i])
|
||||||
end
|
end
|
||||||
self.object:set_texture_mod(full_mod)
|
self.object:set_texture_mod(full_mod)
|
||||||
|
@ -275,7 +275,8 @@ function mob_class:check_head_swivel(dtime)
|
||||||
|
|
||||||
who_are_you_looking_at(self, dtime)
|
who_are_you_looking_at(self, dtime)
|
||||||
|
|
||||||
local newr, oldp, oldr = vector.zero(), nil, nil
|
local newr = vector.zero()
|
||||||
|
local oldp, oldr
|
||||||
if self.object.get_bone_override then -- minetest >= 5.9
|
if self.object.get_bone_override then -- minetest >= 5.9
|
||||||
local ov = self.object:get_bone_override(self.head_swivel)
|
local ov = self.object:get_bone_override(self.head_swivel)
|
||||||
oldp, oldr = ov.position.vec, ov.rotation.vec
|
oldp, oldr = ov.position.vec, ov.rotation.vec
|
||||||
|
|
|
@ -38,7 +38,7 @@ local function line_of_sight(origin, target, see_through_opaque, liquids)
|
||||||
end
|
end
|
||||||
mcl_mobs.line_of_sight = line_of_sight
|
mcl_mobs.line_of_sight = line_of_sight
|
||||||
|
|
||||||
local NODE_IGNORE = { name = "ignore", groups = {} } -- fallback for unknown nodes
|
mcl_mobs.NODE_IGNORE = { name = "ignore", groups = {} } -- fallback for unknown nodes
|
||||||
|
|
||||||
--api and helpers
|
--api and helpers
|
||||||
-- effects: sounds and particles mostly
|
-- effects: sounds and particles mostly
|
||||||
|
@ -417,7 +417,6 @@ function mcl_mobs.register_arrow(name, def)
|
||||||
hit_object = def.hit_object,
|
hit_object = def.hit_object,
|
||||||
homing = def.homing,
|
homing = def.homing,
|
||||||
drop = def.drop or false, -- drops arrow as registered item when true
|
drop = def.drop or false, -- drops arrow as registered item when true
|
||||||
collisionbox = {0, 0, 0, 0, 0, 0}, -- remove box around arrows
|
|
||||||
timer = 0,
|
timer = 0,
|
||||||
switch = 0,
|
switch = 0,
|
||||||
_lifetime = def._lifetime or 7,
|
_lifetime = def._lifetime or 7,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
|
local minetest, mcl_mobs = minetest, mcl_mobs
|
||||||
local mob_class = mcl_mobs.mob_class
|
local mob_class = mcl_mobs.mob_class
|
||||||
--- Item and armor management
|
--- Item and armor management
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ function mcl_mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
||||||
-- jump
|
-- jump
|
||||||
if ctrl.jump then
|
if ctrl.jump then
|
||||||
if velo.y == 0 then
|
if velo.y == 0 then
|
||||||
velo.y = velo.y + sqrt(entity.jump_height * 20)
|
velo.y = velo.y + math.sqrt(entity.jump_height * 20)
|
||||||
acce_y = acce_y + 1
|
acce_y = acce_y + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,7 +8,7 @@ local CHECK_HERD_FREQUENCY = 4
|
||||||
|
|
||||||
local PATHFINDING = "gowp"
|
local PATHFINDING = "gowp"
|
||||||
|
|
||||||
local node_snow = "mcl_core:snow"
|
local NODE_SNOW = "mcl_core:snow"
|
||||||
|
|
||||||
local logging = minetest.settings:get_bool("mcl_logging_mobs_movement", true)
|
local logging = minetest.settings:get_bool("mcl_logging_mobs_movement", true)
|
||||||
local mobs_griefing = minetest.settings:get_bool("mobs_griefing", true)
|
local mobs_griefing = minetest.settings:get_bool("mobs_griefing", true)
|
||||||
|
@ -16,7 +16,6 @@ local mobs_griefing = minetest.settings:get_bool("mobs_griefing", true)
|
||||||
local random = math.random
|
local random = math.random
|
||||||
local sin = math.sin
|
local sin = math.sin
|
||||||
local cos = math.cos
|
local cos = math.cos
|
||||||
local abs = math.abs
|
|
||||||
local floor = math.floor
|
local floor = math.floor
|
||||||
local PI = math.pi
|
local PI = math.pi
|
||||||
local TWOPI = 2 * math.pi
|
local TWOPI = 2 * math.pi
|
||||||
|
@ -24,12 +23,9 @@ local HALFPI = 0.5 * math.pi
|
||||||
local QUARTERPI = 0.25 * math.pi
|
local QUARTERPI = 0.25 * math.pi
|
||||||
|
|
||||||
local vector_new = vector.new
|
local vector_new = vector.new
|
||||||
local vector_zero = vector.zero
|
|
||||||
local vector_copy = vector.copy
|
|
||||||
local vector_offset = vector.offset
|
local vector_offset = vector.offset
|
||||||
local vector_distance = vector.distance
|
local vector_distance = vector.distance
|
||||||
|
|
||||||
local node_ok = mcl_mobs.node_ok
|
|
||||||
local mobs_see_through_opaque = mcl_mobs.see_through_opaque
|
local mobs_see_through_opaque = mcl_mobs.see_through_opaque
|
||||||
local line_of_sight = mcl_mobs.line_of_sight
|
local line_of_sight = mcl_mobs.line_of_sight
|
||||||
|
|
||||||
|
@ -286,24 +282,25 @@ function mob_class:do_jump()
|
||||||
local nod = minetest.get_node(vector_offset(pos, dir_x, 0.5, dir_z)).name
|
local nod = minetest.get_node(vector_offset(pos, dir_x, 0.5, dir_z)).name
|
||||||
local ndef = minetest.registered_nodes[nod.name]
|
local ndef = minetest.registered_nodes[nod.name]
|
||||||
-- thin blocks that do not need to be jumped
|
-- thin blocks that do not need to be jumped
|
||||||
if nod.name == node_snow or (ndef and ndef.groups.carpet or 0) > 0 then return false end
|
if nod.name == NODE_SNOW or (ndef and ndef.groups.carpet or 0) > 0 then return false end
|
||||||
|
-- nothing to jump on?
|
||||||
-- this is used to detect if there's a block on top of the block in front of the mob.
|
|
||||||
-- If there is, there is no point in jumping as we won't manage.
|
|
||||||
local node_top = minetest.get_node(vector_offset(pos, dir_x, 1.5, dir_z)).name
|
|
||||||
-- TODO: also check above the mob itself?
|
|
||||||
|
|
||||||
-- we don't attempt to jump if there's a stack of blocks blocking, unless attacking
|
|
||||||
local ntdef = minetest.registered_nodes[node_top]
|
|
||||||
if ntdef and ntdef.walkable == true and not (self.attack and self.state == "attack") then return false end
|
|
||||||
|
|
||||||
if self.walk_chance ~= 0 and not (ndef and ndef.walkable) and not self._can_jump_cliff then return false end
|
if self.walk_chance ~= 0 and not (ndef and ndef.walkable) and not self._can_jump_cliff then return false end
|
||||||
|
-- facing a fence? jumping will not help (FIXME: consider jump height)
|
||||||
if (ndef.groups.fence or 0) ~= 0 or (ndef.groups.fence_gate or 0) ~= 0 or (ndef.groups.wall or 0) ~= 0 then
|
if (ndef.groups.fence or 0) ~= 0 or (ndef.groups.fence_gate or 0) ~= 0 or (ndef.groups.wall or 0) ~= 0 then
|
||||||
self.facing_fence = true
|
self.facing_fence = true
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- this is used to detect if there's a block on top of the block in front of the mob.
|
||||||
|
-- If there is, there is no point in jumping as we won't manage.
|
||||||
|
local node_top = minetest.get_node(vector_offset(pos, dir_x, 1.5, dir_z)).name
|
||||||
|
-- TODO: also check above the mob itself, and check the full mob height?
|
||||||
|
|
||||||
|
-- we don't attempt to jump if there's a stack of blocks blocking, unless attacking
|
||||||
|
local ntdef = minetest.registered_nodes[node_top]
|
||||||
|
-- TODO: snow, carpet?
|
||||||
|
if ntdef and ntdef.walkable == true --[[and not (self.attack and self.state == "attack")]] then return false end
|
||||||
|
|
||||||
v.y = math.min(v.y, 0) + math.sqrt(self.jump_height * 20 + (in_water or self._can_jump_cliff and 10 or 0))
|
v.y = math.min(v.y, 0) + math.sqrt(self.jump_height * 20 + (in_water or self._can_jump_cliff and 10 or 0))
|
||||||
v.y = math.min(-self.fall_speed, math.max(v.y, self.fall_speed))
|
v.y = math.min(-self.fall_speed, math.max(v.y, self.fall_speed))
|
||||||
self.object:set_velocity(v)
|
self.object:set_velocity(v)
|
||||||
|
@ -385,7 +382,6 @@ function mob_class:replace_node(pos)
|
||||||
on_replace_return = self.on_replace(self, pos, oldnode, newnode)
|
on_replace_return = self.on_replace(self, pos, oldnode, newnode)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if on_replace_return ~= false then
|
if on_replace_return ~= false then
|
||||||
if mobs_griefing then
|
if mobs_griefing then
|
||||||
minetest.after(self.replace_delay, function()
|
minetest.after(self.replace_delay, function()
|
||||||
|
@ -416,40 +412,32 @@ function mob_class:check_runaway_from()
|
||||||
if not self.runaway_from and self.state ~= "flop" then return end
|
if not self.runaway_from and self.state ~= "flop" then return end
|
||||||
|
|
||||||
local s = self.object:get_pos()
|
local s = self.object:get_pos()
|
||||||
local p, sp, dist
|
local min_dist, min_player = self.view_range + 1, nil
|
||||||
local player, obj, min_player
|
|
||||||
local type, name = "", ""
|
|
||||||
local min_dist = self.view_range + 1
|
|
||||||
local objs = minetest.get_objects_inside_radius(s, self.view_range)
|
local objs = minetest.get_objects_inside_radius(s, self.view_range)
|
||||||
|
|
||||||
for n = 1, #objs do
|
for n = 1, #objs do
|
||||||
|
local name, player = "", nil
|
||||||
if objs[n]:is_player() then
|
if objs[n]:is_player() then
|
||||||
if mcl_mobs.invis[ objs[n]:get_player_name() ]
|
if mcl_mobs.invis[objs[n]:get_player_name()] or self.owner == objs[n]:get_player_name() or not self:object_in_range(objs[n]) then
|
||||||
or self.owner == objs[n]:get_player_name()
|
name = ""
|
||||||
or (not self:object_in_range(objs[n])) then
|
|
||||||
type = ""
|
|
||||||
else
|
else
|
||||||
player = objs[n]
|
player = objs[n]
|
||||||
type = "player"
|
|
||||||
name = "player"
|
name = "player"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
obj = objs[n]:get_luaentity()
|
local obj = objs[n]:get_luaentity()
|
||||||
if obj then
|
if obj then
|
||||||
player = obj.object
|
player = obj.object
|
||||||
type = obj.type
|
|
||||||
name = obj.name or ""
|
name = obj.name or ""
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- find specific mob to runaway from
|
-- find specific mob to runaway from
|
||||||
if name ~= "" and name ~= self.name
|
if name ~= "" and name ~= self.name and specific_runaway(self.runaway_from, name) then
|
||||||
and specific_runaway(self.runaway_from, name) then
|
local p = player:get_pos()
|
||||||
p = player:get_pos()
|
local dist = vector_distance(p, s)
|
||||||
sp = s
|
|
||||||
dist = vector_distance(p, s)
|
|
||||||
-- choose closest player/mpb to runaway from
|
-- choose closest player/mpb to runaway from
|
||||||
if dist < min_dist and line_of_sight(vector_offset(sp, 0, 1, 0), vector_offset(p, 0, 1, 0), self.see_through_opaque or mobs_see_through_opaque, false) then
|
if dist < min_dist and line_of_sight(vector_offset(s, 0, 1, 0), vector_offset(p, 0, 1, 0), self.see_through_opaque or mobs_see_through_opaque, false) then
|
||||||
-- aim higher to make looking up hills more realistic
|
-- aim higher to make looking up hills more realistic
|
||||||
min_dist = dist
|
min_dist = dist
|
||||||
min_player = player
|
min_player = player
|
||||||
|
@ -458,7 +446,7 @@ function mob_class:check_runaway_from()
|
||||||
end
|
end
|
||||||
|
|
||||||
if min_player then
|
if min_player then
|
||||||
local lp = player:get_pos()
|
local lp = min_player:get_pos()
|
||||||
self:turn_in_direction(s.x - lp.x, s.z - lp.z, 4) -- away from player
|
self:turn_in_direction(s.x - lp.x, s.z - lp.z, 4) -- away from player
|
||||||
self.state = "runaway"
|
self.state = "runaway"
|
||||||
self.runaway_timer = 3
|
self.runaway_timer = 3
|
||||||
|
@ -474,10 +462,9 @@ function mob_class:check_follow()
|
||||||
and self.state ~= "attack"
|
and self.state ~= "attack"
|
||||||
and self.order ~= "sit"
|
and self.order ~= "sit"
|
||||||
and self.state ~= "runaway" then
|
and self.state ~= "runaway" then
|
||||||
local s = self.object:get_pos()
|
|
||||||
local players = minetest.get_connected_players()
|
local players = minetest.get_connected_players()
|
||||||
for n = 1, #players do
|
for n = 1, #players do
|
||||||
if (self:object_in_range(players[n])) and not mcl_mobs.invis[ players[n]:get_player_name() ] then
|
if self:object_in_range(players[n]) and not mcl_mobs.invis[players[n]:get_player_name()] then
|
||||||
self.following = players[n]
|
self.following = players[n]
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
@ -592,7 +579,7 @@ function mob_class:do_states_walk()
|
||||||
-- Better way to find shore - copied from upstream
|
-- Better way to find shore - copied from upstream
|
||||||
local lp = minetest.find_nodes_in_area_under_air(vector_offset(s, -5, -0.5, -5), vector_offset(s, 5, 1, 5), {"group:solid"})
|
local lp = minetest.find_nodes_in_area_under_air(vector_offset(s, -5, -0.5, -5), vector_offset(s, 5, 1, 5), {"group:solid"})
|
||||||
if #lp == 0 then
|
if #lp == 0 then
|
||||||
local lp = minetest.find_nodes_in_area_under_air(vector_offset(s, -10, -0.5, -10), vector_offset(s, 10, 1, 10), {"group:solid"})
|
lp = minetest.find_nodes_in_area_under_air(vector_offset(s, -10, -0.5, -10), vector_offset(s, 10, 1, 10), {"group:solid"})
|
||||||
end
|
end
|
||||||
-- TODO: use node with smallest change in yaw instead of random?
|
-- TODO: use node with smallest change in yaw instead of random?
|
||||||
lp = #lp > 0 and lp[random(#lp)]
|
lp = #lp > 0 and lp[random(#lp)]
|
||||||
|
@ -617,7 +604,7 @@ function mob_class:do_states_walk()
|
||||||
-- facing wall? then turn
|
-- facing wall? then turn
|
||||||
local facing_wall = false
|
local facing_wall = false
|
||||||
-- todo: use moveresult collision info here?
|
-- todo: use moveresult collision info here?
|
||||||
if moveresult and moveresult.collides and self:get_velocity_xyz() < 0.1 then
|
if self.collides and self:get_velocity_xyz() < 0.1 then
|
||||||
facing_wall = true
|
facing_wall = true
|
||||||
else --if not facing_wall then
|
else --if not facing_wall then
|
||||||
local cbox = self.collisionbox
|
local cbox = self.collisionbox
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
|
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
|
||||||
local mob_class = mcl_mobs.mob_class
|
local mob_class = mcl_mobs.mob_class
|
||||||
local validate_vector = mcl_util.validate_vector
|
--local validate_vector = mcl_util.validate_vector
|
||||||
|
|
||||||
local MAX_DTIME = 0.25 -- todo: make user configurable?
|
local MAX_DTIME = 0.25 -- todo: make user configurable?
|
||||||
local ACCELERATION_MIX = 1.0 -- how much of acceleration to handle in Lua instead of MTE todo: make user configurable
|
local ACCELERATION_MIX = 1.0 -- how much of acceleration to handle in Lua instead of MTE todo: make user configurable
|
||||||
|
@ -20,9 +20,10 @@ local atan2 = math.atan2
|
||||||
local sin = math.sin
|
local sin = math.sin
|
||||||
local cos = math.cos
|
local cos = math.cos
|
||||||
local sqrt = math.sqrt
|
local sqrt = math.sqrt
|
||||||
local node_ok = mcl_mobs.node_ok
|
--local node_ok = mcl_mobs.node_ok
|
||||||
|
local NODE_IGNORE = mcl_mobs.NODE_IGNORE
|
||||||
|
|
||||||
local PATHFINDING = "gowp"
|
--local PATHFINDING = "gowp"
|
||||||
local mobs_drop_items = minetest.settings:get_bool("mobs_drop_items") ~= false
|
local mobs_drop_items = minetest.settings:get_bool("mobs_drop_items") ~= false
|
||||||
local mob_active_range = tonumber(minetest.settings:get("mcl_mob_active_range")) or 48
|
local mob_active_range = tonumber(minetest.settings:get("mcl_mob_active_range")) or 48
|
||||||
|
|
||||||
|
@ -53,10 +54,11 @@ end
|
||||||
-- these may be "nil" (= ignore) and are otherwise already resolved via minetest.registered_nodes
|
-- these may be "nil" (= ignore) and are otherwise already resolved via minetest.registered_nodes
|
||||||
function mob_class:update_standing(pos, moveresult)
|
function mob_class:update_standing(pos, moveresult)
|
||||||
local temp_pos = vector.offset(pos, 0, self.collisionbox[2] + 0.5, 0) -- foot level
|
local temp_pos = vector.offset(pos, 0, self.collisionbox[2] + 0.5, 0) -- foot level
|
||||||
|
self.collides = moveresult and moveresult.collides
|
||||||
self.standing_in = minetest.registered_nodes[minetest.get_node(temp_pos).name] or NODE_IGNORE
|
self.standing_in = minetest.registered_nodes[minetest.get_node(temp_pos).name] or NODE_IGNORE
|
||||||
temp_pos.y = temp_pos.y - 1.5 -- below
|
temp_pos.y = temp_pos.y - 1.5 -- below
|
||||||
self.standing_on_node = minetest.get_node(temp_pos) -- to allow access to param2 in, e.g., stalker
|
self.standing_on_node = minetest.get_node(temp_pos) -- to allow access to param2 in, e.g., stalker
|
||||||
self.standing_on = standing_on or minetest.registered_nodes[self.standing_on_node.name] or NODE_IGNORE
|
self.standing_on = self.standing_on_node and minetest.registered_nodes[self.standing_on_node.name] or NODE_IGNORE
|
||||||
-- sometimes, we may be colliding with a node *not* below us, effectively standing on it instead (e.g., a corner)
|
-- sometimes, we may be colliding with a node *not* below us, effectively standing on it instead (e.g., a corner)
|
||||||
if not self.standing_on.walkable and moveresult and moveresult.collisions then
|
if not self.standing_on.walkable and moveresult and moveresult.collisions then
|
||||||
-- to inspect: minetest.log("action", dump(moveresult):gsub(" *\n\\s*",""))
|
-- to inspect: minetest.log("action", dump(moveresult):gsub(" *\n\\s*",""))
|
||||||
|
@ -103,13 +105,10 @@ end
|
||||||
|
|
||||||
function mob_class:item_drop(cooked, looting_level)
|
function mob_class:item_drop(cooked, looting_level)
|
||||||
if not mobs_drop_items then return end
|
if not mobs_drop_items then return end
|
||||||
|
if self.child and self.type ~= "monster" then return end
|
||||||
looting_level = looting_level or 0
|
looting_level = looting_level or 0
|
||||||
|
|
||||||
if (self.child and self.type ~= "monster") then return end
|
|
||||||
|
|
||||||
local obj, item, num
|
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
self.drops = self.drops or {}
|
self.drops = self.drops or {}
|
||||||
|
|
||||||
for n = 1, #self.drops do
|
for n = 1, #self.drops do
|
||||||
|
@ -139,7 +138,7 @@ function mob_class:item_drop(cooked, looting_level)
|
||||||
end
|
end
|
||||||
|
|
||||||
if num > 0 then
|
if num > 0 then
|
||||||
item = dropdef.name
|
local item = dropdef.name
|
||||||
|
|
||||||
if cooked then
|
if cooked then
|
||||||
local output = minetest.get_craft_result({method = "cooking", width = 1, items = {item}})
|
local output = minetest.get_craft_result({method = "cooking", width = 1, items = {item}})
|
||||||
|
@ -149,8 +148,7 @@ function mob_class:item_drop(cooked, looting_level)
|
||||||
end
|
end
|
||||||
|
|
||||||
for x = 1, num do
|
for x = 1, num do
|
||||||
obj = minetest.add_item(pos, ItemStack(item .. " 1"))
|
local obj = minetest.add_item(pos, ItemStack(item .. " 1"))
|
||||||
|
|
||||||
if obj and obj:get_luaentity() then
|
if obj and obj:get_luaentity() then
|
||||||
obj:set_velocity(vector.new((random() - 0.5) * 1.5, 6, (random() - 0.5) * 1.5))
|
obj:set_velocity(vector.new((random() - 0.5) * 1.5, 6, (random() - 0.5) * 1.5))
|
||||||
elseif obj then
|
elseif obj then
|
||||||
|
@ -191,8 +189,11 @@ function mob_class:collision()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- move mob in facing direction
|
-- move mob in facing direction
|
||||||
function mob_class:set_velocity(v)
|
-- @param v number: Velocity in direction the mob is facing
|
||||||
|
-- @param o number, optional: Orthogonal velocity, for strafing
|
||||||
|
function mob_class:set_velocity(v, o)
|
||||||
self.target_vel = v
|
self.target_vel = v
|
||||||
|
self.target_orth = o
|
||||||
end
|
end
|
||||||
|
|
||||||
-- calculate mob velocity (3d)
|
-- calculate mob velocity (3d)
|
||||||
|
@ -245,7 +246,7 @@ function mob_class:set_yaw(yaw, delay, dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- name tag easter egg, test engine capabilities for rolling
|
-- name tag easter egg, test engine capabilities for rolling
|
||||||
local function update_roll()
|
--[[local function update_roll(self)
|
||||||
local is_Fleckenstein = self.nametag == "Fleckenstein"
|
local is_Fleckenstein = self.nametag == "Fleckenstein"
|
||||||
if not is_Fleckenstein and not self.is_Fleckenstein then return end
|
if not is_Fleckenstein and not self.is_Fleckenstein then return end
|
||||||
|
|
||||||
|
@ -266,7 +267,7 @@ local function update_roll()
|
||||||
self.object:set_pos(pos)
|
self.object:set_pos(pos)
|
||||||
end
|
end
|
||||||
self.is_Fleckenstein = is_Fleckenstein
|
self.is_Fleckenstein = is_Fleckenstein
|
||||||
end
|
end]]
|
||||||
|
|
||||||
-- Improved smooth rotation
|
-- Improved smooth rotation
|
||||||
-- @param dtime number: timestep length
|
-- @param dtime number: timestep length
|
||||||
|
@ -288,7 +289,7 @@ function mob_class:smooth_rotation(dtime)
|
||||||
yaw = yaw + (random() * 2 - 1) / 72 * dtime
|
yaw = yaw + (random() * 2 - 1) / 72 * dtime
|
||||||
end
|
end
|
||||||
if yaw ~= initial_yaw then self.object:set_yaw(yaw - self.rotate) end
|
if yaw ~= initial_yaw then self.object:set_yaw(yaw - self.rotate) end
|
||||||
--update_roll() -- Fleckenstein easter egg
|
--update_roll(self) -- Fleckenstein easter egg
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Handling of intentional acceleration by the mob
|
-- Handling of intentional acceleration by the mob
|
||||||
|
@ -296,11 +297,13 @@ end
|
||||||
-- TODO: have mobs that acccelerate faster and that accelerate slower?
|
-- TODO: have mobs that acccelerate faster and that accelerate slower?
|
||||||
-- @param dtime number: timestep length
|
-- @param dtime number: timestep length
|
||||||
function mob_class:smooth_acceleration(dtime)
|
function mob_class:smooth_acceleration(dtime)
|
||||||
local yaw = self.target_yaw or (self.object:get_yaw() or 0) + self.rotate
|
local yaw = self.move_yaw or self.target_yaw or (self.object:get_yaw() or 0) + self.rotate
|
||||||
local vel = self.target_vel or 0
|
local vel = self.target_vel or 0 -- can also stop
|
||||||
local x, z = -sin(yaw) * vel, cos(yaw) * vel
|
local x, z = -sin(yaw), cos(yaw)
|
||||||
|
local orth = self.target_orth or 0 -- strafing
|
||||||
|
x, z = x * vel + z * orth, z * vel + x * orth
|
||||||
local v = self.object:get_velocity()
|
local v = self.object:get_velocity()
|
||||||
local w = min(dtime * 5, 1)
|
local w = 10 * min(dtime, 0.1) -- 0.1 time to fully change direction / accelerate
|
||||||
v.x, v.z = v.x + w * (x - v.x), v.z + w * (z - v.z)
|
v.x, v.z = v.x + w * (x - v.x), v.z + w * (z - v.z)
|
||||||
self.object:set_velocity(v)
|
self.object:set_velocity(v)
|
||||||
end
|
end
|
||||||
|
@ -874,7 +877,6 @@ function mob_class:limit_vel_acc_for_large_dtime(pos, dtime, moveresult)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Update velocity and acceleration at the end of our movement logic
|
--- Update velocity and acceleration at the end of our movement logic
|
||||||
--
|
|
||||||
function mob_class:update_vel_acc(dtime)
|
function mob_class:update_vel_acc(dtime)
|
||||||
local vel = self.object:get_velocity()
|
local vel = self.object:get_velocity()
|
||||||
--vel.x, vel.y, vel.z = vel.x * visc, (vel.y + acc.y * dtime) * visc, vel.z * visc
|
--vel.x, vel.y, vel.z = vel.x * visc, (vel.y + acc.y * dtime) * visc, vel.z * visc
|
||||||
|
@ -913,7 +915,7 @@ function mob_class:check_water_flow(dtime, pos)
|
||||||
-- Just to make sure we don't manipulate the speed for no reason
|
-- Just to make sure we don't manipulate the speed for no reason
|
||||||
if vec.x ~= 0 or vec.y ~= 0 or vec.z ~= 0 then
|
if vec.x ~= 0 or vec.y ~= 0 or vec.z ~= 0 then
|
||||||
-- Minecraft Wiki: Flowing speed is "about 1.39 meters per second"
|
-- Minecraft Wiki: Flowing speed is "about 1.39 meters per second"
|
||||||
local f = 8 -- but we have acceleration ehre, not velocity. Was: 1.39
|
local f = 10 -- but we have acceleration here, not velocity. Was: 1.39
|
||||||
-- Set new item moving speed into the direciton of the liquid
|
-- Set new item moving speed into the direciton of the liquid
|
||||||
self.acceleration = self.acceleration + vector.new(vec.x * f, -0.22, vec.z * f)
|
self.acceleration = self.acceleration + vector.new(vec.x * f, -0.22, vec.z * f)
|
||||||
--self.physical_state = true
|
--self.physical_state = true
|
||||||
|
|
Loading…
Reference in New Issue