681 lines
24 KiB
Plaintext
681 lines
24 KiB
Plaintext
#include maps\mp\agents\_scriptedAgents;
|
|
|
|
main()
|
|
{
|
|
self endon( "killanimscript" );
|
|
|
|
self.bLockGoalPos = true;
|
|
|
|
startNode = self GetNegotiationStartNode();
|
|
endNode = self GetNegotiationEndNode();
|
|
assert( IsDefined( startNode ) && IsDefined( endNode ) );
|
|
|
|
if ( startNode.type == "Jump" || startNode.type == "Jump Attack" )
|
|
{
|
|
nextNode = self GetNegotiationNextNode();
|
|
|
|
if ( IsDefined( startNode.target ) && IsDefined( endNode.targetname ) && startNode.target == endNode.targetname )
|
|
{
|
|
self.traverseType = "canned";
|
|
self DoTraverse( startNode, endNode );
|
|
return;
|
|
}
|
|
|
|
attackableEnemy = find_attackable_enemy_at_node( endNode );
|
|
if ( IsDefined( attackableEnemy ) )
|
|
{
|
|
self.traverseType = "jump_attack";
|
|
self.leapEndPos = endNode.origin;
|
|
|
|
self maps\mp\agents\alien\_alien_melee::melee_leap( attackableEnemy );
|
|
}
|
|
else
|
|
{
|
|
self.traverseType = "jump";
|
|
self Jump( startNode, endNode, nextNode );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self.traverseType = "canned";
|
|
self doTraverse( startNode, endNode );
|
|
}
|
|
}
|
|
|
|
find_attackable_enemy_at_node( nodeToCheck )
|
|
{
|
|
if (( self maps\mp\alien\_utility::get_alien_type() == "spitter" ) ||
|
|
( self maps\mp\alien\_utility::get_alien_type() == "seeder" ))
|
|
return undefined;
|
|
|
|
CLOSE_PLAYER_DIST_SQ = 128 * 128;
|
|
COS_45 = 0.707;
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( DistanceSquared( player.origin, nodeToCheck.origin ) > CLOSE_PLAYER_DIST_SQ )
|
|
continue;
|
|
|
|
playerToNode = VectorNormalize( nodeToCheck.origin - player.origin );
|
|
playerForward = AnglesToForward( player.angles );
|
|
forwardDot = VectorDot( playerToNode, playerForward );
|
|
|
|
if ( forwardDot > COS_45 )
|
|
return player;
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
end_script()
|
|
{
|
|
self.bLockGoalPos = false;
|
|
if ( self.traverseType == "jump" )
|
|
{
|
|
self.previousAnimState = "traverse_jump";
|
|
}
|
|
else if ( self.traverseType == "jump_attack" )
|
|
{
|
|
self.previousAnimState = "traverse_jump_attack";
|
|
}
|
|
else
|
|
{
|
|
self.previousAnimState = "traverse_canned";
|
|
}
|
|
self.traverseType = undefined;
|
|
}
|
|
|
|
|
|
Jump( startNode, endNode, nextNode )
|
|
{
|
|
nextPos = undefined;
|
|
if ( IsDefined( nextNode ) )
|
|
nextPos = nextNode.origin;
|
|
|
|
if ( isDefined( level.dlc_alien_jump_override ) )
|
|
{
|
|
[[level.dlc_alien_jump_override]]( startNode, endNode, nextNode, nextPos );
|
|
return;
|
|
}
|
|
|
|
self maps\mp\agents\alien\_alien_jump::Jump( startNode.origin, startNode.angles, endNode.origin, endNode.angles, nextPos, undefined, endNode.script_noteworthy );
|
|
}
|
|
|
|
doTraverse( startNode, endNode )
|
|
{
|
|
traverseData = level.alienAnimData.cannedTraverseAnims[ startNode.animscript ];
|
|
AssertEx( isDefined( traverseData ), "Traversal '" + startNode.animscript + "' is not supported" );
|
|
|
|
animState = traverseData [ "animState" ];
|
|
AssertEx( isDefined( animState ), "No animState specified for traversal '" + startNode.animscript + "'" );
|
|
|
|
self.startNode = startNode;
|
|
self.endNode = endNode;
|
|
|
|
self ScrAgentSetPhysicsMode( "noclip" );
|
|
self ScrAgentSetOrientMode( "face angle abs", startNode.angles );
|
|
self ScrAgentSetAnimMode( "anim deltas" );
|
|
self ScrAgentSetAnimScale( 1.0, 1.0 );
|
|
|
|
if ( isdefined( traverseData[ "traverseSound" ] ) )
|
|
self thread maps\mp\_utility::play_sound_on_tag( traverseData[ "traverseSound" ] );
|
|
|
|
if ( isdefined( traverseData[ "traverseAnimScale" ] ) )
|
|
self ScrAgentSetAnimScale( traverseData[ "traverseAnimScale" ], traverseData[ "traverseAnimScale" ] );
|
|
|
|
switch ( animState )
|
|
{
|
|
case "traverse_climb_up":
|
|
alienClimbUp( startNode, endNode, "traverse_climb_up", self GetAnimEntry( "traverse_climb_up", 4 ) );
|
|
break;
|
|
|
|
case "traverse_climb_up_over_56":
|
|
alienClimbUp( startNode, endNode, "traverse_climb_up_over_56" );
|
|
break;
|
|
|
|
case "traverse_climb_up_ledge_18_run":
|
|
alienClimbUp( startNode, endNode, "traverse_climb_up_ledge_18_run" );
|
|
break;
|
|
|
|
case "traverse_climb_up_ledge_18_idle":
|
|
alienClimbUp( startNode, endNode, "traverse_climb_up_ledge_18_idle" );
|
|
break;
|
|
|
|
case "climb_up_end_jump_side_l":
|
|
alienClimbUp( startNode, endNode, "climb_up_end_jump_side_l" );
|
|
break;
|
|
|
|
case "climb_up_end_jump_side_r":
|
|
alienClimbUp( startNode, endNode, "climb_up_end_jump_side_r" );
|
|
break;
|
|
|
|
case "traverse_climb_down":
|
|
alienClimbDown( startNode, endNode, "traverse_climb_down" );
|
|
break;
|
|
|
|
case "traverse_climb_over_56_down":
|
|
alienClimbDown( startNode, endNode, "traverse_climb_over_56_down" );
|
|
break;
|
|
case "run":
|
|
alienWallRun( startNode, endNode, "run" );
|
|
break;
|
|
|
|
default:
|
|
alienRegularTraversal( startNode, animState, traverseData [ "animIndexArray" ], traverseData [ "endInOriented" ], traverseData [ "flexHeightEndAtTraverseEnd" ] );
|
|
break;
|
|
}
|
|
|
|
self.startNode = undefined;
|
|
self.endNode = undefined;
|
|
self ScrAgentSetAnimScale( 1, 1 );
|
|
}
|
|
|
|
alienRegularTraversal( startNode, animState, animIndexArray, endInOriented, flexHeightEndAtTraverseEnd )
|
|
{
|
|
animIndex = animIndexArray [ RandomInt ( animIndexArray.size ) ];
|
|
animEntry = self GetAnimEntry( animState, animIndex );
|
|
result = needFlexibleHeightSupport( animEntry );
|
|
animTime = GetAnimLength( animEntry );
|
|
|
|
self traverseAnimLerp( animEntry, startNode );
|
|
|
|
// If we have an apex, move us away from our wall on death
|
|
if ( AnimHasNotetrack( animEntry, "highest_point" ) )
|
|
self.apexTraversalDeathVector = VectorNormalize( self.startNode.origin - self.endNode.origin );
|
|
|
|
// If we are pointing to an entity, assume it's a scriptable
|
|
scriptable = GetEnt( startnode.target, "targetname" );
|
|
if ( IsDefined( scriptable ) )
|
|
{
|
|
scriptable thread runScriptableTraverse( animTime );
|
|
}
|
|
|
|
if( result.need_support )
|
|
doTraversalWithFlexibleHeight( animState, animIndex, animEntry, result.start_notetrack, result.end_notetrack, flexHeightEndAtTraverseEnd, ::alienTraverseNotetrackHandler );
|
|
else
|
|
PlayAnimNUntilNotetrack( animState, animIndex, "canned_traverse", "end", ::alienTraverseNotetrackHandler );
|
|
|
|
endRegularTraversal( endInOriented );
|
|
}
|
|
|
|
runScriptableTraverse( animTime )
|
|
{
|
|
self notify( "stop_previous_traversal" );
|
|
self endon( "stop_previous_traversal" );
|
|
self SetScriptablePartState( 0, 1 );//plays the animation
|
|
wait animTime;
|
|
self SetScriptablePartState( 0, 0 );//resets the scriptable state
|
|
}
|
|
|
|
endRegularTraversal( endInOriented )
|
|
{
|
|
if( endInOriented )
|
|
{
|
|
self ScrAgentSetPhysicsMode( "noclip" );
|
|
self.oriented = true;
|
|
self.ignoreme = true;
|
|
}
|
|
else
|
|
{
|
|
self ScrAgentSetPhysicsMode( "gravity" );
|
|
self.oriented = false;
|
|
self.ignoreme = false;
|
|
}
|
|
}
|
|
|
|
needFlexibleHeightSupport( animEntry )
|
|
{
|
|
result = spawnStruct();
|
|
|
|
if ( AnimHasNotetrack ( animEntry, "traverse_up" ) )
|
|
{
|
|
result.need_support = true;
|
|
result.start_notetrack = "traverse_up";
|
|
result.end_notetrack = "traverse_up_end";
|
|
return result;
|
|
}
|
|
|
|
if ( AnimHasNotetrack ( animEntry, "traverse_drop" ) )
|
|
{
|
|
result.need_support = true;
|
|
result.start_notetrack = "traverse_drop";
|
|
result.end_notetrack = "traverse_drop_end";
|
|
return result;
|
|
}
|
|
|
|
result.need_support = false;
|
|
return result;
|
|
}
|
|
|
|
doTraversalWithFlexibleHeight( animState, animIndex, animEntry, startNotetrack, endNotetrack, flexHeightEndAtTraverseEnd, notetrackHandlerFunc )
|
|
{
|
|
CONST_TRAVERSAL_ANIM_LABEL = "canned_traverse";
|
|
|
|
PlayAnimNUntilNotetrack( animState, animIndex, CONST_TRAVERSAL_ANIM_LABEL, startNotetrack, notetrackHandlerFunc );
|
|
|
|
if ( flexHeightEndAtTraverseEnd )
|
|
{
|
|
flex_height_end_pos = self.endNode.origin;
|
|
flex_height_anim_end_time = 1;
|
|
}
|
|
else
|
|
{
|
|
AssertEx( isDefined( self.endNode.target ), "Traversal " + animState + " " + animIndex + " at " + self.origin + ". Need to link a script struct from the traversal end point to mark the apex point for the animation" );
|
|
flex_height_end_pos = common_scripts\utility::getstruct( self.endNode.target, "targetname" );
|
|
AssertEx( isDefined( flex_height_end_pos ), "Traversal " + animState + " " + animIndex + " at " + self.origin + ". Unable to find the apex point struct" );
|
|
flex_height_end_pos = flex_height_end_pos.origin;
|
|
apexNotetrackTimes = GetNotetrackTimes( animEntry, "highest_point" );
|
|
flex_height_anim_end_time = apexNotetrackTimes[ 0 ];
|
|
AssertEx( isDefined( flex_height_anim_end_time ), "Traversal " + animState + " " + animIndex + " at " + self.origin + ". Missing 'highest_point' notetrack" );
|
|
}
|
|
|
|
doTraversalWithFlexibleHeight_internal( animState, animIndex, CONST_TRAVERSAL_ANIM_LABEL, animEntry, startNotetrack, endNotetrack, flex_height_end_pos, flex_height_anim_end_time, notetrackHandlerFunc );
|
|
}
|
|
|
|
doTraversalWithFlexibleHeight_internal( animState, animIndex, animLabel, animEntry, startNotetrack, endNotetrack, flexHeightEndPos, flexHeightAnimEndTime, notetrackHandlerFunc )
|
|
{
|
|
remaining_height = abs( self.origin[ 2 ] - flexHeightEndPos[ 2 ] );
|
|
|
|
startNotetrackTimes = GetNotetrackTimes( animEntry, startNotetrack );
|
|
start_time = startNotetrackTimes[ 0 ];
|
|
|
|
endNotetrackTimes = GetNotetrackTimes( animEntry, endNotetrack );
|
|
end_time = endNotetrackTimes[ 0 ];
|
|
AssertEx( end_time > start_time, "Traversal " + animState + " " + animIndex + " has incorrectly placed flexible height notetracks." );
|
|
|
|
remaining_anim_delta = GetMoveDelta( animEntry, start_time, flexHeightAnimEndTime );
|
|
remaining_anim_height = abs( remaining_anim_delta[ 2 ] );
|
|
|
|
anim_delta_between = GetMoveDelta( animEntry, start_time, end_time );
|
|
scaled_anim_height = abs( anim_delta_between[ 2 ] );
|
|
AssertEx( scaled_anim_height > 0.0, "Traversal " + animState + " " + animIndex + " has bad traverse notetracks." );
|
|
not_scaled_anim_height = remaining_anim_height - scaled_anim_height;
|
|
|
|
//<TODO J.C.> When we have time, we need to investigate why this is happening on certain traversals
|
|
//AssertEx( ( remaining_height - not_scaled_anim_height ) > 0, "Traversal " + animState + " " + animIndex + " at " + self.origin + " has no vertical space to do flexible height." );
|
|
|
|
if ( remaining_height <= not_scaled_anim_height )
|
|
anim_scale = 1;
|
|
else
|
|
anim_scale = ( remaining_height - not_scaled_anim_height ) / scaled_anim_height;
|
|
|
|
anim_rate = 1 / anim_scale;
|
|
|
|
self ScrAgentSetAnimScale( 1.0, anim_scale );
|
|
PlayAnimNAtRateUntilNotetrack( animState, animIndex, anim_rate, animLabel, endNotetrack, notetrackHandlerFunc );
|
|
|
|
self ScrAgentSetAnimScale( 1.0, 1.0 );
|
|
PlayAnimNUntilNotetrack( animState, animIndex, animLabel, "end", notetrackHandlerFunc );
|
|
|
|
self.apexTraversalDeathVector = undefined;
|
|
}
|
|
|
|
alienTraverseNotetrackHandler( note, animState, animIndex, animTime )
|
|
{
|
|
switch ( note )
|
|
{
|
|
case "apply_physics":
|
|
self ScrAgentSetPhysicsMode( "gravity" );
|
|
break;
|
|
|
|
case "highest_point":
|
|
if ( isDefined( self.apexTraversalDeathVector ) )
|
|
self.apexTraversalDeathVector *= -1;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//===========================================
|
|
// Special traversals
|
|
//===========================================
|
|
|
|
//////////////////
|
|
// Climb up
|
|
|
|
alienClimbUp( startNode, endNode, animState, longerEndAnim )
|
|
{
|
|
startAnim = self GetAnimEntry( animState, 0 );
|
|
scrabbleAnim = self GetAnimEntry( animState, 1 );
|
|
loopAnim = self GetAnimEntry( animState, 2 );
|
|
endAnim = self GetAnimEntry( animState, 3 );
|
|
|
|
totalHeight = endNode.origin[ 2 ] - startnode.origin[ 2 ];
|
|
startAnimHeight = GetMoveDelta( startAnim, 0, 1 )[ 2 ];
|
|
scrabbleAnimHeight = GetMoveDelta( scrabbleAnim, 0, 1 )[ 2 ];
|
|
loopAnimHeight = GetMoveDelta( loopAnim, 0, 1 )[ 2 ];
|
|
endAnimHeight = GetMoveDelta( endAnim, 0, 1 )[ 2 ];
|
|
longerEndAnimHeight = undefined;
|
|
|
|
climbUpNotetrackTime = getNoteTrackTimes( startAnim, "climb_up_teleport" ) [ 0 ];
|
|
climbUpAnimDeltaBeforeNotetrack = GetMoveDelta( startAnim, 0, climbUpNotetrackTime );
|
|
climbUpAnimDeltaAfterNotetrack = GetMoveDelta( startAnim, climbUpNotetrackTime, 1 );
|
|
startAnimHeightAfterNotetrack = climbUpAnimDeltaAfterNotetrack[ 2 ];
|
|
|
|
if ( totalHeight < ( startAnimHeight + endAnimHeight ) )
|
|
Println( "ERROR: Height is too short for " + animState + ". Modify the geo or use another traversal." );
|
|
|
|
distForScrabbleAndLoop = totalHeight - ( startAnimHeight + endAnimHeight );
|
|
canDoScrabble = false;
|
|
numOfLoop = 0;
|
|
if ( distForScrabbleAndLoop > 0 )
|
|
{
|
|
canDoScrabble = ( distForScrabbleAndLoop - scrabbleAnimHeight ) > 0;
|
|
numOfLoop = max ( 0, floor ( ( distForScrabbleAndLoop - canDoScrabble * scrabbleAnimHeight ) / loopAnimHeight ) );
|
|
}
|
|
|
|
teleportAnimHeight = canDoScrabble * scrabbleAnimHeight + numOfLoop * loopAnimHeight + startAnimHeightAfterNotetrack;
|
|
teleportRealHeight = totalHeight - endAnimHeight - ( startAnimHeight - startAnimHeightAfterNotetrack );
|
|
animScalerZ = teleportRealHeight / teleportAnimHeight;
|
|
|
|
canDoLongerEndAnim = false;
|
|
if ( isDefined ( longerEndAnim ))
|
|
{
|
|
longerEndAnimHeight = GetMoveDelta( longerEndAnim, 0, 1 )[ 2 ];
|
|
endAnimHeightDiff = longerEndAnimHeight - endAnimHeight;
|
|
canDoLongerEndAnim = ( teleportRealHeight - teleportAnimHeight ) > endAnimHeightDiff;
|
|
animScalerZ = ( teleportRealHeight - canDoLongerEndAnim * endAnimHeightDiff )/ teleportAnimHeight;
|
|
}
|
|
|
|
selectedEndAnim = endAnim;
|
|
if ( canDoLongerEndAnim )
|
|
selectedEndAnim = longerEndAnim;
|
|
|
|
stopTeleportNotetrack = getNoteTrackTimes( selectedEndAnim, "stop_teleport" ) [ 0 ];
|
|
endAnimHeightBeforeNotetrack = GetMoveDelta( selectedEndAnim, 0, stopTeleportNotetrack )[ 2 ];
|
|
stopToEndAnimDelta = GetMoveDelta( selectedEndAnim, stopTeleportNotetrack, 1 );
|
|
stopToEndAnimDeltaXY = length( stopToEndAnimDelta * ( 1, 1, 0 ) );
|
|
|
|
// startAnim: Play the anim normally until climb_up_teleport notetrack
|
|
self ScrAgentSetAnimScale( 1, 1 );
|
|
|
|
self traverseClimbUpLerp( startAnim, startNode );
|
|
|
|
PlayAnimNUntilNotetrack( animState, 0, "canned_traverse", "climb_up_teleport" );
|
|
|
|
// startAnim: Initial horizontal scaling to make up for any XY displacement. Start to scale to Z.
|
|
self ScrAgentSetAnimScale( 1, animScalerZ );
|
|
self WaitUntilNotetrack( "canned_traverse", "end" );
|
|
|
|
// scrabble and loop animation: Continue the Z scaling.
|
|
self ScrAgentSetAnimScale( 1, animScalerZ );
|
|
if ( canDoScrabble )
|
|
PlayAnimNUntilNotetrack( animState, 1, "canned_traverse", "finish" );
|
|
|
|
for ( i = 0; i < numOfLoop; i++ )
|
|
{
|
|
PlayAnimNUntilNotetrack( animState, 2, "canned_traverse", "end" );
|
|
}
|
|
|
|
//Final height adjustment, making sure alien reach enough height and will not end up inside geo when finish the traversal
|
|
selfToEndHeight = endNode.origin[ 2 ] - self.origin[ 2 ] - stopToEndAnimDelta[ 2 ];
|
|
animScalerZ = 1.0;
|
|
if ( selfToEndHeight > endAnimHeightBeforeNotetrack )
|
|
animScalerZ = selfToEndHeight / endAnimHeightBeforeNotetrack;
|
|
|
|
self ScrAgentSetAnimScale( 1, animScalerZ );
|
|
|
|
if ( canDoLongerEndAnim )
|
|
PlayAnimNUntilNotetrack( animState, 4, "canned_traverse", "stop_teleport", ::alienTraverseNotetrackHandler );
|
|
else
|
|
PlayAnimNUntilNotetrack( animState, 3, "canned_traverse", "stop_teleport", ::alienTraverseNotetrackHandler );
|
|
|
|
//Final horizontal adjustment, making sure alien will end at the traverse End node
|
|
selfToEndXY = distance2D( self.origin, endNode.origin );
|
|
animScalerXY = selfToEndXY / stopToEndAnimDeltaXY;
|
|
|
|
self ScrAgentSetAnimScale( animScalerXY, 1 );
|
|
self WaitUntilNotetrack( "canned_traverse", "end" );
|
|
}
|
|
|
|
/////////////////////
|
|
// Climb down
|
|
|
|
alienClimbDown( startNode, endNode, animState )
|
|
{
|
|
startAnim = self GetAnimEntry( animState, 0 );
|
|
loopAnim = self GetAnimEntry( animState, 1 );
|
|
slideAnim = self GetAnimEntry( animState, 2 );
|
|
endAnim = self GetAnimEntry( animState, 3 );
|
|
jumpOffEndAnim = self GetAnimEntry( animState, 4 );
|
|
|
|
totalHeight= startNode.origin[ 2 ] - endNode.origin[ 2 ];
|
|
startAnimHeight = -1 * GetMoveDelta( startAnim, 0, 1 )[ 2 ];
|
|
slideAnimHeight = -1 * GetMoveDelta( slideAnim, 0, 1 )[ 2 ];
|
|
loopAnimHeight = -1 * GetMoveDelta( loopAnim, 0, 1 )[ 2 ];
|
|
endAnimHeight = -1 * GetMoveDelta( endAnim, 0, 1 )[ 2 ];
|
|
jumpOffEndAnimHeight = -1 * GetMoveDelta( jumpOffEndAnim, 0, 1 )[ 2 ];
|
|
|
|
if ( totalHeight < ( startAnimHeight + endAnimHeight ) )
|
|
Println( "ERROR: Height is too short for " + animState + ". Modify the geo or use another traversal." );
|
|
|
|
endAnimToPlay = endAnim;
|
|
endAnimToPlayHeight = endAnimHeight;
|
|
canDoJump = false;
|
|
|
|
//Determine whether alien can play the jump off anim for end
|
|
if ( self canDoJumpForEnd( startnode, endNode, startAnim, jumpOffEndAnim ))
|
|
{
|
|
endAnimToPlay = jumpOffEndAnim;
|
|
endAnimToPlayHeight = jumpOffEndAnimHeight;
|
|
canDoJump = true;
|
|
}
|
|
|
|
distForSlideAndLoop = totalHeight - ( startAnimHeight + endAnimToPlayHeight );
|
|
canDoSlide = false;
|
|
numOfLoop = 0;
|
|
if ( distForSlideAndLoop > 0 )
|
|
{
|
|
canDoSlide = ( distForSlideAndLoop - slideAnimHeight ) > 0;
|
|
numOfLoop = max ( 0, floor (( distForSlideAndLoop - canDoSlide * slideAnimHeight ) / loopAnimHeight ));
|
|
}
|
|
|
|
self ScrAgentSetAnimScale( 1, 1 );
|
|
|
|
self traverseClimbDownLerp( startAnim, startNode );
|
|
|
|
PlayAnimNUntilNotetrack( animState, 0, "canned_traverse", "end" );
|
|
|
|
slideAndLoopAnimHeight = canDoSlide * slideAnimHeight + numOfLoop * loopAnimHeight;
|
|
if ( slideAndLoopAnimHeight > 0 )
|
|
{
|
|
animScaler = abs( ( distForSlideAndLoop )/ slideAndLoopAnimHeight );
|
|
self ScrAgentSetAnimScale( 1, animScaler );
|
|
}
|
|
|
|
//<Note J.C.>: Playing the loop and slide animation from the same anim state has caused the following issue.:
|
|
// (1) The "will_finish_soon" notetrack will fire off immediately due to the short anim length for the slide anim,
|
|
// causing the slide animation to not play
|
|
// (2) When this happens, the alien will keep playing the loop animation even when the jump-off state is activated.
|
|
// If time permits, we need to look into how situations like this should be prevented.
|
|
for ( i = 0; i < numOfLoop; i++ )
|
|
{
|
|
PlayAnimNUntilNotetrack( "traverse_climb_down_loop", 0, "traverse_climb_down_loop", "end" );
|
|
}
|
|
if ( canDoSlide )
|
|
PlayAnimNUntilNotetrack( "traverse_climb_down_slide", 0, "traverse_climb_down_slide", "end" );
|
|
|
|
//Final height adjustment, making sure alien ends up on the ground when finish
|
|
teleportStartTime = getNoteTrackTimes( endAnimToPlay, "climb_down_teleport" ) [ 0 ];
|
|
teleportEndTime = getNoteTrackTimes( endAnimToPlay, "stop_teleport" ) [ 0 ];
|
|
animHeightAfterNotetrack = -1 * GetMoveDelta( endAnimToPlay, teleportStartTime, teleportEndTime )[ 2 ];
|
|
heightAdjustment = abs( self.origin[ 2 ] - endNode.origin[ 2 ] - abs ( GetMoveDelta( endAnimToPlay, teleportEndTime, 1 )[ 2 ] ) );
|
|
animScaler = heightAdjustment / animHeightAfterNotetrack;
|
|
|
|
self ScrAgentSetAnimScale( 1, animScaler );
|
|
|
|
if ( canDoJump )
|
|
PlayAnimNUntilNotetrack( animState, 4, "canned_traverse", "stop_teleport" );
|
|
else
|
|
PlayAnimNUntilNotetrack( animState, 3, "canned_traverse", "stop_teleport" );
|
|
|
|
self ScrAgentSetAnimScale( 1, 1 );
|
|
self ScrAgentSetPhysicsMode( "gravity" );
|
|
self WaitUntilNotetrack( "canned_traverse", "end" );
|
|
}
|
|
|
|
traverseAnimLerp( startAnim, startNode )
|
|
{
|
|
// Make sure we're oriented exactly with the node -
|
|
// lerp to the correct position for the first part of the anim
|
|
|
|
lerp_time = maps\mp\agents\alien\_alien_anim_utils::getLerpTime( startAnim );
|
|
lerp_target_pos = maps\mp\agents\alien\_alien_anim_utils::getPosInSpaceAtAnimTime( startAnim, startNode.origin, startNode.angles, lerp_time );
|
|
|
|
thread maps\mp\agents\alien\_alien_anim_utils::doLerp( lerp_target_pos, lerp_time );
|
|
}
|
|
|
|
traverseClimbDownLerp( startAnim, startNode )
|
|
{
|
|
VERTICAL_DROP = -30; // For climb down, go down when attempt to locate the vertical edge
|
|
HORIZONTAL_EXTENSION = 60; // Further extend horizontally for nodes places close to the vertical edge
|
|
|
|
doTraverseClimbLerp( startAnim, startNode, VERTICAL_DROP, HORIZONTAL_EXTENSION, true );
|
|
}
|
|
|
|
traverseClimbUpLerp( startAnim, startNode )
|
|
{
|
|
VERTICAL_RAISE = 0; // For climb up, go up when attempt to locate the vertical edge
|
|
HORIZONTAL_EXTENSION = 50; // Further extend horizontally for nodes places placed far from the vertical edge
|
|
|
|
doTraverseClimbLerp( startAnim, startNode, VERTICAL_RAISE, HORIZONTAL_EXTENSION, false );
|
|
}
|
|
|
|
doTraverseClimbLerp( startAnim, startNode, verticalProbeDis, horizontalProbeDis, probeForward )
|
|
{
|
|
lerp_time = maps\mp\agents\alien\_alien_anim_utils::getLerpTime( startAnim );
|
|
lerp_target_pos = maps\mp\agents\alien\_alien_anim_utils::getPosInSpaceAtAnimTime( startAnim, startNode.origin, startNode.angles, lerp_time );
|
|
|
|
if ( probeForward )
|
|
horizontal_probe_direction = ( lerp_target_pos - startNode.origin ) * ( 1, 1, 0 );
|
|
else
|
|
horizontal_probe_direction = ( startNode.origin - lerp_target_pos ) * ( 1, 1, 0 );
|
|
|
|
horizontal_offset = vectorNormalize( horizontal_probe_direction );
|
|
horizontal_offset *= horizontalProbeDis;
|
|
|
|
anim_end_pos = maps\mp\agents\alien\_alien_anim_utils::getPosInSpaceAtAnimTime( startAnim, startNode.origin, startNode.angles, GetAnimLength( startAnim ) );
|
|
end_pos_aligned = alignToVerticalEdge( anim_end_pos, verticalProbeDis, horizontal_offset );
|
|
|
|
xy_displacement = end_pos_aligned - anim_end_pos;
|
|
lerp_target_pos += xy_displacement;
|
|
|
|
thread maps\mp\agents\alien\_alien_anim_utils::doLerp( lerp_target_pos, lerp_time );
|
|
}
|
|
|
|
alignToVerticalEdge( lerp_target_pos, vertical_displacement, horizontal_offset )
|
|
{
|
|
BACKWARD_SCALAR = 3.0; // When doing a backward trace toward the lerp_target_pos, extend the horizontal_offset further to
|
|
// make sure we hit the vertical edge
|
|
|
|
lerp_target_pos += horizontal_offset;
|
|
lerp_target_pos += ( 0, 0, vertical_displacement );
|
|
|
|
trace_end_pos = lerp_target_pos - horizontal_offset * BACKWARD_SCALAR;
|
|
trace = bulletTrace( lerp_target_pos, trace_end_pos, false );
|
|
lerp_target_pos = trace["position"];
|
|
lerp_target_pos += ( 0, 0, -1 * vertical_displacement );
|
|
|
|
return lerp_target_pos;
|
|
}
|
|
|
|
canDoJumpForEnd( startnode, endNode, startAnim, jumpAnim )
|
|
{
|
|
TRACE_START_FORWARD_PADDING = 10;
|
|
TRACE_END_UP_PADDING = ( 0, 0, 10 );
|
|
TRACE_CAPSULE_RADIUS = 5;
|
|
TRACE_CAPSULE_HEIGHT = self.height;
|
|
|
|
startAnimDelta = GetMoveDelta( startAnim, 0, 1 );
|
|
startAnimDeltaXY = Length2D ( startAnimDelta );
|
|
startAnimDeltaZ = startAnimDelta [ 2 ] * -1;
|
|
|
|
jumpAnimDelta = GetMoveDelta( jumpAnim, 0, 1 );
|
|
jumpAnimDeltaXY = Length2D ( jumpAnimDelta );
|
|
jumpAnimDeltaZ = jumpAnimDelta[ 2 ] * -1;
|
|
|
|
startToEndXY = VectorNormalize (( endNode.origin - startnode.origin ) * ( 1, 1, 0 ));
|
|
startAnimEndPos = startnode.origin + startToEndXY * startAnimDeltaXY - ( 0, 0, startAnimDeltaZ );
|
|
|
|
startAnimEndGroundPos = PhysicsTrace( startAnimEndPos, startAnimEndPos + ( 0, 0, -2000 ) );
|
|
startAnimEndAboveGround = ( startAnimEndPos - startAnimEndGroundPos ) [ 2 ];
|
|
|
|
if ( startAnimEndAboveGround < jumpAnimDeltaZ )
|
|
return false;
|
|
|
|
jumpStartPos = startAnimEndGroundPos + ( 0, 0, jumpAnimDeltaZ );
|
|
jumpEndPos = startAnimEndGroundPos + startToEndXY * jumpAnimDeltaXY;
|
|
|
|
traceStartPos = jumpStartPos + startToEndXY * TRACE_START_FORWARD_PADDING;
|
|
traceEndPos = jumpEndPos + TRACE_END_UP_PADDING;
|
|
|
|
return ( self AIPhysicsTracePassed( traceStartPos, traceEndPos, TRACE_CAPSULE_RADIUS, TRACE_CAPSULE_HEIGHT, false ) );
|
|
}
|
|
|
|
alienWallRun( startNode, endNode, animState )
|
|
{
|
|
self.oriented = true;
|
|
|
|
startToEnd = endNode.origin - startNode.origin;
|
|
up = AnglesToUp( endNode.angles );
|
|
forward = VectorNormalize( startToEnd );
|
|
left = VectorCross( up, forward );
|
|
forward = VectorCross( left, up );
|
|
right = (0,0,0) - left;
|
|
|
|
startToEndAngles = AxisToAngles( forward, right, up );
|
|
|
|
self ScrAgentSetOrientMode( "face angle abs", startToEndAngles );
|
|
|
|
animEntry = self GetAnimEntry( animState, 0 );
|
|
time = GetAnimLength( animEntry );
|
|
moveDelta = GetMoveDelta( animEntry );
|
|
dist = Length( moveDelta );
|
|
distToEnd = Length( endNode.origin - self.origin );
|
|
lerpTime = time * ( distToEnd / dist );
|
|
self ScrAgentDoAnimLerp( self.origin, endNode.origin, lerpTime );
|
|
|
|
self SetAnimState( animState, 0 );
|
|
|
|
wait( lerpTime );
|
|
|
|
self alienWallRun_WaitForAngles( startToEndAngles );
|
|
}
|
|
|
|
alienWallRun_AnglesAlmostEqual( angles1, angles2, diff )
|
|
{
|
|
if ( abs( angleClamp180( angles2[0] - angles1[0] ) > diff ) )
|
|
return false;
|
|
if ( abs( angleClamp180( angles2[1] - angles1[1] ) > diff ) )
|
|
return false;
|
|
if ( abs( angleClamp180( angles2[2] - angles1[2] ) > diff ) )
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// do a little extra wait, time out after 0.5s in case something changes.
|
|
// make sure we're within 5 degrees of our desired angles, but also cancel
|
|
// out if we're not actually closing in our desired angles because maybe
|
|
// something changed out our desired angles.
|
|
// *hocus-pocus-handwavey-insurance*
|
|
alienWallRun_WaitForAngles( desiredAngles )
|
|
{
|
|
previousDiff = 360;
|
|
waitTime = 0.5;
|
|
|
|
while ( waitTime > 0 )
|
|
{
|
|
// do an extra check, in addition to the anglesdelta, to see if the angles are close to
|
|
// each other, because anglesdelta SREs if they're too close. which seems rather unuseful.
|
|
if ( alienWallRun_AnglesAlmostEqual( self.angles, desiredAngles, 1 ) )
|
|
break;
|
|
|
|
diff = AnglesDelta( desiredAngles, self.angles );
|
|
if ( diff < 5 || diff >= previousDiff )
|
|
break;
|
|
previousDiff = diff;
|
|
wait( 0.05 );
|
|
waitTime -= 0.05;
|
|
}
|
|
} |