Use better algorithm for correcting too fast mob movement
This commit is contained in:
parent
65b0f4739a
commit
73fb95bfb4
@ -1,8 +1,8 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file main_follow.lua
|
||||
@ -12,10 +12,10 @@
|
||||
--! @date 2012-08-09
|
||||
--
|
||||
--! @defgroup mgen_follow MGEN: follow movement generator
|
||||
--! @brief A movement generator creating movement that trys to follow a moving
|
||||
--! @brief A movement generator creating movement that trys to follow a moving
|
||||
--! target or reach a given point on map
|
||||
--! @ingroup framework_int
|
||||
--! @{
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@ -51,21 +51,21 @@ mgen_follow.name = "follow_mov_gen"
|
||||
function mgen_follow.identify_movement_state(ownpos,targetpos)
|
||||
mobf_assert_backtrace(ownpos ~= nil)
|
||||
mobf_assert_backtrace(targetpos ~= nil)
|
||||
|
||||
|
||||
local same_height_delta = 0.1
|
||||
|
||||
|
||||
local los = mobf_line_of_sight(ownpos,targetpos)
|
||||
|
||||
|
||||
if ownpos.y > targetpos.y - same_height_delta and
|
||||
ownpos.y < targetpos.y + same_height_delta then
|
||||
|
||||
|
||||
if los then
|
||||
return "same_height_los"
|
||||
else
|
||||
return "same_height_no_los"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if ownpos.y < targetpos.y then
|
||||
if los then
|
||||
return "below_los"
|
||||
@ -81,7 +81,7 @@ function mgen_follow.identify_movement_state(ownpos,targetpos)
|
||||
return "above_no_los"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return "unknown"
|
||||
end
|
||||
|
||||
@ -103,14 +103,14 @@ function mgen_follow.handleteleport(entity,now,targetpos)
|
||||
if (entity.dynamic_data.movement.last_next_to_target ~= nil ) then
|
||||
local time_since_next_to_target =
|
||||
now - entity.dynamic_data.movement.last_next_to_target
|
||||
|
||||
dbg_mobf.fmovement_lvl3("MOBF: time since next to target: " .. time_since_next_to_target ..
|
||||
|
||||
dbg_mobf.fmovement_lvl3("MOBF: time since next to target: " .. time_since_next_to_target ..
|
||||
" delay: " .. dump(entity.data.movement.teleportdelay) ..
|
||||
" teleportsupport: " .. dump(entity.dynamic_data.movement.teleportsupport))
|
||||
|
||||
if (entity.dynamic_data.movement.teleportsupport) and
|
||||
time_since_next_to_target > entity.data.movement.teleportdelay then
|
||||
|
||||
|
||||
--check targetpos try to playe above if not valid
|
||||
local maxoffset = 5
|
||||
local current_offset = 0
|
||||
@ -123,9 +123,9 @@ function mgen_follow.handleteleport(entity,now,targetpos)
|
||||
print("MOBF: teleport target within block trying above: " .. current_offset)
|
||||
current_offset = current_offset +1
|
||||
end
|
||||
|
||||
|
||||
targetpos.y = targetpos.y + current_offset
|
||||
|
||||
|
||||
--adjust to collisionbox of mob
|
||||
if entity.collisionbox[2] < -0.5 then
|
||||
targetpos.y = targetpos.y - (entity.collisionbox[2] + 0.49)
|
||||
@ -153,20 +153,20 @@ end
|
||||
function mgen_follow.callback(entity,now)
|
||||
|
||||
dbg_mobf.fmovement_lvl3("MOBF: Follow mgen callback called")
|
||||
|
||||
|
||||
if entity == nil then
|
||||
mobf_bug_warning(LOGLEVEL_ERROR,"MOBF BUG!!!: called movement gen without entity!")
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
if entity.dynamic_data == nil or
|
||||
entity.dynamic_data.movement == nil then
|
||||
mobf_bug_warning(LOGLEVEL_ERROR,"MOBF BUG!!!: >" ..entity.data.name .. "< removed=" .. dump(entity.removed) .. " entity=" .. tostring(entity) .. " probab movement callback")
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local follow_speedup = {x=10,y=2,z=10 }
|
||||
|
||||
|
||||
if entity.data.movement.follow_speedup ~= nil then
|
||||
if type(entity.data.movement.follow_speedup) == "table" then
|
||||
follow_speedup = entity.data.movement.follow_speedup
|
||||
@ -175,17 +175,17 @@ function mgen_follow.callback(entity,now)
|
||||
follow_speedup.z= entity.data.movement.follow_speedup
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--check max speed limit
|
||||
mgen_follow.checkspeed(entity)
|
||||
|
||||
|
||||
|
||||
|
||||
--check environment
|
||||
local basepos = entity.getbasepos(entity)
|
||||
local pos_quality = environment.pos_quality(basepos,entity)
|
||||
|
||||
|
||||
if environment.evaluate_state(pos_quality, LT_GOOD_POS) or
|
||||
(entity.data.movement.canfly and
|
||||
(entity.data.movement.canfly and
|
||||
environment.evaluate_state(pos_quality,LT_GOOD_FLY_POS)) then
|
||||
local toset = {
|
||||
x= basepos.x,
|
||||
@ -194,21 +194,21 @@ function mgen_follow.callback(entity,now)
|
||||
--save known good position
|
||||
entity.dynamic_data.movement.last_pos_in_env = toset
|
||||
end
|
||||
|
||||
|
||||
if pos_quality.media_quality == MQ_IN_AIR or -- wrong media
|
||||
pos_quality.media_quality == MQ_IN_WATER or -- wrong media
|
||||
pos_quality.geometry_quality == GQ_NONE or -- no ground contact (TODO this was drop above water before)
|
||||
pos_quality.surface_quality_min == SQ_WATER then -- above water
|
||||
|
||||
|
||||
|
||||
|
||||
if entity.dynamic_data.movement.invalid_env_count == nil then
|
||||
entity.dynamic_data.movement.invalid_env_count = 0
|
||||
end
|
||||
|
||||
entity.dynamic_data.movement.invalid_env_count =
|
||||
|
||||
entity.dynamic_data.movement.invalid_env_count =
|
||||
entity.dynamic_data.movement.invalid_env_count + 1
|
||||
|
||||
|
||||
|
||||
|
||||
--don't change at first invalid pos but give some steps to cleanup by
|
||||
--other less invasive mechanisms
|
||||
if entity.dynamic_data.movement.invalid_env_count > 10 then
|
||||
@ -218,7 +218,7 @@ function mgen_follow.callback(entity,now)
|
||||
basepos = entity.getbasepos(entity)
|
||||
else
|
||||
local newpos = environment.get_suitable_pos_same_level(basepos,1,entity,true)
|
||||
|
||||
|
||||
if newpos == nil then
|
||||
newpos = environment.get_suitable_pos_same_level( {
|
||||
x=basepos.x,
|
||||
@ -226,7 +226,7 @@ function mgen_follow.callback(entity,now)
|
||||
z=basepos.z }
|
||||
,1,entity,true)
|
||||
end
|
||||
|
||||
|
||||
if newpos == nil then
|
||||
newpos = environment.get_suitable_pos_same_level( {
|
||||
x=basepos.x,
|
||||
@ -234,7 +234,7 @@ function mgen_follow.callback(entity,now)
|
||||
z=basepos.z }
|
||||
,1,entity,true)
|
||||
end
|
||||
|
||||
|
||||
if newpos == nil then
|
||||
dbg_mobf.fmovement_lvl1("MOBF: no way to fix it removing mob")
|
||||
spawning.remove(entity,"mgen_follow poscheck")
|
||||
@ -248,116 +248,116 @@ function mgen_follow.callback(entity,now)
|
||||
else
|
||||
entity.dynamic_data.movement.invalid_env_count = 0
|
||||
end
|
||||
|
||||
if pos_quality.level_quality ~= LQ_OK and
|
||||
|
||||
if pos_quality.level_quality ~= LQ_OK and
|
||||
entity.data.movement.canfly then
|
||||
local current_accel = entity.object:getacceleration()
|
||||
|
||||
|
||||
if pos_quality.level_quality == LQ_ABOVE then
|
||||
if current_accel.y >= 0 then
|
||||
current_accel.y = - entity.data.movement.max_accel
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if pos_quality.level_quality == LQ_BELOW then
|
||||
local current_accel = entity.object:getacceleration()
|
||||
if current_accel.y <= 0 then
|
||||
current_accel.y = entity.data.movement.max_accel
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
entity.object:setacceleration(current_accel)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
--fixup height fixup
|
||||
if entity.data.movement.canfly then
|
||||
local current_accel = entity.object:getacceleration()
|
||||
|
||||
|
||||
if current_accel.y ~= 0 then
|
||||
current_accel.y = 0
|
||||
entity.object:setacceleration(current_accel)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if entity.dynamic_data.movement.target ~= nil or
|
||||
entity.dynamic_data.movement.guardspawnpoint then
|
||||
dbg_mobf.fmovement_lvl3("MOBF: Target available")
|
||||
--calculate distance to target
|
||||
local targetpos = nil
|
||||
|
||||
|
||||
if entity.dynamic_data.movement.target ~= nil then
|
||||
dbg_mobf.fmovement_lvl3("MOBF: have moving target")
|
||||
|
||||
|
||||
if not mobf_is_pos(entity.dynamic_data.movement.target) then
|
||||
targetpos = entity.dynamic_data.movement.target:getpos()
|
||||
else
|
||||
targetpos = entity.dynamic_data.movement.target
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if targetpos == nil and
|
||||
entity.dynamic_data.movement.guardspawnpoint == true then
|
||||
dbg_mobf.fmovement_lvl3("MOBF: non target selected")
|
||||
targetpos = entity.dynamic_data.spawning.spawnpoint
|
||||
targetpos = entity.dynamic_data.spawning.spawnpoint
|
||||
end
|
||||
|
||||
|
||||
if targetpos == nil then
|
||||
mobf_bug_warning(LOGLEVEL_ERROR,"MOBF: " .. entity.data.name
|
||||
.. " don't have targetpos "
|
||||
mobf_bug_warning(LOGLEVEL_ERROR,"MOBF: " .. entity.data.name
|
||||
.. " don't have targetpos "
|
||||
.. "SP: " .. dump(entity.dynamic_data.spawning.spawnpoint)
|
||||
.. " TGT: " .. dump(entity.dynamic_data.movement.target))
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local distance = mobf_calc_distance(basepos,targetpos)
|
||||
|
||||
|
||||
if mobf_line_of_sight({x=basepos.x,y=basepos.y+1,z=basepos.z},
|
||||
{x=targetpos.x,y=targetpos.y+1,z=targetpos.z}) == false then
|
||||
dbg_mobf.fmovement_lvl3("MOBF: no line of sight")
|
||||
--TODO teleport support?
|
||||
--TODO other ways to handle this?
|
||||
--return
|
||||
--return
|
||||
end
|
||||
--dbg_mobf.fmovement_lvl3("MOBF: line of sight")
|
||||
|
||||
|
||||
local max_distance = entity.dynamic_data.movement.max_distance
|
||||
|
||||
|
||||
if max_distance == nil then
|
||||
max_distance = 1
|
||||
end
|
||||
|
||||
|
||||
--check if mob needs to move towards target
|
||||
dbg_mobf.fmovement_lvl3("MOBF: max distance is set to : "
|
||||
dbg_mobf.fmovement_lvl3("MOBF: max distance is set to : "
|
||||
.. max_distance .. " dist: " .. distance)
|
||||
if distance > max_distance then
|
||||
entity.dynamic_data.movement.was_moving_last_step = true
|
||||
|
||||
|
||||
if mgen_follow.handleteleport(entity,now,targetpos) then
|
||||
return
|
||||
end
|
||||
|
||||
dbg_mobf.fmovement_lvl3("MOBF: distance:" .. distance)
|
||||
|
||||
|
||||
local current_state =
|
||||
mgen_follow.identify_movement_state(basepos,targetpos)
|
||||
local handled = false
|
||||
|
||||
if handled == false and
|
||||
|
||||
if handled == false and
|
||||
(current_state == "same_height_los" or
|
||||
current_state == "above_los" or
|
||||
current_state == "above_no_los" ) then
|
||||
dbg_mobf.fmovement_lvl3("MOBF: \t Case 1: " .. current_state)
|
||||
local accel_to_set =
|
||||
movement_generic.get_accel_to(targetpos,entity,true)
|
||||
|
||||
handled =
|
||||
|
||||
handled =
|
||||
mgen_follow.set_acceleration(entity,
|
||||
accel_to_set,
|
||||
follow_speedup,
|
||||
basepos)
|
||||
end
|
||||
|
||||
|
||||
if handled == false and
|
||||
(current_state == "below_los" or
|
||||
current_state == "below_no_los" or
|
||||
@ -365,23 +365,23 @@ function mgen_follow.callback(entity,now)
|
||||
dbg_mobf.fmovement_lvl3("MOBF: \t Case 2: " .. current_state)
|
||||
local accel_to_set =
|
||||
movement_generic.get_accel_to(targetpos,entity)
|
||||
|
||||
|
||||
--seems to be a flying mob
|
||||
if (accel_to_set.y >0) then
|
||||
handled =
|
||||
handled =
|
||||
mgen_follow.set_acceleration(entity,
|
||||
accel_to_set,
|
||||
follow_speedup,
|
||||
basepos)
|
||||
else
|
||||
local current_velocity = entity.object:getvelocity()
|
||||
local predicted_pos =
|
||||
local predicted_pos =
|
||||
movement_generic.predict_next_block(basepos,
|
||||
current_velocity,
|
||||
accel_to_set)
|
||||
|
||||
|
||||
--TODO replace by quality based mechanism!!!!!!!------------
|
||||
local pos_state =
|
||||
local pos_state =
|
||||
environment.pos_is_ok(predicted_pos,entity)
|
||||
if pos_state == "collision_jumpable" then
|
||||
local pos_to_set = entity.object:getpos()
|
||||
@ -390,11 +390,11 @@ function mgen_follow.callback(entity,now)
|
||||
basepos.y=basepos.y+1.1
|
||||
end
|
||||
------------------------------------------------------------
|
||||
|
||||
dbg_mobf.fmovement_lvl3("MOBF: setting acceleration to: "
|
||||
|
||||
dbg_mobf.fmovement_lvl3("MOBF: setting acceleration to: "
|
||||
.. printpos(accel_to_set) .. " predicted_state: "
|
||||
.. pos_state);
|
||||
handled =
|
||||
handled =
|
||||
mgen_follow.set_acceleration(entity,
|
||||
accel_to_set,
|
||||
follow_speedup,
|
||||
@ -418,16 +418,16 @@ function mgen_follow.callback(entity,now)
|
||||
local yaccel = environment.get_default_gravity(basepos,
|
||||
entity.environment.media,
|
||||
entity.data.movement.canfly)
|
||||
|
||||
|
||||
dbg_mobf.fmovement_lvl3("MOBF: next to target")
|
||||
entity.object:setvelocity({x=0,y=0,z=0})
|
||||
entity.object:setacceleration({x=0,y=yaccel,z=0})
|
||||
entity.dynamic_data.movement.last_next_to_target = now
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
else
|
||||
--TODO evaluate if this is an error case
|
||||
--TODO evaluate if this is an error case
|
||||
end
|
||||
end
|
||||
|
||||
@ -440,17 +440,17 @@ end
|
||||
-------------------------------------------------------------------------------
|
||||
function mgen_follow.next_block_ok(entity,pos,acceleration,velocity)
|
||||
local current_velocity = velocity
|
||||
|
||||
|
||||
if current_velocity == nil then
|
||||
current_velocity = entity.object:getvelocity()
|
||||
end
|
||||
|
||||
|
||||
local predicted_pos = movement_generic.predict_next_block(pos,current_velocity,acceleration)
|
||||
|
||||
|
||||
local quality = environment.pos_quality(predicted_pos,entity)
|
||||
|
||||
|
||||
return (
|
||||
(quality.media_quality == MQ_IN_MEDIA) and
|
||||
(quality.media_quality == MQ_IN_MEDIA) and
|
||||
(quality.level_quality == LQ_OK) and
|
||||
(
|
||||
(quality.surface_quality_min == Q_UNKNOWN) or
|
||||
@ -491,18 +491,18 @@ function mgen_follow.init_dynamic_data(entity,now)
|
||||
max_distance = entity.data.movement.max_distance,
|
||||
invalid_env_count = 0,
|
||||
}
|
||||
|
||||
|
||||
if entity.data.movement.guardspawnpoint ~= nil and
|
||||
entity.data.movement.guardspawnpoint then
|
||||
dbg_mobf.fmovement_lvl3("MOBF: setting guard point to: " .. printpos(entity.dynamic_data.spawning.spawnpoint))
|
||||
data.guardspawnpoint = true
|
||||
end
|
||||
|
||||
|
||||
if entity.data.movement.teleportdelay~= nil then
|
||||
data.last_next_to_target = now
|
||||
data.teleportsupport = true
|
||||
end
|
||||
|
||||
|
||||
entity.dynamic_data.movement = data
|
||||
end
|
||||
|
||||
@ -519,22 +519,26 @@ function mgen_follow.checkspeed(entity)
|
||||
|
||||
local current_velocity = entity.object:getvelocity()
|
||||
|
||||
local xzspeed =
|
||||
local xzspeed =
|
||||
mobf_calc_scalar_speed(current_velocity.x,current_velocity.z)
|
||||
|
||||
if (xzspeed > entity.data.movement.max_speed) then
|
||||
|
||||
--preserver orientation when correcting speed
|
||||
local dir = mobf_calc_yaw(current_velocity.x,current_velocity.z)
|
||||
local velocity_to_set = mobf_calc_vector_components(dir,entity.data.movement.max_speed * 0.25)
|
||||
|
||||
velocity_to_set.y=current_velocity.y
|
||||
|
||||
entity.object:setvelocity(velocity_to_set)
|
||||
|
||||
|
||||
local direction = mobf_calc_yaw(current_velocity.x,
|
||||
current_velocity.z)
|
||||
|
||||
--reduce speed to 90% of current speed
|
||||
local new_speed = mobf_calc_vector_components(direction,xzspeed*0.9)
|
||||
|
||||
local current_accel = entity.object:getacceleration()
|
||||
|
||||
new_speed.y = current_velocity.y
|
||||
entity.object:setvelocity(new_speed)
|
||||
entity.object:setacceleration({x=0,y=current_accel.y,z=0})
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
@ -554,7 +558,7 @@ function mgen_follow.set_acceleration(entity,accel,speedup,pos)
|
||||
|
||||
accel.x = accel.x*speedup.x
|
||||
accel.z = accel.z*speedup.z
|
||||
|
||||
|
||||
if entity.data.movement.canfly then
|
||||
accel.y = accel.y*speedup.y
|
||||
end
|
||||
@ -571,7 +575,7 @@ function mgen_follow.set_acceleration(entity,accel,speedup,pos)
|
||||
else
|
||||
local current_velocity = entity.object:getvelocity()
|
||||
current_velocity.y = 0
|
||||
|
||||
|
||||
if mgen_follow.next_block_ok(entity,pos,{x=0,y=0,z=0},current_velocity) then
|
||||
accel_to_set = {x=0,y=0,z=0}
|
||||
entity.object:setvelocity(current_velocity)
|
||||
@ -579,11 +583,11 @@ function mgen_follow.set_acceleration(entity,accel,speedup,pos)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
dbg_mobf.fmovement_lvl1(
|
||||
"MOBF: \t acceleration " .. printpos(accel) ..
|
||||
" would result in invalid position not applying!")
|
||||
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user