luacheck and other improvements

This commit is contained in:
kno10 2024-10-07 17:22:01 +02:00
parent a5cfaed843
commit 98600c87de
9 changed files with 143 additions and 226 deletions

View File

@ -1,5 +1,4 @@
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 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
local textures = self.base_texture
local mesh = self.base_mesh
local vis_size = self.base_size
local colbox = self.base_colbox
local selbox = self.base_selbox
self.textures = self.gotten and def.gotten_texture or self.base_texture
self.mesh = self.gotten and def.gotten_mesh or self.base_mesh
self.visual_size = self.base_size
self.collisionbox = self.base_colbox
self.selectionbox = self.base_selbox
if self.gotten == true and def.gotten_texture then textures = def.gotten_texture end
if self.gotten == true and def.gotten_mesh then mesh = def.gotten_mesh end
if self.child == true then
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
if self.child then
self.visual_size = { x = self.base_size.x * .5, y = self.base_size.y * .5 }
self.textures = def.child_texture and def.child_texture[1] or self.textures
colbox = {
self.collisionbox = {
self.base_colbox[1] * .5,
self.base_colbox[2] * .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[6] * .5
}
selbox = {
self.selectionbox = {
self.base_selbox[1] * .5,
self.base_selbox[2] * .5,
self.base_selbox[3] * .5,
@ -182,8 +179,8 @@ function mob_class:mob_activate(staticdata, def, dtime)
}
end
if self.health == 0 then self.health = math.random(self.hp_min, self.hp_max) end
if self.breath == nil then self.breath = self.breath_max end
self.health = (self.health and self.health > 0 and self.health) or math.random(self.hp_min, self.hp_max)
self.breath = self.breath or self.breath_max
self.path = {}
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_health = self.health
self.sounds.distance = self.sounds.distance or 10
self.textures = textures
self.mesh = mesh
self.collisionbox = colbox
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_in = mcl_mobs.NODE_IGNORE
self.standing_on = mcl_mobs.NODE_IGNORE
self.standing_under = mcl_mobs.NODE_IGNORE
self.standing_depth = 0
self.state = self.state or "stand"
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()
-- 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
-- initializes self.acceleration:
if self:gravity_and_floating(pos, dtime, moveresult) then return end -- keep early, for gravity!
if self:check_dying() 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)
local cx, cz = self:collision()
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 not self.object:get_luaentity() then return false end
end
@ -398,8 +391,12 @@ function mob_class:on_step(dtime, moveresult)
-- allow crash in development mode
if DEVELOPMENT then return on_step_work(self, dtime, moveresult) end
-- 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 = pcall(on_step_work, self, dtime, moveresult)
local status, retVal
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
warn_user_error()
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
--minetest.log("Match - passive")
mob_match = true
else
--minetest.log("No match for type.")
--else
-- minetest.log("No match for type.")
end
elseif mob_name and (o.name == mob_name or string.find(o.name, mob_name)) then
--minetest.log("Match - mob_name = ".. tostring(o.name))
mob_match = true
else
--minetest.log("No match - o.type = ".. tostring(o.type))
--minetest.log("No match - mob_name = ".. tostring(o.name))
--minetest.log("No match - mob_type = ".. tostring(mob_name))
--else
-- minetest.log("No match - o.type = ".. tostring(o.type))
-- minetest.log("No match - mob_name = ".. tostring(o.name))
-- minetest.log("No match - mob_type = ".. tostring(mob_name))
end
if mob_match then

View File

@ -5,7 +5,7 @@ local HORNY_TIME = 30
local HORNY_AGAIN_TIME = 30 -- was 300 or 15*20
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 function mcl_log (message)
@ -29,18 +29,13 @@ end
-- feeding, taming and breeding (thanks blert2112)
function mob_class:feed_tame(clicker, feed_count, breed, tame, notake)
if not self.follow then
return false
end
if clicker:get_wielded_item():get_definition()._mcl_not_consumable then
return false
end
if not self.follow then return false end
if clicker:get_wielded_item():get_definition()._mcl_not_consumable then return false end
-- can eat/tame with item in hand
if self.nofollow or self:follow_holding(clicker) then
local consume_food = false
-- tame if not still a baby
if tame and not self.child then
if not self.owner or self.owner == "" then
self.tamed = true
@ -50,7 +45,6 @@ function mob_class:feed_tame(clicker, feed_count, breed, tame, notake)
end
-- increase health
if self.health < self.hp_max and not consume_food then
consume_food = true
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
-- make children grow quicker
if not consume_food and self.child == true then
if not consume_food and self.child then
consume_food = true
-- deduct 10% of the time to adulthood
self.hornytimer = self.hornytimer + ((CHILD_GROW_TIME - self.hornytimer) * 0.1)
end
-- breed animals
if breed and not consume_food and self.hornytimer == 0 and not self.horny then
self.food = (self.food or 0) + 1
consume_food = true
@ -102,24 +94,15 @@ end
-- Spawn a child
function mcl_mobs.spawn_child(pos, mob_type)
local child = minetest.add_entity(pos, mob_type)
if not child then
return
end
if not child then return end
local ent = child:get_luaentity()
mcl_mobs.effect(pos, 15, "mcl_particles_smoke.png", 1, 2, 2, 15, 5)
ent.child = true
local textures
-- using specific child texture (if found)
if ent.child_texture then
textures = ent.child_texture[1]
end
mcl_mobs.effect(pos, 15, "mcl_particles_smoke.png", 1, 2, 2, 15, 5)
-- and resize to half height
child:set_properties({
textures = textures,
textures = ent.child_texture and ent.child_texture[1],
visual_size = {
x = ent.base_size.x * .5,
y = ent.base_size.y * .5,
@ -151,16 +134,12 @@ end
-- find two animals of same type and breed if nearby and horny
function mob_class:check_breeding()
--mcl_log("In breed function")
-- child takes a long time before growing into adult
if self.child == true then
-- When a child, hornytimer is used to count age until adulthood
self.hornytimer = self.hornytimer + 1
if self.hornytimer >= CHILD_GROW_TIME then
self.child = false
self.hornytimer = 0
@ -177,11 +156,7 @@ function mob_class:check_breeding()
self.on_grown(self)
else
-- jump when fully grown so as not to fall into ground
self.object:set_velocity({
x = 0,
y = self.jump_height,
z = 0
})
self.object:set_velocity(vector.new(0, self.jump_height, 0))
end
self.animation = nil
@ -189,121 +164,79 @@ function mob_class:check_breeding()
self._current_animation = nil -- Mobs Redo does nothing otherwise
self:set_animation(anim)
end
return
else
-- horny animal can mate for HORNY_TIME seconds,
-- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds
if self.horny == true then
self.hornytimer = self.hornytimer + 1
end
-- horny animal can mate for HORNY_TIME seconds,
-- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds
if self.horny == true then
self.hornytimer = self.hornytimer + 1
if self.hornytimer >= HORNY_TIME + HORNY_AGAIN_TIME then
self.hornytimer = 0
self.horny = false
end
if self.hornytimer >= HORNY_TIME + HORNY_AGAIN_TIME then
self.hornytimer = 0
self.horny = false
end
end
-- find another same animal who is also horny and mate if nearby
if self.horny == true
and self.hornytimer <= HORNY_TIME then
if self.horny and self.hornytimer <= HORNY_TIME then
mcl_log("In breed function. All good. Do the magic.")
local pos = self.object:get_pos()
mcl_mobs.effect({x = pos.x, y = pos.y + 1, z = pos.z}, 8, "heart.png", 3, 4, 1, 0.1)
mcl_mobs.effect(vector.new(pos.x, pos.y + 1, pos.z), 8, "heart.png", 3, 4, 1, 0.1)
local objs = minetest.get_objects_inside_radius(pos, 3)
local num = 0
local ent = nil
for n = 1, #objs do
ent = objs[n]:get_luaentity()
local ent = objs[n]:get_luaentity()
-- check for same animal with different colour
local canmate = false
if ent then
if ent.name == self.name then
canmate = true
else
local entname = string.split(ent.name,":")
local selfname = string.split(self.name,":")
if entname[1] == selfname[1] then
entname = string.split(entname[2],"_")
selfname = string.split(selfname[2],"_")
if entname[1] == selfname[1] then
canmate = true
end
if entname[1] == selfname[1] then canmate = true end
end
end
end
if canmate then mcl_log("In breed function. Can mate.") end
if ent
and canmate == true
and ent.horny == true
and ent.hornytimer <= HORNY_TIME then
if ent and canmate and ent.horny and ent.hornytimer <= HORNY_TIME then
num = num + 1
end
-- found your mate? then have a baby
if num > 1 then
self.hornytimer = HORNY_TIME + 1
ent.hornytimer = HORNY_TIME + 1
-- spawn baby
minetest.after(5, function(parent1, parent2, pos)
if not parent1.object:get_luaentity() then
return
end
if not parent2.object:get_luaentity() then
return
end
if not parent1.object:get_luaentity() then return 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))
-- custom breed function
if parent1.on_breed then
-- when false, skip going any further
if parent1.on_breed(parent1, parent2) == false then
return
end
end
if parent1.on_breed and not parent1.on_breed(parent1, parent2) then return end
pos = vector.round(pos)
local child = mcl_mobs.spawn_child(pos, parent1.name)
if not child then return end
local ent_c = child:get_luaentity()
-- Use texture of one of the parents
local p = math.random(1, 2)
if p == 1 then
ent_c.base_texture = parent1.base_texture
else
ent_c.base_texture = parent2.base_texture
end
child:set_properties({
textures = ent_c.base_texture
})
ent_c.base_texture = math.random(1, 2) == 1 and parent1.base_texture or parent2.base_texture
child:set_properties({ textures = ent_c.base_texture })
-- tamed and owned by parents' owner
ent_c.tamed = true
ent_c.owner = parent1.owner
end, self, ent, pos)
num = 0
break
end
end
@ -311,9 +244,7 @@ function mob_class:check_breeding()
end
function mob_class:toggle_sit(clicker,p)
if not self.tamed or self.child or self.owner ~= clicker:get_player_name() then
return
end
if not self.tamed or self.child or self.owner ~= clicker:get_player_name() then return end
local pos = self.object:get_pos()
local particle
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)
minetest.add_particle({
pos = vector.add(pos, pp),
velocity = {x=0,y=0.2,z=0},
velocity = vector.new(0, 0.2, 0),
expirationtime = 1,
size = 4,
texture = particle,

View File

@ -27,10 +27,12 @@ local vector_offset = vector.offset
local vector_new = vector.new
local vector_copy = vector.copy
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
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
-- get this mob to attack the object
@ -60,7 +62,7 @@ local function entity_physics(pos, radius)
if dist < 1 then dist = 1 end
local damage = floor((4 / dist) * radius)
local ent = objs[n]:get_luaentity()
--local ent = objs[n]:get_luaentity()
-- punches work on entities AND players
objs[n]:punch(objs[n], 1.0, {
@ -143,7 +145,7 @@ function mob_class:smart_mobs(s, p, dist, dtime)
if use_pathfind then
-- lets try find a path, first take care of positions
-- 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
-- also adjust height for player models!
@ -381,7 +383,7 @@ function mob_class:npc_attack()
p.y = p.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_player = obj.object
end
@ -605,7 +607,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
local v = self.object:get_velocity()
if not v then return end
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
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
end
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
kb = kb + luaentity._knockback * 0.25
end
@ -695,11 +697,8 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
local alert_pos = hitter:get_pos()
if alert_pos then
local objs = minetest.get_objects_inside_radius(alert_pos, self.view_range)
local obj = nil
for n = 1, #objs do
obj = objs[n]:get_luaentity()
local obj = objs[n]:get_luaentity()
if obj then
-- only alert members of same mob or friends
if obj.group_attack
@ -768,17 +767,16 @@ function mob_class:do_states_attack(dtime)
if self.timer > 100 then self.timer = 1 end
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
if not self.attack
or not self.attack:get_pos()
or not self:object_in_range(self.attack)
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)
return
@ -955,7 +953,7 @@ function mob_class:do_states_attack(dtime)
self.path.stuck_timer = 0
self.path.following = false -- not stuck anymore
self:set_velocity( 0)
self:set_velocity(0)
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
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)
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 not self.strafe_direction then self.strafe_direction = HALFPI end
if random(40) == 1 then self.strafe_direction = self.strafe_direction * -1 end
if not self.strafe_direction then self.strafe_direction = math.random(0, 1) * 2 - 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
if self.avoid_distance and dist < self.avoid_distance and self.shooter_avoid_enemy then
local f = (self.avoid_distance - dist) / self.avoid_distance
--self:set_velocity(f * self.walk_velocity) --self.object:add_velocity(vector_new(-sin(dir) * f, 0, cos(dir) * f))
self.acceleration.x = self.acceleration.x - sin(dir) * f * 8
self.acceleration.z = self.acceleration.z + cos(dir) * f * 8
if self.avoid_distance and self.shooter_avoid_enemy then
local f = (dist - self.avoid_distance) / self.avoid_distance
f = math.max(-1, math.min(1, f))
f = f * math.abs(f)
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
else
self:set_velocity(0)

View File

@ -1,6 +1,6 @@
local math, tonumber, vector, minetest, mcl_mobs = math, tonumber, vector, minetest, mcl_mobs
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 disable_blood = minetest.settings:get_bool("mobs_disable_blood")
@ -128,7 +128,7 @@ function mob_class:remove_texture_mod(mod)
table.insert(remove, i)
end
end
for i=#remove, 1 do
for i=#remove, 1, -1 do
table.remove(self.texture_mods, remove[i])
end
self.object:set_texture_mod(full_mod)
@ -207,7 +207,7 @@ function mob_class:set_animation(anim, fixed_frame)
elseif not self.object:get_attach() then
self.jockey = nil
end
if self.state == "die" and anim ~= "die" and anim ~= "stand" then return end
if self.fly and self:flight_check() and anim == "walk" then anim = "fly" end
@ -275,7 +275,8 @@ function mob_class:check_head_swivel(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
local ov = self.object:get_bone_override(self.head_swivel)
oldp, oldr = ov.position.vec, ov.rotation.vec
@ -327,7 +328,7 @@ function mob_class:check_head_swivel(dtime)
elseif not locked_object and math.abs(oldr.y) > 0.05 and math.abs(oldr.x) < 0.05 then
newr = vector.multiply(oldr, 0.9)
end
-- 0.02 is about 1.14 degrees tolerance, to update less often
local newp = vector.new(0, self.bone_eye_height, self.horizontal_head_height)
if math.abs(oldr.x-newr.x) + math.abs(oldr.y-newr.y) + math.abs(oldr.z-newr.z) < 0.02 and vector.equals(oldp, newp) then return end

View File

@ -38,7 +38,7 @@ local function line_of_sight(origin, target, see_through_opaque, liquids)
end
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
-- effects: sounds and particles mostly
@ -417,7 +417,6 @@ function mcl_mobs.register_arrow(name, def)
hit_object = def.hit_object,
homing = def.homing,
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,
switch = 0,
_lifetime = def._lifetime or 7,

View File

@ -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
--- Item and armor management

View File

@ -126,7 +126,7 @@ function mcl_mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
-- jump
if ctrl.jump 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
end
end

View File

@ -8,7 +8,7 @@ local CHECK_HERD_FREQUENCY = 4
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 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 sin = math.sin
local cos = math.cos
local abs = math.abs
local floor = math.floor
local PI = math.pi
local TWOPI = 2 * math.pi
@ -24,12 +23,9 @@ local HALFPI = 0.5 * math.pi
local QUARTERPI = 0.25 * math.pi
local vector_new = vector.new
local vector_zero = vector.zero
local vector_copy = vector.copy
local vector_offset = vector.offset
local vector_distance = vector.distance
local node_ok = mcl_mobs.node_ok
local mobs_see_through_opaque = mcl_mobs.see_through_opaque
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 ndef = minetest.registered_nodes[nod.name]
-- 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
-- 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 nod.name == NODE_SNOW or (ndef and ndef.groups.carpet or 0) > 0 then return false end
-- nothing to jump on?
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
self.facing_fence = true
return false
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(-self.fall_speed, math.max(v.y, self.fall_speed))
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)
end
if on_replace_return ~= false then
if mobs_griefing then
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
local s = self.object:get_pos()
local p, sp, dist
local player, obj, min_player
local type, name = "", ""
local min_dist = self.view_range + 1
local min_dist, min_player = self.view_range + 1, nil
local objs = minetest.get_objects_inside_radius(s, self.view_range)
for n = 1, #objs do
local name, player = "", nil
if objs[n]:is_player() then
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
type = ""
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
name = ""
else
player = objs[n]
type = "player"
name = "player"
end
else
obj = objs[n]:get_luaentity()
local obj = objs[n]:get_luaentity()
if obj then
player = obj.object
type = obj.type
name = obj.name or ""
end
end
-- find specific mob to runaway from
if name ~= "" and name ~= self.name
and specific_runaway(self.runaway_from, name) then
p = player:get_pos()
sp = s
dist = vector_distance(p, s)
if name ~= "" and name ~= self.name and specific_runaway(self.runaway_from, name) then
local p = player:get_pos()
local dist = vector_distance(p, s)
-- 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
min_dist = dist
min_player = player
@ -458,7 +446,7 @@ function mob_class:check_runaway_from()
end
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.state = "runaway"
self.runaway_timer = 3
@ -474,10 +462,9 @@ function mob_class:check_follow()
and self.state ~= "attack"
and self.order ~= "sit"
and self.state ~= "runaway" then
local s = self.object:get_pos()
local players = minetest.get_connected_players()
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]
break
end
@ -592,7 +579,7 @@ function mob_class:do_states_walk()
-- 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"})
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
-- TODO: use node with smallest change in yaw instead of random?
lp = #lp > 0 and lp[random(#lp)]
@ -617,7 +604,7 @@ function mob_class:do_states_walk()
-- facing wall? then turn
local facing_wall = false
-- 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
else --if not facing_wall then
local cbox = self.collisionbox

View File

@ -1,6 +1,6 @@
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
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 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 cos = math.cos
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 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
function mob_class:update_standing(pos, moveresult)
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
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 = 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)
if not self.standing_on.walkable and moveresult and moveresult.collisions then
-- to inspect: minetest.log("action", dump(moveresult):gsub(" *\n\\s*",""))
@ -103,13 +105,10 @@ end
function mob_class:item_drop(cooked, looting_level)
if not mobs_drop_items then return end
if self.child and self.type ~= "monster" then return end
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()
self.drops = self.drops or {}
for n = 1, #self.drops do
@ -139,7 +138,7 @@ function mob_class:item_drop(cooked, looting_level)
end
if num > 0 then
item = dropdef.name
local item = dropdef.name
if cooked then
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
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
obj:set_velocity(vector.new((random() - 0.5) * 1.5, 6, (random() - 0.5) * 1.5))
elseif obj then
@ -191,8 +189,11 @@ function mob_class:collision()
end
-- 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_orth = o
end
-- calculate mob velocity (3d)
@ -245,7 +246,7 @@ function mob_class:set_yaw(yaw, delay, dtime)
end
-- name tag easter egg, test engine capabilities for rolling
local function update_roll()
--[[local function update_roll(self)
local is_Fleckenstein = self.nametag == "Fleckenstein"
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)
end
self.is_Fleckenstein = is_Fleckenstein
end
end]]
-- Improved smooth rotation
-- @param dtime number: timestep length
@ -288,7 +289,7 @@ function mob_class:smooth_rotation(dtime)
yaw = yaw + (random() * 2 - 1) / 72 * dtime
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
-- Handling of intentional acceleration by the mob
@ -296,11 +297,13 @@ end
-- TODO: have mobs that acccelerate faster and that accelerate slower?
-- @param dtime number: timestep length
function mob_class:smooth_acceleration(dtime)
local yaw = self.target_yaw or (self.object:get_yaw() or 0) + self.rotate
local vel = self.target_vel or 0
local x, z = -sin(yaw) * vel, cos(yaw) * vel
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 -- can also stop
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 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)
self.object:set_velocity(v)
end
@ -874,7 +877,6 @@ function mob_class:limit_vel_acc_for_large_dtime(pos, dtime, moveresult)
end
--- Update velocity and acceleration at the end of our movement logic
--
function mob_class:update_vel_acc(dtime)
local vel = self.object:get_velocity()
--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
if vec.x ~= 0 or vec.y ~= 0 or vec.z ~= 0 then
-- 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
self.acceleration = self.acceleration + vector.new(vec.x * f, -0.22, vec.z * f)
--self.physical_state = true