sapier 5d48fbcfee Removed env reference
Added support for animation speed changing (requires core patch)
2013-05-26 13:35:33 +02:00

274 lines
7.9 KiB
Lua

-------------------------------------------------------------------------------
-- Mob Framework Mod by Sapier
--
-- You may copy, use, modify or do nearly anything except removing this
-- copyright notice.
-- And of course you are NOT allow to pretend you have written it.
--
--! @file path_based_movement_gen.lua
--! @brief component containing a path based movement generator
--! @copyright Sapier
--! @author Sapier
--! @date 2012-08-09
--
--! @defgroup mgen_path_based MGEN: Path based movement generator
--! @ingroup framework_int
--! @{
-- Contact sapier a t gmx net
-------------------------------------------------------------------------------
--! @class p_mov_gen
--! @brief a movement generator evaluating a path to a target and following it
--!@}
p_mov_gen = {}
--! @brief movement generator identifier
--! @memberof p_mov_gen
p_mov_gen.name = "mgen_path"
-------------------------------------------------------------------------------
-- name: callback(entity,now)
--
--! @brief path based movement generator callback
--! @memberof p_mov_gen
--
-- param1: mob to do movement
-- param2: current time
-- retval: -
-------------------------------------------------------------------------------
function p_mov_gen.callback(entity,now,dstep)
mobf_assert_backtrace(entity ~= nil)
mobf_assert_backtrace(entity.dynamic_data ~= nil)
mobf_assert_backtrace(entity.dynamic_data.p_movement ~= nil)
if entity.dynamic_data.p_movement.eta ~= nil then
if now < entity.dynamic_data.p_movement.eta then
return
end
end
local current_pos = entity.object:getpos()
local handled = false
if entity.dynamic_data.p_movement.path == nil then
dbg_mobf.path_mov_lvl1(
"MOBF: path movement but mo path set!!")
return
end
local max_distance = entity.data.movement.max_distance
if entity.dynamic_data.movement.max_distance ~= nil then
max_distance = entity.dynamic_data.movement.max_distance
end
mobf_assert_backtrace(entity.dynamic_data.p_movement.next_path_index ~= nil)
mobf_assert_backtrace(max_distance ~= nil)
--check if target is reached
if p_mov_gen.distance_to_next_point(entity,current_pos)
< max_distance then
dbg_mobf.path_mov_lvl1("MOBF: pathmov next to next point switching target")
local update_target = true
--return to begining of path
if entity.dynamic_data.p_movement.next_path_index
== #entity.dynamic_data.p_movement.path then
if entity.data.patrol ~= nil and
entity.data.patrol.cycle_path then
--0 is correct as it's incremented by one later
entity.dynamic_data.p_movement.next_path_index = 0
else
dbg_mobf.path_mov_lvl1("MOBF: cycle not set not updating point")
update_target = false
end
end
if update_target then
entity.dynamic_data.p_movement.next_path_index =
entity.dynamic_data.p_movement.next_path_index + 1
entity.dynamic_data.movement.target =
entity.dynamic_data.p_movement.path
[entity.dynamic_data.p_movement.next_path_index]
dbg_mobf.path_mov_lvl1("MOBF: (1) setting new target to index: " ..
entity.dynamic_data.p_movement.next_path_index .. " pos: " ..
printpos(entity.dynamic_data.movement.target))
handled = true
end
end
if not handled and
entity.dynamic_data.movement.target == nil then
entity.dynamic_data.movement.target =
entity.dynamic_data.p_movement.path
[entity.dynamic_data.p_movement.next_path_index]
dbg_mobf.path_mov_lvl1("MOBF: (2) setting new target to index: " ..
entity.dynamic_data.p_movement.next_path_index .. " pos: " ..
printpos(entity.dynamic_data.movement.target))
end
mgen_follow.callback(entity,now)
end
-------------------------------------------------------------------------------
-- name: distance_to_next_point(entity)
--
--! @brief get distance to next target point (2d only)
--! @memberof p_mov_gen
--! @private
--
--! @param entity mob to check
--! @param current_pos position mob is atm
--
--! @retval distance
-------------------------------------------------------------------------------
function p_mov_gen.distance_to_next_point(entity,current_pos)
local index = entity.dynamic_data.p_movement.next_path_index
mobf_assert_backtrace(entity.dynamic_data.p_movement.path ~= nil)
mobf_assert_backtrace(index <= #entity.dynamic_data.p_movement.path)
return mobf_calc_distance_2d(current_pos,
entity.dynamic_data.p_movement.path[index])
end
-------------------------------------------------------------------------------
-- name: init_dynamic_data(entity,now)
--
--! @brief initialize dynamic data required by movement generator
--! @memberof p_mov_gen
--
--! @param entity to initialize
--! @param now current time
--! @param restored_data data restored on activate
-------------------------------------------------------------------------------
function p_mov_gen.init_dynamic_data(entity,now,restored_data)
local pos = entity.object:getpos()
local data = {
path = nil,
eta = nil,
last_move_stop = now,
next_path_index = 1,
force_target = nil,
pathowner = nil,
pathname = nil,
}
if restored_data ~= nil then
dbg_mobf.path_mov_lvl3(
"MOBF: path movement reading stored data: " .. dump(restored_data))
if restored_data.pathowner ~= nil and
restored_data.pathname ~= nil then
data.pathowner = restored_data.pathowner
data.pathname = restored_data.pathname
data.path = mobf_path.getpoints(data.pathowner,data.pathname)
dbg_mobf.path_mov_lvl3(
"MOBF: path movement restored points: " .. dump(data.path))
end
if restored_data.pathindex ~= nil and
type(restored_data.pathindex) == "number" and
restored_data.pathindex > 0 and
data.path ~= nil and
restored_data.pathindex < #data.path then
data.next_path_index = restored_data.pathindex
end
end
entity.dynamic_data.p_movement = data
mgen_follow.init_dynamic_data(entity,now)
end
-------------------------------------------------------------------------------
-- name: set_target(entity,target)
--
--! @brief set target for movgen
--! @memberof p_mov_gen
--! @public
--
--! @param entity mob to apply to
--! @param target to set
-------------------------------------------------------------------------------
function p_mov_gen.set_target(entity,target)
mobf_assert_backtrace(target ~= nil)
local current_pos = entity.getbasepos(entity)
local targetpos = nil
if not mobf_is_pos(target) then
if target:is_player() then
targetpos = target:getpos()
targetpos.y = targetpos.y +0.5
else
if type(target.getbasepos) == "function" then
targetpos = target.getbasepos(target)
else
targetpos = target:getpos()
end
end
else
targetpos = target
end
if targetpos == nil then
return false
end
if entity.dynamic_data.p_movement.lasttargetpos ~= nil then
if mobf_pos_is_same(entity.dynamic_data.p_movement.lasttargetpos,
targetpos) then
return true
end
end
entity.dynamic_data.p_movement.lasttargetpos = targetpos
entity.dynamic_data.p_movement.path = nil
entity.dynamic_data.p_movement.next_path_index = 1
--on target mode max distance is always 0.5
entity.dynamic_data.movement.max_distance = 0.5
--try to find path on our own
entity.dynamic_data.p_movement.path =
minetest.find_path(current_pos,targetpos,5,1,1,nil)
if entity.dynamic_data.p_movement.path ~= nil then
--a valid path has at least 2 positions
mobf_assert_backtrace(#entity.dynamic_data.p_movement.path > 1)
entity.dynamic_data.movement.target =
entity.dynamic_data.p_movement.path[2]
return true
end
if entity.dynamic_data.p_movement.path == nil then
print(
"MOBF: no pathfinding support/ no path found directly setting targetpos as path")
entity.dynamic_data.p_movement.path = {}
table.insert(entity.dynamic_data.p_movement.path,targetpos)
entity.dynamic_data.movement.target =
entity.dynamic_data.p_movement.path[1]
return true
end
return false
end
--register this movement generator
registerMovementGen(p_mov_gen.name,p_mov_gen)