boiii-scripts/shared/ai/animation_selector_table_evaluators.gsc
2023-04-13 17:30:38 +02:00

237 lines
14 KiB
Plaintext

#using scripts\shared\ai\systems\animation_selector_table;
#using scripts\shared\array_shared;
function autoexec RegisterASTScriptFunctions()
{
AnimationSelectorTable::RegisterAnimationSelectorTableEvaluator("testFunction",&testFunction);;
// ------- EVALUATOR BLOCKED BY GEO ANIMATIONS -----------//
AnimationSelectorTable::RegisterAnimationSelectorTableEvaluator("evaluateBlockedAnimations",&evaluateBlockedAnimations);;
// ------- EVALUATOR HUMAN LOCOMOTION TURNS -----------//
AnimationSelectorTable::RegisterAnimationSelectorTableEvaluator("evaluateHumanTurnAnimations",&evaluateHumanTurnAnimations);;
// ------- EVALUATOR HUMAN EXPOSED ARRIVALS -----------//
AnimationSelectorTable::RegisterAnimationSelectorTableEvaluator("evaluateHumanExposedArrivalAnimations",&evaluateHumanExposedArrivalAnimations);;
}
function testFunction( entity, animations )
{
if ( IsArray( animations ) && animations.size > 0 )
{
return animations[0];
}
}
function private Evaluator_CheckAnimationAgainstGeo( entity, animation )
{
PixBeginEvent( "Evaluator_CheckAnimationAgainstGeo" );
assert( IsActor( entity ) );
// Since this check is mostly used for turn animations, a better approximation
// of movement is to use the midpoint position of the animation and the end
// point of the animation.
localDeltaHalfVector = GetMoveDelta( animation, 0, 0.5, entity );
midPoint = entity LocalToWorldCoords( localDeltaHalfVector );
// ignore any Z translation.
midPoint = ( midPoint[0], midPoint[1], entity.origin[2] );
/#
RecordLine( entity.origin, midPoint, ( 1, .5, 0 ), "Animscript", entity );
#/
if( entity MayMoveToPoint( midPoint, true, true ) )
{
localDeltaVector = GetMoveDelta( animation, 0, 1, entity );
endPoint = entity LocalToWorldCoords( localDeltaVector );
endPoint = ( endPoint[0], endPoint[1], entity.origin[2] );
/#
RecordLine( midPoint, endPoint, ( 1, .5, 0 ), "Animscript", entity );
#/
if ( entity MayMoveFromPointToPoint( midPoint, endPoint, true, true ) )
{
PixEndEvent();
return true;
}
}
PixEndEvent();
return false;
}
function private Evaluator_CheckAnimationEndPointAgainstGeo( entity, animation )
{
PixBeginEvent( "Evaluator_CheckAnimationEndPointAgainstGeo" );
assert( IsActor( entity ) );
localDeltaVector = GetMoveDelta( animation, 0, 1, entity );
endPoint = entity LocalToWorldCoords( localDeltaVector );
endPoint = ( endPoint[0], endPoint[1], entity.origin[2] );
if( entity MayMoveToPoint( endPoint, false, false ) )
{
PixEndEvent();
return true;
}
PixEndEvent();
return false;
}
function private Evaluator_CheckAnimationForOverShootingGoal( entity, animation )
{
PixBeginEvent( "Evaluator_CheckAnimationForOverShootingGoal" );
assert( IsActor( entity ) );
localDeltaVector = GetMoveDelta( animation, 0, 1, entity );
endPoint = entity LocalToWorldCoords( localDeltaVector );
animDistSq = LengthSquared( localDeltaVector );
if( entity HasPath() )
{
startPos = entity.origin;
goalPos = entity.pathGoalPos;
assert( IsDefined( goalPos ) );
distToGoalSq = DistanceSquared( startPos, goalPos );
// goal is straight in front of the AI, just make sure that the endpoint is not beyond the goal position
if( animDistSq < distToGoalSq )
{
PixEndEvent();
return true;
}
}
PixEndEvent();
return false;
}
function private Evaluator_CheckAnimationAgainstNavmesh( entity, animation )
{
assert( IsActor( entity ) );
localDeltaVector = GetMoveDelta( animation, 0, 1, entity );
endPoint = entity LocalToWorldCoords( localDeltaVector );
// make sure that the point is on the navmesh and away from boundary
if( IsPointOnNavMesh( endPoint, entity ) )
return true;
return false;
}
function private Evaluator_CheckAnimationArrivalPosition( entity, animation )
{
localDeltaVector = GetMoveDelta( animation, 0, 1, entity );
endPoint = entity LocalToWorldCoords( localDeltaVector );
animDistSq = LengthSquared( localDeltaVector );
startPos = entity.origin;
goalPos = entity.pathGoalPos;
distToGoalSq = DistanceSquared( startPos, goalPos );
return distToGoalSq < animDistSq && entity IsPosAtGoal( endPoint );
}
function private Evaluator_FindFirstValidAnimation( entity, animations, tests )
{
assert( IsArray( animations ), "An array of animations must be passed in to validate against." );
assert( IsArray( tests ), "An array of test functions must be passed in to validate an animation." );
// Only check the first animation within the group of animations, since each animation is synonymous with each other.
foreach ( aliasAnimations in animations )
{
if ( aliasAnimations.size > 0 )
{
valid = true;
animation = aliasAnimations[0];
foreach ( test in tests )
{
if ( ![[test]]( entity, animation ) )
{
valid = false;
break;
}
}
if ( valid )
{
return animation;
}
}
}
}
// ------- EVALUATOR BLOCKED BY GEO ANIMATIONS -----------//
function private evaluateBlockedAnimations( entity, animations )
{
if( animations.size > 0 )
{
return Evaluator_FindFirstValidAnimation(
entity,
animations,
array(
&Evaluator_CheckAnimationAgainstGeo,
&Evaluator_CheckAnimationForOverShootingGoal ) );
}
return undefined;
}
function private evaluateHumanTurnAnimations( entity, animations )
{
/#
// SUMEET - Added this check just for testing.
if( ( isdefined( level.ai_dontTurn ) && level.ai_dontTurn ) )
return undefined;
#/
/#
Record3DText( "" + GetTime() + ": Turn Evaluator", entity.origin, ( 1, .5, 0 ), "Animscript", entity );
#/
if( animations.size > 0 )
{
return Evaluator_FindFirstValidAnimation(
entity,
animations,
array(
&Evaluator_CheckAnimationForOverShootingGoal,
&Evaluator_CheckAnimationAgainstGeo,
&Evaluator_CheckAnimationAgainstNavmesh ) );
}
return undefined;
}
function private evaluateHumanExposedArrivalAnimations( entity, animations )
{
if( !IsDefined( entity.pathGoalPos ) )
return undefined;
if( animations.size > 0 )
{
return Evaluator_FindFirstValidAnimation(
entity,
animations,
array( &Evaluator_CheckAnimationArrivalPosition ) );
}
return undefined;
}