dungeon/mods/mobf/mgen_probab/height_level_control.lua

292 lines
11 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 height_level_control.lua
--! @brief component containing random drop features
--! @copyright Sapier
--! @author Sapier
--! @date 2012-08-09
--
--! @ingroup mgen_probab
--! @{
-- Contact sapier a t gmx net
-------------------------------------------------------------------------------
--! @class height_level_control
--! @brief class containing height level functionality
height_level_control = {}
--!@}
-------------------------------------------------------------------------------
-- name: calc_level_change_time(entity)
--
--! @brief calculate time required to change one height level
--! @memberof height_level_control
--! @private
--
--! @param entity mob to calculate change time
--! @param default_accel default accel for mob
--! @return time in seconds
-------------------------------------------------------------------------------
function height_level_control.calc_level_change_time(entity,default_accel)
local retval = 1 --default value
--calculate a reasonable value to stop level change
if entity.data.movement.canfly == nil or
entity.data.movement.canfly == false then --case mob can't fly
return 0
else
-- if it's a flying mob and left it's normal medium
if default_accel ~= 0 then
retval = 0
else
retval = math.sqrt(2/entity.data.movement.min_accel)
end
end
return retval
end
-------------------------------------------------------------------------------
-- name: precheck_movement(entity,movement_state,pos_predicted,pos_predicted_state)
--
--! @brief check if there is a level change in progress that may
-- need to be stopped
--! @memberof height_level_control
--
--! @param entity mob to check for level change
--! @param movement_state current state of movement
--! @param pos_predicted position the mob will be next
--! @param pos_predicted_state state of the next position
-------------------------------------------------------------------------------
function height_level_control.precheck_movement(entity,movement_state,pos_predicted,pos_predicted_state)
if entity.data.movement.canfly ~= nil and
entity.data.movement.canfly == true and
entity.dynamic_data.movement.changing_levels == true then
local level_change_time = height_level_control.calc_level_change_time(entity,movement_state.default_y_accel)
local time_completed = entity.dynamic_data.movement.ts_random_jump + level_change_time
dbg_mobf.pmovement_lvl1("MOBF: ".. movement_state.now .. " " .. entity.data.name ..
" check complete level change " .. time_completed)
if entity.dynamic_data.movement.changing_levels and
time_completed < movement_state.now then
dbg_mobf.pmovement_lvl2("MOBF: ".. movement_state.now .. " " .. entity.data.name ..
" level change complete reestablishing default y acceleration " .. movement_state.default_y_accel)
entity.dynamic_data.movement.changing_levels = false
movement_state.current_velocity.y = 0
entity.object:setvelocity(movement_state.current_velocity)
movement_state.accel_to_set = movement_state.current_acceleration
movement_state.accel_to_set.y = movement_state.default_y_accel
movement_state.changed = true
end
end
--mob would fly/swim into height it shouldn't be
if movement_state.changed == false then
local invalid_pos_handled = false
--mob would fly/swim into height it shouldn't be
if invalid_pos_handled == false and
pos_predicted_state == "above_limit" then
local min_y,max_y = environment.get_absolute_min_max_pos(entity.environment,movement_state.basepos)
if (pos_predicted.y - max_y) > 10 then
movement_state.override_height_change_chance = 1
else
movement_state.override_height_change_chance = (pos_predicted.y - max_y)/10
end
invalid_pos_handled = true
end
--mob would fly/swim into height it shouldn't be
if invalid_pos_handled == false and
pos_predicted_state == "below_limit" then
local min_y,max_y = environment.get_absolute_min_max_pos(entity.environment,movement_state.basepos)
if (min_y - pos_predicted.y) > 10 then
movement_state.override_height_change_chance = 1
else
movement_state.override_height_change_chance = (min_y - pos_predicted.y)/10
end
end
end
end
-------------------------------------------------------------------------------
-- name: random_jump_fly(entity,movement_state)
--
--! @brief apply random jump for flying mobs
--! @memberof height_level_control
--! @private
--
--! @param entity mob to apply random jump
--! @param movement_state current movement state
--! @return movement_state is modified!
-------------------------------------------------------------------------------
function height_level_control.random_jump_fly(entity,movement_state)
--get some information
local accel_to_set = movement_state.current_acceleration
local current_state = environment.pos_is_ok(movement_state.basepos,entity)
--find direction
local ydirection = 1
if current_state == "ok" then
if math.random() <= 0.5 then
ydirection = -1
end
end
if current_state == "above_limit" then
ydirection = -1
end
--state "below_limit" is already handled by initialization value
--prepare basic information about what may be afterwards
local targetpos = {x=movement_state.basepos.x,y=movement_state.basepos.y+ydirection,z=movement_state.basepos.z}
local target_state = environment.pos_is_ok(targetpos,entity);
dbg_mobf.pmovement_lvl2("MOBF: " .. entity.data.name .." flying change y accel dir="..ydirection.." ypos="..movement_state.basepos.y..
" min="..entity.environment.min_height_above_ground..
" max="..entity.environment.max_height_above_ground..
" below="..target_state)
--really do level change
if (target_state == "ok") or
target_state == current_state then
local min_y, max_y = environment.get_absolute_min_max_pos(entity.environment,movement_state.basepos)
dbg_mobf.pmovement_lvl2("MOBF: check level borders current=".. movement_state.basepos.y ..
" min=" .. min_y ..
" max=" .. max_y)
movement_state.accel_to_set.y = ydirection * entity.data.movement.min_accel
entity.dynamic_data.movement.ts_random_jump = movement_state.now
entity.dynamic_data.movement.changing_levels = true
dbg_mobf.pmovement_lvl2("MOBF: " .. entity.data.name .. " " .. movement_state.now .. " " ..
" changing level within borders: " .. movement_state.accel_to_set.y)
movement_state.changed = true
end
end
-------------------------------------------------------------------------------
-- name: random_jump_ground(entity,movement_state)
--
--! @brief apply random jump for ground mobs
--! @memberof height_level_control
--! @private
--
--! @param entity mob to apply random jump
--! @param movement_state current movement state
--! @return movement_state is a modification!
-------------------------------------------------------------------------------
function height_level_control.random_jump_ground(entity,movement_state)
if movement_state.default_y_accel == 0 then
minetest.log(LOGLEVEL_ERROR,"MOBF BUG!!! ground mob can't have zero default acceleration!!!")
end
local random_jump_time = 2 * (entity.dynamic_data.movement.mpattern.random_jump_initial_speed /
math.abs(movement_state.default_y_accel))
local next_jump = entity.dynamic_data.movement.ts_random_jump +
entity.dynamic_data.movement.mpattern.random_jump_delay +
random_jump_time
dbg_mobf.movement_lvl2("MOBF: now=" .. movement_state.now .. " time of next jump=" .. next_jump ..
" | " .. random_jump_time .. " " .. entity.dynamic_data.movement.mpattern.random_jump_delay .. " " ..
entity.dynamic_data.movement.ts_random_jump .. " " .. movement_state.default_y_accel .. " " ..
entity.dynamic_data.movement.mpattern.random_jump_initial_speed)
if movement_state.now > next_jump then
local ground_distance = mobf_ground_distance(movement_state.basepos)
--we shouldn't be moving in y direction at that time so probably we are just dropping
--we can only jump while on solid ground!
if ground_distance <= 1 then
local current_speed = entity.object:getvelocity();
dbg_mobf.pmovement_lvl2("MOBF: " .. entity.data.name .." doing random jump "..
"speed: " .. entity.dynamic_data.movement.mpattern.random_jump_initial_speed ..
": ",entity)
current_speed.y = entity.dynamic_data.movement.mpattern.random_jump_initial_speed
entity.object:setvelocity(current_speed)
entity.dynamic_data.movement.ts_random_jump = movement_state.now
else
dbg_mobf.pmovement_lvl2("MOBF: " .. entity.data.name .. " Random jump but ground distance was:" .. ground_distance ..
" " ..movement_state.current_acceleration.y ..
" " ..movement_state.default_y_accel)
--this is a workaround for a bug
--setting y acceleration to 0 for ground born mobs shouldn't be possible
if movement_state.current_acceleration.y == 0 then
movement_state.accel_to_set.x = movement_state.current_acceleration.x
movement_state.accel_to_set.y = movement_state.default_y_accel
movement_state.accel_to_set.z = movement_state.current_acceleration.z
movement_state.changed = true
end
end
end
end
-------------------------------------------------------------------------------
-- name: random_movement_handler(entity,movement_state)
--
--! @brief generate a random y-movement
--! @memberof height_level_control
--
--! @param entity mob to apply random jump
--! @param movement_state current movement state
--! @return movement_state is a modified!
-------------------------------------------------------------------------------
function height_level_control.random_movement_handler(entity,movement_state)
--generate random y movement changes
if movement_state.changed == false and
entity.dynamic_data.movement.changing_levels == false and
(math.random() < entity.dynamic_data.movement.mpattern.random_jump_chance or
math.random() < movement_state.override_height_change_chance) then
dbg_mobf.pmovement_lvl1("MOBF: Random jump chance for mob " .. entity.data.name .. " "..
entity.dynamic_data.movement.ts_random_jump .. " "..
entity.dynamic_data.movement.mpattern.random_jump_delay .. " " .. movement_state.now
)
local to_set
--flying/swiming mobs do level change on random jump chance
if entity.data.movement.canfly then
height_level_control.random_jump_fly(entity,movement_state)
--ground mobs
else
height_level_control.random_jump_ground(entity,movement_state)
end
end
end