Incomplete SP dump provided by Louvenarde

This commit is contained in:
reaaLx
2024-09-05 17:14:53 +10:00
parent 1ea2370337
commit e5de1d5d55
784 changed files with 340494 additions and 0 deletions

126
animscripts/animmode.gsc Normal file
View File

@ -0,0 +1,126 @@
main()
{
self endon( "death" );
self endon( "stop_animmode" );
self notify( "killanimscript" );
self._tag_entity endon( self._anime );
if ( isdefined( self._custom_anim_thread ) )
{
self thread [[ self._custom_anim_thread ]]();
self._custom_anim_thread = undefined;
}
loop = isdefined( self._custom_anim_loop ) && self._custom_anim_loop;
if ( loop )
{
self endon( "stop_loop" );
self._custom_anim_loop = undefined;
}
else
{
thread notify_on_end( self._anime );
}
anime = self._anime;
self._anime = undefined;
arraySize = 0;
if ( loop )
{
arraySize = level._scr_anim[ self._animname ][ anime ].size;
animationName = level._scr_anim[ self._animname ][ anime ][ randomint( arraySize ) ];
}
else
{
animationName = level._scr_anim[ self._animname ][ anime ];
}
origin = getstartOrigin( self._tag_entity.origin, self._tag_entity.angles, animationName );
angles = getstartAngles( self._tag_entity.origin, self._tag_entity.angles, animationName );
newOrigin = self getDropToFloorPosition( origin );
if ( isdefined( newOrigin ) )
origin = newOrigin;
else
println( "Custom animation may be playing in solid for entity '" + self getentnum() + "'\n" );
if ( !isdefined( self.noTeleport ) )
self teleport( origin, angles );
self.pushable = 0;
clear_time = 0.3;
blend_time = 0.2;
if ( isdefined( self.anim_blend_time_override ) )
{
clear_time = self.anim_blend_time_override;
blend_time = self.anim_blend_time_override;
}
self animMode( self._animmode );
self clearAnim( self.root_anim, clear_time );
// self setAnim( %body, 1, 0 ); // The %body node should always have weight 1.
self OrientMode( "face angle", angles[ 1 ] );
anim_string = "custom_animmode";
self setflaggedanimrestart( anim_string, animationName, 1, blend_time, 1 );
self._tag_entity thread maps\_anim::start_notetrack_wait( self, anim_string, anime, self._animname );
self._tag_entity thread maps\_anim::animscriptDoNoteTracksThread( self, anim_string, anime );
//thread maps\_debug::drawArrowForever( self._tag_entity.origin, self._tag_entity.angles );
tag_entity = self._tag_entity;
self._tag_entity = undefined;
self._animmode = undefined;
self endon( "killanimscript" );
endMarker = "end";
if ( !loop )
{
if ( animHasNoteTrack( animationName, "finish" ) )
endMarker = "finish";
else if ( animHasNoteTrack( animationName, "stop anim" ) )
endMarker = "stop anim";
}
while ( 1 )
{
self waittillmatch( anim_string, endMarker );
if ( loop )
{
animationName = level._scr_anim[ self._animname ][ anime ][ randomint( arraySize ) ];
self SetFlaggedAnimKnobLimitedRestart( anim_string, animationName, 1, 0.2, 1 );
if ( isdefined( tag_entity ) )
{
tag_entity thread maps\_anim::start_notetrack_wait( self, anim_string, anime, self._animname );
tag_entity thread maps\_anim::animscriptDoNoteTracksThread( self, anim_string, anime );
}
}
else
{
break;
}
}
if ( endMarker != "end" )
self OrientMode( "face motion" );
self notify( "finished_custom_animmode" + anime );
}
notify_on_end( msg )
{
self endon( "death" );
self endon( "finished_custom_animmode" + msg );
self waittill( "killanimscript" );
self notify( "finished_custom_animmode" + msg );
}

1524
animscripts/animset.gsc Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

58
animscripts/civilian.gsc Normal file
View File

@ -0,0 +1,58 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\_anim;
#include animscripts\shared;
#using_animtree( "generic_human" );
cover()
{
self endon( "killanimscript" );
self clearanim( %root, 0.2 );
if ( self animscripts\utility::IsInCombat() )
situation = "idle_combat";
else
situation = "idle_noncombat";
idle_array = undefined;
if ( isdefined( self.animname ) && isdefined( level._scr_anim[ self.animname ] ) )
idle_array = level._scr_anim[ self.animname ][ situation ];
if ( !isdefined( idle_array ) )
{
if ( !isdefined( level._scr_anim[ "default_civilian" ] ) )
return;
idle_array = level._scr_anim[ "default_civilian" ][ situation ];
}
thread move_check();
for ( ;; )
{
self setflaggedanimknoball( "idle", random( idle_array ), %root, 1, 0.2, 1 );
self waittillmatch( "idle", "end" );
}
}
move_check()
{
self endon( "killanimscript" );
while ( !isdefined( self.champion ) )
{
wait( 1 );
}
}
stop()
{
cover();
}
get_flashed_anim()
{
return anim.civilianFlashedArray[ randomint( anim.civilianFlashedArray.size ) ];
}

View File

@ -0,0 +1,19 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\_anim;
#include animscripts\shared;
get_flashed_anim()
{
return anim.civilianFlashedArray[ randomint( anim.civilianFlashedArray.size ) ];
}
main()
{
flashDuration = self flashBangGetTimeLeftSec();
if ( flashDuration <= 0 )
return;
animscripts\flashed::flashBangedLoop( get_flashed_anim(), flashDuration );
}

View File

@ -0,0 +1,74 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\_anim;
#include animscripts\shared;
#using_animtree( "generic_human" );
main()
{
animscripts\init::main();
if ( !isdefined( level._initialized_civilian_animations ) )
{
initCivilianAnims();
}
animscripts\civilian\civilian_init_common::civilian_init();
}
initCivilianAnims()
{
level._initialized_civilian_animations = true;
//put the default ones here:
level._scr_anim[ "default_civilian" ][ "run_combat" ] = [ %civilian_run_upright ];
level._scr_anim[ "default_civilian" ][ "run_hunched_combat" ] = [ %civilian_run_hunched_A, %civilian_run_hunched_C, %civilian_run_hunched_flinch ];
level._scr_anim[ "default_civilian" ][ "run_noncombat" ] = [ %civilian_walk_cool ];
level._scr_anim[ "default_civilian" ][ "run_hunched_weights" ] = get_cumulative_weights( [3, 3, 1] );
level._scr_anim[ "default_civilian" ][ "run_weights" ] = get_cumulative_weights( [ 1 ] );
level._scr_anim[ "default_civilian" ][ "idle_noncombat" ] = [ %unarmed_cowerstand_idle ];
level._scr_anim[ "default_civilian" ][ "idle_combat" ] = [ %casual_crouch_v2_idle, %unarmed_cowercrouch_idle_duck ];
level._scr_anim[ "default_civilian" ][ "dodge_left" ] = %civilian_briefcase_walk_dodge_L;
level._scr_anim[ "default_civilian" ][ "dodge_right" ] = %civilian_briefcase_walk_dodge_R;
level._scr_anim[ "default_civilian" ][ "react_stumble" ] = [ %run_react_stumble ];
//7 9 <- 8 is invalid, it's straight.
//4 6 <- 5 is invalid, it's not a turn.
//1 2 3
level._scr_anim[ "default_civilian"]["run_combat_turn"][1] = %civilian_run_upright_turnL135;
level._scr_anim[ "default_civilian"]["run_combat_turn"][2] = %civilian_run_upright_turn180;
level._scr_anim[ "default_civilian"]["run_combat_turn"][3] = %civilian_run_upright_turnR135;
level._scr_anim[ "default_civilian"]["run_combat_turn"][4] = %civilian_run_upright_turnL90;
level._scr_anim[ "default_civilian"]["run_combat_turn"][6] = %civilian_run_upright_turnR90;
level._scr_anim[ "default_civilian"]["run_combat_turn"][7] = %civilian_run_upright_turnL45;
level._scr_anim[ "default_civilian"]["run_combat_turn"][9] = %civilian_run_upright_turnR45;
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][1] = %civilian_run_upright_turnL135;
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][2] = %civilian_run_upright_turn180;
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][3] = %civilian_run_upright_turnR135;
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][4] = %civilian_run_hunched_turnL90;
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][6] = %civilian_run_hunched_turnR90;
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][7] = %civilian_run_hunched_turnL45;
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][9] = %civilian_run_hunched_turnR45;
//a more dramatic version. Randomly chosen from.
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][1] = [];
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][2] = [];
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][3] = [];
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][4] = [ %civilian_run_hunched_turnL90_slide, %civilian_run_hunched_turnL90_stumble ];
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][6] = [ %civilian_run_hunched_turnR90_slide, %civilian_run_hunched_turnR90_stumble ];
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][7] = [];
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][9] = [];
//TagCC<NOTE>: not happy with this, but we don't have flashes around civilians on the moon,
//so I'm hesistent to mess with this just yet.
anim.civilianFlashedArray = [ %unarmed_cowerstand_react, %unarmed_cowercrouch_react_A, %unarmed_cowercrouch_react_B ];
}

View File

@ -0,0 +1,229 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\_anim;
#include animscripts\shared;
#using_animtree( "generic_human" );
civilian_init()
{
self.allowdeath = 1;
self.disablearrivals = true;
self.disableexits = true;
self.neverEnableCQB = true;
self.alwaysRunForward = true;
self OrientMode( "face default" );
self.combatmode = "no_cover";
self.pushplayer = false;
self pushplayer( false );
self.a.reactToBulletChance = 1;
// set the civilians animname to use defaults, or specific group if specified in radiant
animName = undefined;
if ( isdefined( self.civilian_walk_animation ) )
{
self.animname = self.civilian_walk_animation;
self attachProps( self.civilian_walk_animation );
self.alertLevel = "noncombat";
startNonCombat();
}
else
{
self.animname = "default_civilian";
self.alertLevel = "alert";
startCombat();
}
self thread checkCombatState();
// Make sure all required anims exist for this civilian, or set some defaults if they weren't specified
assert( isdefined( level._scr_anim[ self.animname ][ "run_noncombat" ] ) );
self.dropWeapon = false;
self DropAIWeapon();
self.saved = false;
}
attachProps( anime )
{
if ( isdefined( self.hasAttachedProps ) )
return;
initCivilianProps();
prop_model = anim.civilianProps[ anime ];
if ( isdefined( prop_model ) )
{
self attach( prop_model, "tag_inhand", true );
self.hasAttachedProps = true;
}
}
detachProps( anime )
{
if ( isdefined( self.hasAttachedProps ) )
{
self.hasAttachedProps = undefined;
self detach( anim.civilianProps[ anime ], "tag_inhand" );
}
}
initCivilianProps()
{
if ( isdefined( anim.civilianProps ) )
return;
anim.civilianProps = [];
anim.civilianProps[ "civilian_briefcase_walk" ] = "com_metal_briefcase";
anim.civilianProps[ "civilian_crazy_walk" ] = "electronics_pda";
anim.civilianProps[ "civilian_cellphone_walk" ] = "com_cellphone_on";
anim.civilianProps[ "sit_lunch_A" ] = "com_cellphone_on";
anim.civilianProps[ "civilian_soda_walk" ] = "ma_cup_single_closed";
anim.civilianProps[ "civilian_paper_walk" ] = "paper_memo";
anim.civilianProps[ "civilian_coffee_walk" ] = "cs_coffeemug02";
anim.civilianProps[ "civilian_pda_walk" ] = "electronics_pda";
anim.civilianProps[ "reading1" ] = "open_book";
anim.civilianProps[ "reading2" ] = "open_book";
anim.civilianProps[ "texting_stand" ] = "electronics_pda";
anim.civilianProps[ "texting_sit" ] = "electronics_pda";
anim.civilianProps[ "smoking1" ] = "prop_cigarette";
anim.civilianProps[ "smoking2" ] = "prop_cigarette";
}
startNonCombat()
{
self.turnRate = 0.2;
// dodge animations
if ( isdefined( self.civilian_walk_animation ) )
{
dodgeLeft = level._scr_anim[ "default_civilian" ][ "dodge_left" ];
dodgeRight = level._scr_anim[ "default_civilian" ][ "dodge_right" ];
if ( isdefined( level._scr_anim[ self.animname ][ "dodge_left" ] ) )
dodgeLeft = level._scr_anim[ self.animname ][ "dodge_left" ];
if ( isdefined( level._scr_anim[ self.animname ][ "dodge_right" ] ) )
dodgeRight = level._scr_anim[ self.animname ][ "dodge_right" ];
self animscripts\move::setDodgeAnims( dodgeLeft, dodgeRight );
}
// move turn animations
if ( isdefined( level._scr_anim[ self.animname ][ "turn_left_90" ] ) )
{
assert( isdefined( level._scr_anim[ self.animname ][ "turn_right_90" ] ) );
self.pathTurnAnimOverrideFunc = animscripts\civilian\civilian_move::civilian_nonCombatMoveTurn;
self.pathTurnAnimBlendTime = 0.1;
self enable_turnAnims();
}
else
{
self disable_turnAnims();
}
self.run_overrideanim = level._scr_anim[ self.animname ][ "run_noncombat" ];
self.walk_overrideanim = self.run_overrideanim;
self.run_overrideBulletReact = undefined;
if ( self.animname == "default_civilian" )
{
self.run_override_weights = level._scr_anim[ self.animname ][ "run_weights_noncombat" ];
self.walk_override_weights = self.run_override_weights;
}
}
startCombat()
{
self notify( "combat" );
self animscripts\move::clearDodgeAnims();
self.pathTurnAnimBlendTime = undefined;
self enable_turnAnims();
self.turnRate = 0.3;
standing_run = randomint( 3 ) < 1;
if ( isdefined( self.force_civilian_stand_run ) )
{
standing_run = true;
}
else
if ( isdefined( self.force_civilian_hunched_run ) )
{
standing_run = false;
}
if ( standing_run )
{
self.pathTurnAnimOverrideFunc = animscripts\civilian\civilian_move::civilian_combatMoveTurn;
self.run_overrideanim = level._scr_anim[ "default_civilian" ][ "run_combat" ];
self.run_override_weights = level._scr_anim[ "default_civilian" ][ "run_weights" ];
//now check if this animset defines it's own anims
if ( IsDefined( level._scr_anim[ self.animname ][ "run_combat" ] ) )
{
self.run_overrideanim = level._scr_anim[ self.animname ][ "run_combat" ];
self.run_override_weights = level._scr_anim[ self.animname ][ "run_weights" ];
}
}
else
{
self.pathTurnAnimOverrideFunc = animscripts\civilian\civilian_move::civilian_combatHunchedMoveTurn;
self.run_overrideanim = level._scr_anim[ "default_civilian" ][ "run_hunched_combat" ];
self.run_override_weights = level._scr_anim[ "default_civilian" ][ "run_hunched_weights" ];
//now check if this animset defines it's own anims
if ( IsDefined( level._scr_anim[ self.animname ][ "run_hunched_combat" ] ) )
{
self.run_overrideanim = level._scr_anim[ self.animname ][ "run_hunched_combat" ];
self.run_override_weights = level._scr_anim[ self.animname ][ "run_hunched_weights" ];
}
}
self.run_overrideBulletReact = level._scr_anim[ "default_civilian" ][ "react_stumble" ];
//now check if this animset defines it's own anims
if ( IsDefined( level._scr_anim[ self.animname ][ "react_stumble" ] ) )
{
self.run_overrideBulletReact = level._scr_anim[ self.animname ][ "react_stumble" ];
}
self.walk_overrideanim = self.run_overrideanim;
self.walk_override_weights = self.run_override_weights;
detachProps( self.civilian_walk_animation );
}
checkCombatState()
{
self endon( "death" );
wasInCombat = ( self.alertLevelInt > 1 );
while ( 1 )
{
isInCombat = ( self.alertLevelInt > 1 );
if ( wasInCombat && !isInCombat )
startNonCombat();
else if ( !wasInCombat && isInCombat )
startCombat();
wasInCombat = isInCombat;
wait 0.05; // TEMP make this an alert level change wait when code is in.
}
}

View File

@ -0,0 +1,133 @@
#include animscripts\Utility;
#using_animtree( "generic_human" );
main()
{
animscripts\move::main();
}
civilian_nonCombatMoveTurn( angleDiff )
{
assert( isdefined( level._scr_anim[ self.animname ][ "turn_left_90" ] ) );
assert( isdefined( level._scr_anim[ self.animname ][ "turn_right_90" ] ) );
turnAnim = undefined;
if ( angleDiff < -60 && angleDiff > -120 )
turnAnim = level._scr_anim[ self.animname ][ "turn_left_90" ];
if ( angleDiff > 60 && angleDiff < 120 )
turnAnim = level._scr_anim[ self.animname ][ "turn_right_90" ];
if ( isdefined( turnAnim ) && animscripts\move::pathChange_canDoTurnAnim( turnAnim ) )
return turnAnim;
else
return undefined;
}
//7 9 <- 8 is invalid, it's straight.
//4 6 <- 5 is invalid, it's not a turn.
//1 2 3
civilian_combatMoveTurn( angleDiff )
{
turnDir = -1;
turnAnim = undefined;
if ( angleDiff < -22.5 )
{
if ( angleDiff > -45 )
turnDir = 7;
else if ( angleDiff > -112.5 )
turnDir = 4;
else if ( angleDiff > -157.5 )
turnDir = 1;
else
turnDir = 2;
}
else if ( angleDiff > 22.5 )
{
if ( angleDiff < 45 )
turnDir = 9;
else if ( angleDiff < 112.5 )
turnDir = 6;
else if ( angleDiff < 157.5 )
turnDir = 3;
else
turnDir = 2;
}
if ( IsDefined(level._scr_anim[ self.animname ])
&& IsDefined(level._scr_anim[ self.animname ][ "run_combat_turn" ])
&& IsDefined(level._scr_anim[ self.animname ][ "run_combat_turn" ][turnDir]) )
{
turnAnim = level._scr_anim[ self.animname ][ "run_combat_turn" ][turnDir];
}
if ( IsDefined( turnAnim ) && animscripts\move::pathChange_canDoTurnAnim( turnAnim ) )
return turnAnim;
else
return undefined;
}
civilian_combatHunchedMoveTurn( angleDiff )
{
turnDir = -1;
turnAnim = undefined;
largeTurnAnim = undefined;
if ( angleDiff < -22.5 )
{
if ( angleDiff > -45 )
turnDir = 7;
else if ( angleDiff > -112.5 )
turnDir = 4;
else if ( angleDiff > -157.5 )
turnDir = 1;
else
turnDir = 2;
}
else if ( angleDiff > 22.5 )
{
if ( angleDiff < 45 )
turnDir = 9;
else if ( angleDiff < 112.5 )
turnDir = 6;
else if ( angleDiff < 157.5 )
turnDir = 3;
else
turnDir = 2;
}
if ( IsDefined(level._scr_anim[ self.animname ])
&& IsDefined(level._scr_anim[ self.animname ][ "run_combat_hunched_large_turn" ])
&& IsDefined(level._scr_anim[ self.animname ][ "run_combat_hunched_large_turn" ][turnDir]) )
{
largeTurns = level._scr_anim[ self.animname ][ "run_combat_hunched_large_turn" ][turnDir];
if ( largeTurns.size > 0 )
{
largeTurnAnim = largeTurns[RandomInt(largeTurns.size)];
}
else
{
largeTurnAnim = undefined;
}
}
if ( IsDefined( largeTurnAnim ) && ( RandomInt( 3 ) < 2 ) && animscripts\move::pathChange_canDoTurnAnim( largeTurnAnim ) )
return largeTurnAnim;
if ( IsDefined(level._scr_anim[ self.animname ])
&& IsDefined(level._scr_anim[ self.animname ][ "run_combat_hunched_turn" ])
&& IsDefined(level._scr_anim[ self.animname ][ "run_combat_hunched_turn" ][turnDir]) )
{
turnAnim = level._scr_anim[ self.animname ][ "run_combat_hunched_turn" ][turnDir];
}
if ( isdefined( turnAnim ) && animscripts\move::pathChange_canDoTurnAnim( turnAnim ) )
return turnAnim;
else
return undefined;
}

View File

@ -0,0 +1,4 @@
main()
{
animscripts\scripted::main();
}

View File

@ -0,0 +1,76 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\_anim;
#include animscripts\shared;
#using_animtree( "generic_human" );
main()
{
animscripts\lunar\init::main();
if ( !isdefined( level._initialized_civilian_animations ) )
{
initCivilianAnims();
}
animscripts\civilian\civilian_init_common::civilian_init();
}
initCivilianAnims()
{
level._initialized_civilian_animations = true;
level._scr_anim[ "default_civilian" ][ "run_combat" ] = [ %tp_moon_civ_run_combat ];
level._scr_anim[ "default_civilian" ][ "run_weights" ] = common_scripts\utility::get_cumulative_weights( [ 1 ] );
level._scr_anim[ "default_civilian" ][ "run_noncombat" ] = [ %tp_moon_civ_run_noncombat ];
level._scr_anim[ "default_civilian" ][ "run_hunched_combat" ] = [ %tp_moon_civ_run_hunched_combat_A, %tp_moon_civ_run_hunched_combat_B, %tp_moon_civ_run_hunched_combat_C ];
level._scr_anim[ "default_civilian" ][ "run_hunched_weights" ] = common_scripts\utility::get_cumulative_weights( [ 1, 1, 1 ] );
level._scr_anim[ "default_civilian" ][ "idle_noncombat" ] = [ %tp_moon_civ_idle_noncombat ];
level._scr_anim[ "default_civilian" ][ "idle_combat" ] = [ %tp_moon_civ_idle_combat_A, %tp_moon_civ_idle_combat_B ];
level._scr_anim[ "default_civilian" ][ "dodge_left" ] = %tp_moon_civ_dodge_L;
level._scr_anim[ "default_civilian" ][ "dodge_right" ] = %tp_moon_civ_dodge_R;
level._scr_anim[ "default_civilian" ][ "react_stumble" ] = [ %tp_moon_civ_react_stumble ];
level._scr_anim[ "default_civilian" ][ "turn_left_90" ] = %tp_moon_civ_run_noncombat_turn_L90;
level._scr_anim[ "default_civilian" ][ "turn_right_90" ] = %tp_moon_civ_run_noncombat_turn_R90;
//7 9 <- 8 is invalid, it's straight.
//4 6 <- 5 is invalid, it's not a turn.
//1 2 3
level._scr_anim[ "default_civilian"]["run_combat_turn"][1] = %tp_moon_civ_run_combat_turn_L135;
level._scr_anim[ "default_civilian"]["run_combat_turn"][2] = %tp_moon_civ_run_combat_turn_180;
level._scr_anim[ "default_civilian"]["run_combat_turn"][3] = %tp_moon_civ_run_combat_turn_R135;
level._scr_anim[ "default_civilian"]["run_combat_turn"][4] = %tp_moon_civ_run_combat_turn_L90;
level._scr_anim[ "default_civilian"]["run_combat_turn"][6] = %tp_moon_civ_run_combat_turn_R90;
level._scr_anim[ "default_civilian"]["run_combat_turn"][7] = %tp_moon_civ_run_combat_turn_L45;
level._scr_anim[ "default_civilian"]["run_combat_turn"][9] = %tp_moon_civ_run_combat_turn_R45;
//define these if we want hunched turns, they aren't required though.
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][1] = %tp_moon_civ_run_combat_turn_L135;
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][2] = %tp_moon_civ_run_combat_turn_180;
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][3] = %tp_moon_civ_run_combat_turn_R135;
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][4] = %tp_moon_civ_run_combat_hunched_turnL90;
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][6] = %tp_moon_civ_run_combat_hunched_turnR90;
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][7] = %tp_moon_civ_run_combat_hunched_turnL45;
level._scr_anim[ "default_civilian"]["run_combat_hunched_turn"][9] = %tp_moon_civ_run_combat_hunched_turnR45;
/*
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][1] = undefined;
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][2] = undefined;
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][3] = undefined;
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][4] = [ %tp_moon_civ_run_combat_hunched_large_turnL90_slide, %tp_moon_civ_run_combat_hunched_large_turnL90_stumble ];
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][6] = [ %tp_moon_civ_run_combat_hunched_large_turnR90_slide, %tp_moon_civ_run_combat_hunched_large_turnR90_stumble ];
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][7] = undefined;
level._scr_anim[ "default_civilian"]["run_combat_hunched_large_turn"][9] = undefined;
*/
}

1532
animscripts/combat.gsc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
// combat_say.gsc
// Determines when to talk during combat.
// Plays miscellaneous combat lines sometimes during combat
generic_combat()
{
self animscripts\battlechatter::playBattleChatter();
}
// Plays vaguely context-sensitive combat lines sometimes during combat
specific_combat( dialogueLine )
{
self animscripts\battlechatter::playBattleChatter();
}

File diff suppressed because it is too large Load Diff

1402
animscripts/corner.gsc Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,979 @@
#include maps\_utility;
#include animscripts\combat_utility;
#include animscripts\utility;
#include animscripts\shared;
#include common_scripts\utility;
/*
This file contains the overall behavior for all "whack-a-mole" cover nodes.
Callbacks which must be defined:
All callbacks should return true or false depending on whether they succeeded in doing something.
If functionality for a callback isn't available, just don't define it.
mainLoopStart()
optional
reload()
plays a reload animation in a hidden position
leaveCoverAndShoot()
does the main attacking; steps out or stands up and fires, goes back to hiding.
should obey orders from decideWhatAndHowToShoot in shoot_behavior.gsc.
look( maxtime )
looks for up to maxtime, stopping and returning if enemy becomes visible or if suppressed
fastlook()
looks quickly
idle()
idles until the "end_idle" notify.
flinch()
flinches briefly (1-2 seconds), doesn't need to return true or false.
grenade( throwAt )
steps out and throws a grenade at the given player / ai
grenadehidden( throwAt )
throws a grenade at the given player / ai without leaving cover
blindfire()
blindfires from cover
example:
behaviorCallbacks = spawnstruct();
behaviorCallbacks.reload = ::reload;
...
animscripts\cover_behavior::main( behaviorCallbacks );
*/
#using_animtree( "generic_human" );
MELEE_GRACE_PERIOD_REQUIRED_TIME = 3000;
MELEE_GRACE_PERIOD_GIVEN_TIME = 5000;
main( behaviorCallbacks )
{
self.couldntSeeEnemyPos = self.origin;// ( set couldntSeeEnemyPos to a place the enemy can't be while we're in corner behavior )
behaviorStartTime = gettime();
coverTimers = spawnstruct();
coverTimers.nextAllowedLookTime = behaviorStartTime - 1;
coverTimers.nextAllowedSuppressTime = behaviorStartTime - 1;
// we won't look for better cover purely out of boredom until this time
resetLookForBetterCoverTime();
resetRespondToDeathTime();
self.seekOutEnemyTime = gettime();
self.a.lastEncounterTime = behaviorStartTime;
self.a.idlingAtCover = false;
self.a.movement = "stop";
// if we break out of cover mode after this time, we will get a grace period during which we can melee charge the player
self.meleeCoverChargeMinTime = behaviorStartTime + MELEE_GRACE_PERIOD_REQUIRED_TIME;
/#
if ( getdvar( "scr_coveridle" ) == "1" )
self.coverNode.script_onlyidle = true;
#/
self thread watchSuppression();
desynched = ( gettime() > 2500 );
correctAngles = getCorrectCoverAngles();
for ( ;; )
{
if ( shouldHelpAdvancingTeammate() )
{
if ( tryRunningToEnemy( true ) )
{
wait 0.05;
continue;
}
}
if ( isdefined( behaviorCallbacks.mainLoopStart ) )
{
startTime = gettime();
self thread endIdleAtFrameEnd();
[[ behaviorCallbacks.mainLoopStart ]]();
if ( gettime() == startTime )
self notify( "dont_end_idle" );
}
if ( isdefined( behaviorCallbacks.moveToNearByCover ) )
{
if ( [[ behaviorCallbacks.moveToNearByCover ]]() )
continue;
}
// tagJW<NOTE>: We do not need or want to teleport the actor when locked to an object
if ( !self isLinked() )
{
self safeTeleport( self.covernode.origin, correctAngles );
}
if ( !desynched )
{
idle( behaviorCallbacks, 0.05 + randomfloat( 1.5 ) );
desynched = true;
continue;
}
if ( doNonAttackCoverBehavior( behaviorCallbacks ) )
continue;
if ( isdefined( anim.throwGrenadeAtPlayerASAP ) && isAlive( level._player ) )
{
if ( tryThrowingGrenade( behaviorCallbacks, level._player ) )
continue;
}
if ( respondToDeadTeammate() )
return;
// determine visibility and suppressability of enemy.
visibleEnemy = false;
suppressableEnemy = false;
if ( isalive( self.enemy ) )
{
visibleEnemy = isEnemyVisibleFromExposed();
suppressableEnemy = canSuppressEnemyFromExposed();
}
// decide what to do.
if ( visibleEnemy )
{
if ( self.a.getBoredOfThisNodeTime < gettime() )
{
if ( lookForBetterCover() )
return;
}
attackVisibleEnemy( behaviorCallbacks );
}
else
{
if ( isdefined( self.aggressiveMode ) || enemyIsHiding() )
{
if ( advanceOnHidingEnemy() )
return;
}
if ( suppressableEnemy )
{
attackSuppressableEnemy( behaviorCallbacks, coverTimers );
}
else
{
if ( attackNothingToDo( behaviorCallbacks, coverTimers ) )
return;
}
}
}
}
end_script( coverMode )
{
self.turnToMatchNode = undefined;
self.a.prevAttack = undefined;
if ( isDefined( self.meleeCoverChargeMinTime ) && (self.meleeCoverChargeMinTime <= getTime()) )
{
// give the AI a chance to charge the player if he forced him out of cover
self.meleeCoverChargeGraceEndTime = getTime() + MELEE_GRACE_PERIOD_GIVEN_TIME;
self.meleeCoverChargeMinTime = undefined;
}
}
getCorrectCoverAngles()
{
correctAngles = ( self.coverNode.angles[ 0 ], getNodeForwardYaw( self.coverNode ), self.coverNode.angles[ 2 ] );
return correctAngles;
}
RESPOND_TO_DEATH_RETRY_INTERVAL = 30 * 1000;
respondToDeadTeammate()
{
if ( self atDangerousNode() && self.a.respondToDeathTime < gettime() )
{
if ( lookForBetterCover() )
return true;
self.a.respondToDeathTime = gettime() + RESPOND_TO_DEATH_RETRY_INTERVAL;
}
return false;
}
doNonAttackCoverBehavior( behaviorCallbacks )
{
/#
if ( isDefined( self.coverNode.script_onlyidle ) )
{
assert( self.coverNode.script_onlyidle );// true or undefined
idle( behaviorCallbacks );
return true;
}
#/
// if we're suppressed, we do other things.
if ( suppressedBehavior( behaviorCallbacks ) )
{
if ( isEnemyVisibleFromExposed() )
resetSeekOutEnemyTime();
self.a.lastEncounterTime = gettime();
return true;
}
// reload if we need to; everything in this loop involves shooting.
if ( coverReload( behaviorCallbacks, 0 ) )
return true;
return false;
}
attackVisibleEnemy( behaviorCallbacks )
{
if ( distanceSquared( self.origin, self.enemy.origin ) > 750 * 750 )
{
if ( tryThrowingGrenade( behaviorCallbacks, self.enemy ) )
return;
}
if ( leaveCoverAndShoot( behaviorCallbacks, "normal" ) )
{
resetSeekOutEnemyTime();
self.a.lastEncounterTime = gettime();
}
else
{
idle( behaviorCallbacks );
}
}
attackSuppressableEnemy( behaviorCallbacks, coverTimers )
{
if ( self.doingAmbush )
{
if ( leaveCoverAndShoot( behaviorCallbacks, "ambush" ) )
return;
}
else if ( self.provideCoveringFire || gettime() >= coverTimers.nextAllowedSuppressTime )
{
preferredActivity = "suppress";
if ( !self.provideCoveringFire && ( gettime() - self.lastSuppressionTime ) > 5000 && randomint( 3 ) < 2 )
preferredActivity = "ambush";
else if ( !self animscripts\shoot_behavior::shouldSuppress() )
preferredActivity = "ambush";
if ( leaveCoverAndShoot( behaviorCallbacks, preferredActivity ) )
{
coverTimers.nextAllowedSuppressTime = gettime() + randomintrange( 3000, 20000 );
// if they're there, we've seen them
if ( isEnemyVisibleFromExposed() )
self.a.lastEncounterTime = gettime();
return;
}
}
if ( tryThrowingGrenade( behaviorCallbacks, self.enemy ) )
return;
idle( behaviorCallbacks );
}
attackNothingToDo( behaviorCallbacks, coverTimers )
{
if ( coverReload( behaviorCallbacks, 0.1 ) )
return false;
if ( isdefined( self.enemy ) )
{
if ( tryThrowingGrenade( behaviorCallbacks, self.enemy ) )
return false;
}
if ( !self.doingAmbush && gettime() >= coverTimers.nextAllowedLookTime )
{
if ( lookForEnemy( behaviorCallbacks ) )
{
coverTimers.nextAllowedLookTime = gettime() + randomintrange( 4000, 15000 );
// if they're there, we've seen them
return false;
}
}
// we're *really* bored right now
if ( gettime() > self.a.getBoredOfThisNodeTime )
{
if ( cantFindAnythingToDo() )
return true;
}
if ( self.doingAmbush || ( gettime() >= coverTimers.nextAllowedSuppressTime && isdefined( self.enemy ) ) )
{
// be ready to ambush them if they happen to show up
if ( leaveCoverAndShoot( behaviorCallbacks, "ambush" ) )
{
if ( isEnemyVisibleFromExposed() )
resetSeekOutEnemyTime();
self.a.lastEncounterTime = gettime();
coverTimers.nextAllowedSuppressTime = gettime() + randomintrange( 6000, 20000 );
return false;
}
}
idle( behaviorCallbacks );
return false;
}
isEnemyVisibleFromExposed()
{
if ( !isdefined( self.enemy ) )
return false;
// if we couldn't see our enemy last time we stepped out, and they haven't moved, assume we still can't see them.
if ( distanceSquared( self.enemy.origin, self.couldntSeeEnemyPos ) < 16 * 16 )
return false;
else
return canSeeEnemyFromExposed();
}
suppressedBehavior( behaviorCallbacks )
{
if ( !isSuppressedWrapper() )
return false;
nextAllowedBlindfireTime = gettime();
justlooked = true;
//prof_begin( "suppressedBehavior" );
while ( isSuppressedWrapper() )
{
justlooked = false;
// tagJW<NOTE>: We do not need or want to teleport the actor when locked to an object
if ( !self isLinked() )
{
self safeTeleport( self.coverNode.origin );
}
tryMovingNodes = true;
// guys that favor blindfire should try to blindfire instead of move a lot more
if ( isdefined( self.favor_blindfire ) )
tryMovingNodes = coinToss();
if ( tryMovingNodes && !isdefined( self.locked_combat ) )
{
if ( tryToGetOutOfDangerousSituation( behaviorCallbacks ) )
{
self notify( "killanimscript" );
//prof_end( "suppressedBehavior" );
return true;
}
}
// if we're only at a concealment node, and it's not providing cover, we shouldn't try to use the cover to keep us safe!
if ( self.a.atConcealmentNode && self canSeeEnemy() )
{
//prof_end( "suppressedBehavior" );
return false;
}
if ( isEnemyVisibleFromExposed() || canSuppressEnemyFromExposed() )
{
if ( isdefined( anim.throwGrenadeAtPlayerASAP ) && isAlive( level._player ) )
{
if ( tryThrowingGrenade( behaviorCallbacks, level._player ) )
continue;
}
if ( coverReload( behaviorCallbacks, 0 ) )
continue;
if ( self.team != "allies" && gettime() >= nextAllowedBlindfireTime )
{
if ( blindfire( behaviorCallbacks ) )
{
nextAllowedBlindfireTime = gettime();
if ( !isdefined( self.favor_blindfire ) )
nextAllowedBlindfireTime += randomintrange( 3000, 12000 );
continue;
}
}
if ( tryThrowingGrenade( behaviorCallbacks, self.enemy ) )
{
justlooked = true;
continue;
}
}
if ( coverReload( behaviorCallbacks, 0.1 ) )
continue;
//prof_end( "suppressedBehavior" );
idle( behaviorCallbacks );
}
if ( !justlooked && randomint( 2 ) == 0 )
lookfast( behaviorCallbacks );
//prof_end( "suppressedBehavior" );
return true;
}
// returns array of integers 0 through n-1, in random order
getPermutation( n )
{
permutation = [];
assert( n > 0 );
if ( n == 1 )
{
permutation[ 0 ] = 0;
}
else if ( n == 2 )
{
permutation[ 0 ] = randomint( 2 );
permutation[ 1 ] = 1 - permutation[ 0 ];
}
else
{
for ( i = 0; i < n; i++ )
permutation[ i ] = i;
for ( i = 0; i < n; i++ )
{
switchIndex = i + randomint( n - i );
temp = permutation[ switchIndex ];
permutation[ SwitchIndex ] = permutation[ i ];
permutation[ i ] = temp;
}
}
return permutation;
}
callOptionalBehaviorCallback( callback, arg, arg2, arg3 )
{
if ( !isdefined( callback ) )
return false;
//prof_begin( "callOptionalBehaviorCallback" );
self thread endIdleAtFrameEnd();
starttime = gettime();
val = undefined;
if ( isdefined( arg3 ) )
val = [[ callback ]]( arg, arg2, arg3 );
else if ( isdefined( arg2 ) )
val = [[ callback ]]( arg, arg2 );
else if ( isdefined( arg ) )
val = [[ callback ]]( arg );
else
val = [[ callback ]]();
/#
// if this assert fails, a behaviorCallback callback didn't return true or false.
assert( isdefined( val ) && ( val == true || val == false ) );
// behaviorCallbacks must return true if and only if they let time pass.
// (it is also important that they only let time pass if they did what they were supposed to do,
// but that's not so easy to enforce.)
if ( val )
assert( gettime() != starttime );
else
assert( gettime() == starttime );
#/
if ( !val )
self notify( "dont_end_idle" );
//prof_end( "callOptionalBehaviorCallback" );
return val;
}
watchSuppression()
{
self endon( "killanimscript" );
// self.lastSuppressionTime is the last time a bullet whizzed by.
// self.suppressionStart is the last time we were thinking it was safe when a bullet whizzed by.
self.lastSuppressionTime = gettime() - 100000;
self.suppressionStart = self.lastSuppressionTime;
while ( 1 )
{
self waittill( "suppression" );
time = gettime();
if ( self.lastSuppressionTime < time - 700 )
self.suppressionStart = time;
self.lastSuppressionTime = time;
}
}
coverReload( behaviorCallbacks, threshold )
{
if ( self.bulletsInClip > weaponClipSize( self.weapon ) * threshold )
return false;
self.isreloading = true;
result = callOptionalBehaviorCallback( behaviorCallbacks.reload );
self.isreloading = false;
return result;
}
// initialGoal can be either "normal", "suppress", or "ambush".
leaveCoverAndShoot( behaviorCallbacks, initialGoal )
{
self thread animscripts\shoot_behavior::decideWhatAndHowToShoot( initialGoal );
if ( !self.fixedNode && !self.doingAmbush && !isdefined( self.locked_combat ) )
self thread breakOutOfShootingIfWantToMoveUp();
val = callOptionalBehaviorCallback( behaviorCallbacks.leaveCoverAndShoot );
self notify( "stop_deciding_how_to_shoot" );
return val;
}
lookForEnemy( behaviorCallbacks )
{
if ( self.a.atConcealmentNode && self canSeeEnemy() )
return false;
if ( self.a.lastEncounterTime + 6000 > gettime() )
{
return lookfast( behaviorCallbacks );
}
else
{
// look slow if possible
result = callOptionalBehaviorCallback( behaviorCallbacks.look, 2 + randomfloat( 2 ) );
if ( result )
return true;
return callOptionalBehaviorCallback( behaviorCallbacks.fastlook );
}
}
lookfast( behaviorCallbacks )
{
// look fast if possible
result = callOptionalBehaviorCallback( behaviorCallbacks.fastlook );
if ( result )
return true;
return callOptionalBehaviorCallback( behaviorCallbacks.look, 0 );
}
idle( behaviorCallbacks, howLong )
{
self.flinching = false;
if ( isdefined( behaviorCallbacks.flinch ) )
{
// flinch if we just started getting shot at very recently
if ( !self.a.idlingAtCover && gettime() - self.suppressionStart < 600 )
{
if ( [[ behaviorCallbacks.flinch ]]() )
return true;
}
else
{
// if bullets aren't already whizzing by, idle for now but flinch if we get incoming fire
self thread flinchWhenSuppressed( behaviorCallbacks );
}
}
if ( !self.a.idlingAtCover )
{
assert( isdefined( behaviorCallbacks.idle ) );// idle must be available!
self thread idleThread( behaviorCallbacks.idle );// this thread doesn't stop until "end_idle", which must be notified before we start anything else! use endIdleAtFrameEnd() to do this.
self.a.idlingAtCover = true;
}
if ( isdefined( howLong ) )
self idleWait( howLong );
else
self idleWaitABit();
if ( self.flinching )
self waittill( "flinch_done" );
self notify( "stop_waiting_to_flinch" );
}
idleWait( howLong )
{
self endon( "end_idle" );
wait howLong;
}
idleWaitAbit()
{
self endon( "end_idle" );
wait 0.3 + randomfloat( 0.1 );
self waittill( "do_slow_things" );
}
idleThread( idlecallback )
{
self endon( "killanimscript" );
self [[ idlecallback ]]();
}
flinchWhenSuppressed( behaviorCallbacks )
{
self endon( "killanimscript" );
self endon( "stop_waiting_to_flinch" );
lastSuppressionTime = self.lastSuppressionTime;
while ( 1 )
{
self waittill( "suppression" );
time = gettime();
if ( lastSuppressionTime < time - 2000 )
break;
lastSuppressionTime = time;
}
self.flinching = true;
self thread endIdleAtFrameEnd();
assert( isdefined( behaviorCallbacks.flinch ) );
val = [[ behaviorCallbacks.flinch ]]();
if ( !val )
self notify( "dont_end_idle" );
self.flinching = false;
self notify( "flinch_done" );
}
endIdleAtFrameEnd()
{
self endon( "killanimscript" );
self endon( "dont_end_idle" );
waittillframeend;
if ( !isdefined( self ) )
return;
self notify( "end_idle" );
self.a.idlingAtCover = false;
}
tryThrowingGrenade( behaviorCallbacks, throwAt )
{
assert( isdefined( throwAt ) );
// don't throw backwards
forward = anglesToForward( self.angles );
dir = vectorNormalize( throwAt.origin - self.origin );
if ( vectorDot( forward, dir ) < 0 )
return false;
if ( self.doingAmbush && !recentlySawEnemy() )
return false;
if ( self isPartiallySuppressedWrapper() )
{
return callOptionalBehaviorCallback( behaviorCallbacks.grenadehidden, throwAt );
}
else
{
return callOptionalBehaviorCallback( behaviorCallbacks.grenade, throwAt );
}
}
blindfire( behaviorCallbacks )
{
if ( !canBlindFire() )
return false;
return callOptionalBehaviorCallback( behaviorCallbacks.blindfire );
}
// Need this?
breakOutOfShootingIfWantToMoveUp()
{
self endon( "killanimscript" );
self endon( "stop_deciding_how_to_shoot" );
while ( 1 )
{
if ( self.fixedNode || self.doingAmbush )
return;
wait 0.5 + randomfloat( 0.75 );
if ( !isdefined( self.enemy ) )
continue;
if ( enemyIsHiding() )
{
if ( advanceOnHidingEnemy() )
return;
}
if ( !self recentlySawEnemy() && !self canSuppressEnemy() )
{
if ( gettime() > self.a.getBoredOfThisNodeTime )
{
if ( cantFindAnythingToDo() )
return;
}
}
}
}
enemyIsHiding()
{
// if this function is called, we already know that our enemy is not visible from exposed.
// check to see if they're doing anything hiding-like.
if ( !isdefined( self.enemy ) )
return false;
if ( self.enemy isFlashed() )
return true;
if ( isplayer( self.enemy ) )
{
if ( isdefined( self.enemy.health ) && self.enemy.health < self.enemy.maxhealth )
return true;
}
else
{
if ( isAI( self.enemy ) && self.enemy isSuppressedWrapper() )
return true;
}
if ( isdefined( self.enemy.isreloading ) && self.enemy.isreloading )
return true;
return false;
}
resetRespondToDeathTime()
{
self.a.respondToDeathTime = 0;
}
resetLookForBetterCoverTime()
{
currentTime = gettime();
// treat group of shuffle nodes as one node, don't increase getBoredOfThisNodeTime by too much
if ( isdefined( self.didShuffleMove ) && currentTime > self.a.getBoredOfThisNodeTime )
{
self.a.getBoredOfThisNodeTime = currentTime + randomintrange( 2000, 5000 );
}
else if ( isdefined( self.enemy ) )
{
dist = distance2D( self.origin, self.enemy.origin );
if ( dist < self.engageMinDist )
self.a.getBoredOfThisNodeTime = currentTime + randomintrange( 5000, 10000 );
else if ( dist > self.engageMaxDist && dist < self.goalradius )
self.a.getBoredOfThisNodeTime = currentTime + randomintrange( 2000, 5000 );
else
self.a.getBoredOfThisNodeTime = currentTime + randomintrange( 10000, 15000 );
}
else
{
self.a.getBoredOfThisNodeTime = currentTime + randomintrange( 5000, 15000 );
}
}
resetSeekOutEnemyTime()
{
// we'll be willing to actually run right up to our enemy in order to find them if we haven't seen them by this time.
// however, we'll try to find better cover before seeking them out
if ( isdefined( self.aggressiveMode ) )
self.seekOutEnemyTime = gettime() + randomintrange( 500, 1000 );
else
self.seekOutEnemyTime = gettime() + randomintrange( 3000, 5000 );
}
// these next functions are "look for better cover" functions.
// they don't always need to cause the actor to leave the node immediately,
// but if they keep being called over and over they need to become more and more likely to do so,
// as this indicates that new cover is strongly needed.
cantFindAnythingToDo()
{
return advanceOnHidingEnemy();
}
advanceOnHidingEnemy()
{
if ( self.fixedNode || self.doingAmbush )
return false;
if ( isdefined( self.aggressiveMode ) && gettime() >= self.seekOutEnemyTime )
{
return tryRunningToEnemy( false );
}
foundBetterCover = false;
if ( !isdefined( self.enemy ) || !self.enemy isFlashed() )
foundBetterCover = lookForBetterCover();
if ( !foundBetterCover && isdefined( self.enemy ) && !self canSeeEnemyFromExposed() )
{
if ( gettime() >= self.seekOutEnemyTime )
{
return tryRunningToEnemy( false );
}
}
// maybe at this point we could look for someone who's suppressing our enemy,
// and if someone is, we can say "cover me!" and have them say "i got you covered" or something.
return foundBetterCover;
}
tryToGetOutOfDangerousSituation( behaviorCallbacks )
{
if ( isdefined( behaviorCallbacks.moveToNearByCover ) )
{
if ( [[ behaviorCallbacks.moveToNearByCover ]]() )
return true;
}
return lookForBetterCover();
}
// TEMP move these into animsets
set_standing_turns()
{
self.a.array[ "turn_left_45" ] = %exposed_tracking_turn45L;
self.a.array[ "turn_left_90" ] = %exposed_tracking_turn90L;
self.a.array[ "turn_left_135" ] = %exposed_tracking_turn135L;
self.a.array[ "turn_left_180" ] = %exposed_tracking_turn180L;
self.a.array[ "turn_right_45" ] = %exposed_tracking_turn45R;
self.a.array[ "turn_right_90" ] = %exposed_tracking_turn90R;
self.a.array[ "turn_right_135" ] = %exposed_tracking_turn135R;
self.a.array[ "turn_right_180" ] = %exposed_tracking_turn180R;
}
set_crouching_turns()
{
self.a.array[ "turn_left_45" ] = %exposed_crouch_turn_90_left;
self.a.array[ "turn_left_90" ] = %exposed_crouch_turn_90_left;
self.a.array[ "turn_left_135" ] = %exposed_crouch_turn_180_left;
self.a.array[ "turn_left_180" ] = %exposed_crouch_turn_180_left;
self.a.array[ "turn_right_45" ] = %exposed_crouch_turn_90_right;
self.a.array[ "turn_right_90" ] = %exposed_crouch_turn_90_right;
self.a.array[ "turn_right_135" ] = %exposed_crouch_turn_180_right;
self.a.array[ "turn_right_180" ] = %exposed_crouch_turn_180_right;
}
turnToMatchNodeDirection( nodeAngleOffset )
{
if ( isdefined( self.node ) )
{
node = self.node;
absRelYaw = abs( AngleClamp180( self.angles[1] - ( node.angles[1] + nodeAngleOffset ) ) );
if ( self.a.pose == "stand" && node getHighestNodeStance() != "stand" )
{
if ( absRelYaw > 45 && absRelYaw < 90 )
self orientmode( "face angle", self.angles[1] );
else
self orientmode( "face current" );
rate = 1.5;
noteTime = getNotetrackTimes( %exposed_stand_2_crouch, "anim_pose = \"crouch\"" )[0];
noteTime = min( 1, noteTime * 1.1 );
time = noteTime * getAnimLength( %exposed_stand_2_crouch ) / rate;
self setflaggedanimknoballrestart( "crouchanim", %exposed_stand_2_crouch, %body, 1, .2, rate );
self animscripts\shared::DoNoteTracksForTime( time, "crouchanim" );
self clearanim( %body, 0.2 );
}
self orientmode( "face angle", self.angles[1] );
relYaw = AngleClamp180( self.angles[1] - ( node.angles[1] + nodeAngleOffset ) );
if ( abs( relYaw ) > 45 )
{
if ( self.a.pose == "stand" )
set_standing_turns();
else
set_crouching_turns();
self.turnThreshold = 45;
self.turnToMatchNode = true;
animscripts\combat::TurnToFaceRelativeYaw( relYaw );
self.turnToMatchNode = undefined;
}
}
}
moveToNearbyCover()
{
if ( !isdefined( self.enemy ) )
return false;
if ( isdefined( self.didShuffleMove ) )
{
self.didShuffleMove = undefined;
return false;
}
if ( !isdefined( self.node ) )
return false;
if ( randomint( 3 ) == 0 )
return false;
if ( self.fixedNode || self.doingAmbush || self.keepClaimedNode || self.keepClaimedNodeIfValid )
return false;
if ( distanceSquared( self.origin, self.node.origin ) > 16 * 16 )
return false;
node = self findshufflecovernode();
if ( isdefined( node ) && ( node != self.node ) && self useCoverNode( node ) )
{
self.shuffleMove = true;
self.shuffleNode = node;
self.didShuffleMove = true;
// give code a chance use new cover node
wait 0.5;
return true;
}
return false;
}

View File

@ -0,0 +1,25 @@
#include animscripts\Combat_utility;
#include animscripts\Utility;
#include common_scripts\Utility;
#using_animtree( "generic_human" );
main()
{
// assert( !usingSidearm() );
self endon( "killanimscript" );
// [[ self.exception[ "cover_crouch" ] ]]();
animscripts\utility::initialize( "cover_crouch" );
self animscripts\cover_wall::cover_wall_think( "crouch" );
}
end_script()
{
self.coverCrouchLean_aimmode = undefined;
animscripts\cover_behavior::end_script( "crouch" );
}

View File

@ -0,0 +1,53 @@
#include maps\_utility;
#include animscripts\Combat_utility;
#include animscripts\utility;
#using_animtree( "generic_human" );
// (Note that animations called right are used with left corner nodes, and vice versa.)
main()
{
self.animArrayFuncs = [];
self.animArrayFuncs[ "hiding" ][ "stand" ] = ::set_animarray_standing_left;
self.animArrayFuncs[ "hiding" ][ "crouch" ] = ::set_animarray_crouching_left;
if ( IsDefined( self.customAnimFunc ) && IsDefined( self.customAnimFunc[ "cover_left" ] ) )
{
if ( IsDefined( self.customAnimFunc[ "cover_left" ][ "stand" ] ) )
{
self.animArrayFuncs[ "hiding" ][ "stand" ] = self.customAnimFunc[ "cover_left" ][ "stand" ];
}
if ( IsDefined( self.customAnimFunc[ "cover_left" ][ "crouch" ] ) )
{
self.animArrayFuncs[ "hiding" ][ "crouch" ] = self.customAnimFunc[ "cover_left" ][ "crouch" ];
}
}
self endon( "killanimscript" );
animscripts\utility::initialize( "cover_left" );
animscripts\corner::corner_think( "left", 90 );
}
end_script()
{
animscripts\corner::end_script_corner();
animscripts\cover_behavior::end_script( "left" );
}
set_animarray_standing_left() /* void */
{
assert( IsDefined(anim.coverLeftStand) );
self.hideYawOffset = 90;
self.a.array = anim.coverLeftStand;
}
set_animarray_crouching_left()
{
assert( IsDefined(anim.coverLeftCrouch) );
self.hideYawOffset = 90;
self.a.array = anim.coverLeftCrouch;
}

360
animscripts/cover_prone.gsc Normal file
View File

@ -0,0 +1,360 @@
#include animscripts\combat_utility;
#include animscripts\utility;
#include animscripts\shared;
#include common_scripts\utility;
#using_animtree( "generic_human" );
// TODO:
// - figure out why aiming range is incorrect (aiming arc seems a bit off)
main()
{
self endon( "killanimscript" );
animscripts\utility::initialize( "cover_prone" );
// TODO: run cover crouch or exposed crouch
if ( weaponClass( self.weapon ) == "rocketlauncher" )
{
animscripts\combat::main();
return;
}
if ( isDefined( self.a.arrivalType ) && self.a.arrivalType == "prone_saw" )
{
assert( isDefined( self.node.turretInfo ) );
self animscripts\cover_wall::useSelfPlacedTurret( "saw_bipod_prone", "weapon_saw_MG_Setup" );
}
else if ( isDefined( self.node.turret ) )
{
self animscripts\cover_wall::useStationaryTurret();
}
// if we're too close to our enemy, stand up
// (285 happens to be the same distance at which we leave cover and go into exposed if our enemy approaches)
if ( isDefined( self.enemy ) && lengthSquared( self.origin - self.enemy.origin ) < squared( 512 ) )
{
self thread animscripts\combat::main();
return;
}
self setup_cover_prone();
self.coverNode = self.node;
self OrientMode( "face angle", self.coverNode.angles[ 1 ] );
self.a.goingToProneAim = true;
self setProneAnimNodes( -45, 45, %prone_legs_down, %exposed_modern, %prone_legs_up );
if ( self.a.pose != "prone" )
self prone_transitionTo( "prone" );
else
self EnterProneWrapper( 0 );
self thread aimIdleThread();
setupProneAim( 0.2 );
self setAnim( %prone_aim_5, 1, 0.1 );
// face the direction of our covernode
self OrientMode( "face angle", self.coverNode.angles[ 1 ] );
self animmode( "zonly_physics" );
self proneCombatMainLoop();
self notify( "stop_deciding_how_to_shoot" );
}
end_script()
{
self.a.goingToProneAim = undefined;
}
idleThread()
{
self endon( "killanimscript" );
self endon( "kill_idle_thread" );
for ( ;; )
{
idleAnim = animArrayPickRandom( "prone_idle" );
self setflaggedanimlimited( "idle", idleAnim );
self waittillmatch( "idle", "end" );
self clearanim( idleAnim, .2 );
}
}
UpdateProneWrapper( time )
{
self UpdateProne( %prone_aim_feet_45up, %prone_aim_feet_45down, 1, time, 1 );
self setanim( %exposed_aiming, 1, .2 );
}
proneCombatMainLoop()
{
self endon( "killanimscript" );
self thread trackShootEntOrPos();
// self thread ReacquireWhenNecessary();
self thread animscripts\shoot_behavior::decideWhatAndHowToShoot( "normal" );
// self resetGiveUpOnEnemyTime();
desynched = ( gettime() > 2500 );
//prof_begin("prone_combat");
for ( ;; )
{
self animscripts\utility::IsInCombat();// reset our in - combat state
self UpdateProneWrapper( 0.05 );
if ( !desynched )
{
wait( 0.05 + randomfloat( 1.5 ) );
desynched = true;
continue;
}
if ( !isdefined( self.shootPos ) )
{
assert( !isdefined( self.shootEnt ) );
if ( considerThrowGrenade() )
continue;
wait( 0.05 );
continue;
}
assert( isdefined( self.shootPos ) );// we can use self.shootPos after this point.
// self resetGiveUpOnEnemyTime();
// if we're too close to our enemy, stand up
// (285 happens to be the same distance at which we leave cover and go into exposed if our enemy approaches)
distSqToShootPos = lengthsquared( self.origin - self.shootPos );
if ( self.a.pose != "crouch" && self isStanceAllowed( "crouch" ) && distSqToShootPos < squared( 400 ) )
{
if ( distSqToShootPos < squared( 285 ) )
{
prone_transitionTo( "crouch" );
self thread animscripts\combat::main();
return;
}
}
if ( considerThrowGrenade() )// TODO: make considerThrowGrenade work with shootPos rather than only self.enemy
continue;
if ( self proneReload( 0 ) )
continue;
if ( aimedAtShootEntOrPos() )
{
shootUntilShootBehaviorChange();
self clearAnim( %add_fire, .2 );
continue;
}
// idleThread() is running, so just waiting a bit will cause us to idle
wait( 0.05 );
}
//prof_end("prone_combat");
}
proneReload( threshold )
{
return Reload( threshold, self animArray( "reload" ) );
}
setup_cover_prone()
{
self setDefaultAimLimits( self.node );
anim_array = [];
anim_array[ "straight_level" ] = %prone_aim_5;
anim_array[ "fire" ] = %prone_fire_1;
anim_array[ "semi2" ] = %prone_fire_burst;
anim_array[ "semi3" ] = %prone_fire_burst;
anim_array[ "semi4" ] = %prone_fire_burst;
anim_array[ "semi5" ] = %prone_fire_burst;
anim_array[ "single" ] = array( %prone_fire_1 );
anim_array[ "continuous" ] = array( %nx_tp_stand_exposed_stream_01 );
anim_array[ "burst2" ] = %prone_fire_burst;// ( will be limited to 2 shots )
anim_array[ "burst3" ] = %prone_fire_burst;
anim_array[ "burst4" ] = %prone_fire_burst;
anim_array[ "burst5" ] = %prone_fire_burst;
anim_array[ "burst6" ] = %prone_fire_burst;
anim_array[ "reload" ] = %prone_reload;
anim_array[ "look" ] = array( %prone_twitch_look, %prone_twitch_lookfast, %prone_twitch_lookup );
anim_array[ "grenade_safe" ] = array( %prone_grenade_A, %prone_grenade_A );
anim_array[ "grenade_exposed" ] = array( %prone_grenade_A, %prone_grenade_A );
anim_array[ "exposed_idle" ] = array( %prone_idle );
anim_array[ "hide_to_look" ] = %coverstand_look_moveup;
anim_array[ "look_idle" ] = %coverstand_look_idle;
anim_array[ "look_to_hide" ] = %coverstand_look_movedown;
anim_array[ "look_to_hide_fast" ] = %coverstand_look_movedown_fast;
anim_array[ "stand_2_prone" ] = %stand_2_prone_nodelta;
anim_array[ "crouch_2_prone" ] = %crouch_2_prone;
anim_array[ "prone_2_stand" ] = %prone_2_stand_nodelta;
anim_array[ "prone_2_crouch" ] = %prone_2_crouch;
anim_array[ "stand_2_prone_firing" ] = %stand_2_prone_firing;
anim_array[ "crouch_2_prone_firing" ] = %crouch_2_prone_firing;
anim_array[ "prone_2_stand_firing" ] = %prone_2_stand_firing;
anim_array[ "prone_2_crouch_firing" ] = %prone_2_crouch_firing;
self.a.array = anim_array;
}
tryThrowingGrenade( throwAt, safe )
{
theanim = undefined;
if ( isdefined( safe ) && safe )
theanim = animArrayPickRandom( "grenade_safe" );
else
theanim = animArrayPickRandom( "grenade_exposed" );
self animMode( "zonly_physics" );// Unlatch the feet
self.keepClaimedNodeIfValid = true;
armOffset = ( 32, 20, 64 );// needs fixing!
threwGrenade = TryGrenade( throwAt, theanim );
self.keepClaimedNodeIfValid = false;
return threwGrenade;
}
considerThrowGrenade()
{
if ( isdefined( anim.throwGrenadeAtPlayerASAP ) && isAlive( level._player ) )
{
if ( tryThrowingGrenade( level._player, 200 ) )
return true;
}
if ( isdefined( self.enemy ) )
return tryThrowingGrenade( self.enemy, 850 );
return false;
}
shouldFireWhileChangingPose()
{
if ( !isdefined( self.weapon ) || !WeaponIsAuto( self.weapon ) )
return false;
if ( isdefined( self.node ) && distanceSquared( self.origin, self.node.origin ) < 16 * 16 )
return false;// we're on a node and can't use an animation with a delta
if ( isDefined( self.enemy ) && self canSee( self.enemy ) && !isdefined( self.grenade ) && self getAimYawToShootEntOrPos() < 20 )
return animscripts\move::MayShootWhileMoving();
return false;
}
prone_transitionTo( newPose )
{
if ( newPose == self.a.pose )
return;
self clearanim( %root, .3 );
self endFireAndAnimIdleThread();
if ( shouldFireWhileChangingPose() )
transAnim = animArray( self.a.pose + "_2_" + newPose + "_firing" );
else
transAnim = animArray( self.a.pose + "_2_" + newPose );
if ( newPose == "prone" )
{
// this is crucial. if it doesn't have this notetrack, we won't call enterProneWrapper!
assert( animHasNotetrack( transAnim, "anim_pose = \"prone\"" ) );
}
self setFlaggedAnimKnobAllRestart( "trans", transAnim, %body, 1, .2, 1.0 );
animscripts\shared::DoNoteTracks( "trans" );
assert( self.a.pose == newPose );
self setAnimKnobAllRestart( animarray( "straight_level" ), %body, 1, .25 );
setupProneAim( .25 );
}
finishNoteTracks( animname )
{
self endon( "killanimscript" );
animscripts\shared::DoNoteTracks( animname );
}
setupProneAim( transTime )
{
self setAnimKnobAll( %prone_aim_5, %body, 1, transTime );
self setAnimLimited( %prone_aim_2_add, 1, transTime );
self setAnimLimited( %prone_aim_4_add, 1, transTime );
self setAnimLimited( %prone_aim_6_add, 1, transTime );
self setAnimLimited( %prone_aim_8_add, 1, transTime );
}
proneTo( newPose, rate )
{
assert( self.a.pose == "prone" );
// self OrientMode( "face angle", self.angles[1] );
self clearanim( %root, .3 );
transAnim = undefined;
if ( shouldFireWhileChangingPose() )
{
if ( newPose == "crouch" )
transAnim = %prone_2_crouch_firing;
else if ( newPose == "stand" )
transAnim = %prone_2_stand_firing;
}
else
{
if ( newPose == "crouch" )
transAnim = %prone_2_crouch;
else if ( newPose == "stand" )
transAnim = %prone_2_stand_nodelta;
}
if ( isdefined( self.prone_anim_override ) )
transAnim = self.prone_anim_override;
if ( isdefined( self.prone_rate_override ) )
rate = self.prone_rate_override;
assert( isDefined( transAnim ) );
if ( !isdefined( rate ) )
rate = 1;
self ExitProneWrapper( getAnimLength( transAnim ) / 2 );
self setFlaggedAnimKnobAllRestart( "trans", transAnim, %body, 1, .2, rate );
animscripts\shared::DoNoteTracks( "trans" );
self clearAnim( transAnim, 0.1 );
assert( self.a.pose == newPose );
// self.a.pose = newPose; // failsafe
}

View File

@ -0,0 +1,53 @@
#include maps\_utility;
#include animscripts\Combat_utility;
#include animscripts\utility;
#using_animtree( "generic_human" );
// (Note that animations called left are used with right corner nodes, and vice versa.)
main()
{
self.animArrayFuncs = [];
self.animArrayFuncs[ "hiding" ][ "stand" ] = ::set_animarray_standing_right;
self.animArrayFuncs[ "hiding" ][ "crouch" ] = ::set_animarray_crouching_right;
if ( IsDefined( self.customAnimFunc ) && IsDefined( self.customAnimFunc[ "cover_right" ] ) )
{
if ( IsDefined( self.customAnimFunc[ "cover_right" ][ "stand" ] ) )
{
self.animArrayFuncs[ "hiding" ][ "stand" ] = self.customAnimFunc[ "cover_right" ][ "stand" ];
}
if ( IsDefined( self.customAnimFunc[ "cover_right" ][ "crouch" ] ) )
{
self.animArrayFuncs[ "hiding" ][ "crouch" ] = self.customAnimFunc[ "cover_right" ][ "crouch" ];
}
}
self endon( "killanimscript" );
animscripts\utility::initialize( "cover_right" );
animscripts\corner::corner_think( "right", -90 );
}
end_script()
{
animscripts\corner::end_script_corner();
animscripts\cover_behavior::end_script( "right" );
}
set_animarray_standing_right() /* void */
{
assert( IsDefined(anim.coverRightStand));
self.hideYawOffset = -90;
self.a.array = anim.coverRightStand;
}
set_animarray_crouching_right()
{
assert( IsDefined(anim.coverRightCrouch));
self.hideYawOffset = -90;
self.a.array = anim.coverRightCrouch;
}

View File

@ -0,0 +1,22 @@
#include animscripts\Combat_utility;
#include animscripts\Utility;
#include common_scripts\Utility;
#using_animtree( "generic_human" );
main()
{
// assert( !usingSidearm() );
self endon( "killanimscript" );
// [[ self.exception[ "cover_stand" ] ]]();
animscripts\utility::initialize( "cover_stand" );
self animscripts\cover_wall::cover_wall_think( "stand" );
}
end_script()
{
animscripts\cover_behavior::end_script( "stand" );
}

893
animscripts/cover_wall.gsc Normal file
View File

@ -0,0 +1,893 @@
#include animscripts\Combat_utility;
#include animscripts\Utility;
#include common_scripts\Utility;
#using_animtree( "generic_human" );
cover_wall_think( coverType )
{
self endon( "killanimscript" );
if ( isdefined( self.locked_combat ) && self.locked_combat )
{
return;
}
self.coverNode = self.node;
self.coverType = coverType;
if ( !isDefined( self.node.turret ) )
animscripts\cover_behavior::turnToMatchNodeDirection( 0 );
if ( coverType == "crouch" )
{
self setup_cover_crouch( "unknown" );
self.coverNode initCoverCrouchNode();
}
else
{
self setup_cover_stand( "unknown" );
}
self.a.aimIdleThread = undefined;
// face the direction of our covernode
self OrientMode( "face angle", self.coverNode.angles[ 1 ] );
if ( isDefined( self.weapon ) && usingMG() && isDefined( self.node ) && isDefined( self.node.turretInfo ) && canspawnturret() )
{
if ( coverType == "crouch" )
{
if ( isRPD( self.weapon ) )
weaponInfo = "rpd_bipod_crouch";
else
weaponInfo = "saw_bipod_crouch";
}
else
{
if ( isRPD( self.weapon ) )
weaponInfo = "rpd_bipod_stand";
else
weaponInfo = "saw_bipod_stand";
}
if ( isRPD( self.weapon ) )
weaponModel = "weapon_rpd_MG_Setup";
else
weaponModel = "weapon_saw_MG_Setup";
self useSelfPlacedTurret( weaponInfo, weaponModel );
}
else if ( isDefined( self.node ) && isDefined( self.node.turret ) )
{
self useStationaryTurret();
}
self animmode( "normal" );
//start in hide position
if ( coverType == "crouch" && self.a.pose == "stand" )
{
transAnim = animArray( "stand_2_hide" );
time = getAnimLength( transAnim );
self setAnimKnobAllRestart( transAnim, %body, 1, 0.2, fasterAnimSpeed() );
self thread animscripts\shared::moveToOriginOverTime( self.coverNode.origin, time );
wait time;
self.a.coverMode = "hide";
}
else
{
loopHide( .4 );// need to transition to hide here in case we didn't do an approach
if ( distanceSquared( self.origin, self.coverNode.origin ) > 1 )
{
self thread animscripts\shared::moveToOriginOverTime( self.coverNode.origin, .4 );
wait( .2 );
if ( coverType == "crouch" )
self.a.pose = "crouch";
wait( .2 );
}
else
{
wait 0.1;
}
}
self animmode( "zonly_physics" );
if ( coverType == "crouch" )
{
if ( self.a.pose == "prone" )
self ExitProneWrapper( 1 );
self.a.pose = "crouch";// in case we only lerped into the pose
}
if ( self.coverType == "stand" )
self.a.special = "cover_stand";
else
self.a.special = "cover_crouch";
behaviorCallbacks = spawnstruct();
if ( !self.fixedNode )
behaviorCallbacks.moveToNearByCover = animscripts\cover_behavior::moveToNearbyCover;
behaviorCallbacks.reload = ::coverReload;
behaviorCallbacks.leaveCoverAndShoot = ::popUpAndShoot;
behaviorCallbacks.look = ::look;
behaviorCallbacks.fastlook = ::fastLook;
behaviorCallbacks.idle = ::idle;
behaviorCallbacks.flinch = ::flinch;
behaviorCallbacks.grenade = ::tryThrowingGrenade;
behaviorCallbacks.grenadehidden = ::tryThrowingGrenadeStayHidden;
behaviorCallbacks.blindfire = ::blindfire;
animscripts\cover_behavior::main( behaviorCallbacks );
}
isRPD( weapon )
{
return getSubStr( weapon, 0, 3 ) == "rpd" && (weapon.size == 3 || weapon[3] == "_");
}
initCoverCrouchNode()
{
if ( isdefined( self.crouchingIsOK ) )
return;
// it's only ok to crouch at this node if we can see out from a crouched position.
crouchHeightOffset = ( 0, 0, 42 );
forward = anglesToForward( self.angles );
self.crouchingIsOK = sightTracePassed( self.origin + crouchHeightOffset, self.origin + crouchHeightOffset + vector_multiply( forward, 64 ), false, undefined );
}
setup_cover_crouch( exposedAnimSet )
{
if ( !isdefined( self.locked_combat ) )
{
self setDefaultAimLimits( self.coverNode );
}
self setup_crouching_anim_array( exposedAnimSet );
}
setup_cover_stand( exposedAnimSet )
{
if ( !isdefined( self.locked_combat ) )
{
self setDefaultAimLimits( self.coverNode );
}
self setup_standing_anim_array( exposedAnimSet );
}
coverReload()
{
return Reload( 2.0, animArray( "reload" ) );// ( reload no matter what )
}
popUpAndShoot()
{
self.keepClaimedNodeIfValid = true;
if ( isdefined( self.ramboChance ) && randomFloat( 1 ) < self.ramboChance )
{
if ( rambo() )
return true;
}
if ( !pop_up() )
return false;
shootAsTold();
self endFireAndAnimIdleThread();
if ( isDefined( self.shootPos ) )
{
distSqToShootPos = lengthsquared( self.origin - self.shootPos );
// too close for RPG or out of ammo
if ( usingRocketLauncher() && ( distSqToShootPos < squared( 512 ) || self.a.rockets < 1 ) )
{
if ( self.a.pose == "stand" )
animscripts\shared::throwDownWeapon( %RPG_stand_throw );
else
animscripts\shared::throwDownWeapon( %RPG_crouch_throw );
}
}
go_to_hide();
self.coverCrouchLean_aimmode = undefined;
self.keepClaimedNodeIfValid = false;
return true;
}
shootAsTold()
{
self endon( "return_to_cover" );
self maps\_gameskill::didSomethingOtherThanShooting();
while ( 1 )
{
if ( isdefined( self.shouldReturnToCover ) )
break;
if ( !isdefined( self.shootPos ) ) {
assert( !isdefined( self.shootEnt ) );
// give shoot_behavior a chance to iterate
self waittill( "do_slow_things" );
waittillframeend;
if ( isdefined( self.shootPos ) )
continue;
break;
}
if ( !self.bulletsInClip )
break;
// crouch only
if ( self.coverType == "crouch" && needToChangeCoverMode() )
{
break;
// TODO: if changing between stances without returning to cover is implemented,
// we can't just endon("return_to_cover") because it will cause problems when it
// happens while changing stance.
// see corner's implementation of this idea for a better implementation.
// NYI
/*changeCoverMode();
// if they're moving too fast for us to respond intelligently to them,
// give up on firing at them for the moment
if ( needToChangeCoverMode() )
break;
continue;*/
}
shootUntilShootBehaviorChange_coverWall();
self clearAnim( %add_fire, .2 );
}
}
shootUntilShootBehaviorChange_coverWall()
{
if ( self.coverType == "crouch" )
self thread angleRangeThread();// gives stopShooting notify when shootPosOutsideLegalYawRange returns true
self thread aimIdleThread();
shootUntilShootBehaviorChange();
}
rambo()
{
if ( !hasEnemySightPos() )
return false;
animType = "rambo";
if ( randomint( 10 ) < 2 )
animType = "rambo_fail";
if ( !animArrayAnyExist( animType ) )
return false;
if ( self.coverType == "crouch" && !self.coverNode.crouchingIsOK )
return false;
pitch = getShootPosPitch( self.coverNode.origin + getNodeOffset( self.coverNode ) );
if ( pitch > 15 )
return false;
forward = anglesToForward( self.angles );
stepto = self.origin + vector_multiply( forward, -16 );
if ( !self mayMoveToPoint( stepto ) )
return false;
self.coverPosEstablishedTime = gettime();
self animMode( "zonly_physics" );
self.keepClaimedNodeIfValid = true;
self.isRambo = true;
self.a.prevAttack = "rambo";
self.changingCoverPos = true;
self thread animscripts\shared::ramboAim( 0 );
ramboAnim = animArrayPickRandom( animType );
self setFlaggedAnimKnobAllRestart( "rambo", ramboAnim, %body, 1, .2, 1 );
self animscripts\shared::DoNoteTracks( "rambo" );
self notify( "rambo_aim_end" );
self.changingCoverPos = false;
self.keepClaimedNodeIfValid = false;
self.lastRamboTime = getTime();
self.changingCoverPos = false;
self.isRambo = undefined;
return true;
}
idle()
{
self endon( "end_idle" );
while ( 1 )
{
useTwitch = ( randomint( 2 ) == 0 && animArrayAnyExist( "hide_idle_twitch" ) );
if ( useTwitch )
idleanim = animArrayPickRandom( "hide_idle_twitch" );
else
idleanim = animarray( "hide_idle" );
playIdleAnimation( idleAnim, useTwitch );
}
}
flinch()
{
if ( !animArrayAnyExist( "hide_idle_flinch" ) )
return false;
forward = anglesToForward( self.angles );
stepto = self.origin + vector_multiply( forward, -16 );
if ( !self mayMoveToPoint( stepto ) )
return false;
self animmode( "zonly_physics" );
self.keepClaimedNodeIfValid = true;
flinchanim = animArrayPickRandom( "hide_idle_flinch" );
playIdleAnimation( flinchanim, true );
self.keepClaimedNodeIfValid = false;
return true;
}
playIdleAnimation( idleAnim, needsRestart )
{
if ( needsRestart )
self setFlaggedAnimKnobAllRestart( "idle", idleAnim, %body, 1, 0.25, 1 );
else
self setFlaggedAnimKnobAll( "idle", idleAnim, %body, 1, 0.25, 1 );
self.a.coverMode = "hide";
self animscripts\shared::DoNoteTracks( "idle" );
}
look( lookTime )
{
if ( !isdefined( self.a.array[ "hide_to_look" ] ) )
return false;
if ( !peekOut() )
return false;
animscripts\shared::playLookAnimation( animArray( "look_idle" ), lookTime );// TODO: replace
lookanim = undefined;
if ( self isSuppressedWrapper() )
lookanim = animArray( "look_to_hide_fast" );
else
lookanim = animArray( "look_to_hide" );
self setflaggedanimknoballrestart( "looking_end", lookanim, %body, 1, .1 );
animscripts\shared::DoNoteTracks( "looking_end" );
return true;
}
peekOut()
{
if ( isdefined( self.coverNode.script_dontpeek ) )
return false;
// assuming no delta, so no maymovetopoint check
self setFlaggedAnimKnobAll( "looking_start", animArray( "hide_to_look" ), %body, 1, .2 );
animscripts\shared::DoNoteTracks( "looking_start" );
return true;
}
fastLook()
{
self setFlaggedAnimKnobAllRestart( "look", animArrayPickRandom( "look" ), %body, 1, .1 );
self animscripts\shared::DoNoteTracks( "look" );
return true;
}
// These should be adjusted in animation data
pop_up_and_hide_speed()
{
if ( self.a.coverMode == "left" || self.a.coverMode == "right" || self.a.coverMode == "over" )
return 1;
return randomfasterAnimSpeed();
}
pop_up()
{
assert( !isdefined( self.a.coverMode ) || self.a.coverMode == "hide" );
newCoverMode = getBestCoverMode();
timeleft = .1;
popupAnim = animArray( "hide_2_" + newCoverMode );
if ( !self mayMoveToPoint( getAnimEndPos( popupAnim ) ) )
return false;
if ( self.script == "cover_crouch" && newCoverMode == "lean" )
self.coverCrouchLean_aimmode = true;
if ( self.coverType == "crouch" )
self setup_cover_crouch( newCoverMode );
else
self setup_cover_stand( newCoverMode );
self.a.special = "none";
self.specialDeathFunc = undefined;
if ( self.coverType == "stand" )
self.a.special = "cover_stand_aim";
else
self.a.special = "cover_crouch_aim";
self.changingCoverPos = true;
self notify( "done_changing_cover_pos" );
self animmode( "zonly_physics" );
animRate = pop_up_and_hide_speed();
self setFlaggedAnimKnobAllRestart( "pop_up", popUpAnim, %body, 1, .1, animRate );
self thread DoNoteTracksForPopup( "pop_up" );
if ( animHasNoteTrack( popupAnim, "start_aim" ) )
{
self waittillmatch( "pop_up", "start_aim" );
timeleft = getAnimLength( popupAnim ) / animRate * ( 1 - self getAnimTime( popupAnim ) );
}
else
{
self waittillmatch( "pop_up", "end" );
timeleft = .1;
}
self clearAnim( popUpAnim, timeleft + 0.05 );
self.a.coverMode = newCoverMode;
self.a.prevAttack = newCoverMode;
self setup_additive_aim( timeleft );
self thread animscripts\shared::trackShootEntOrPos();
wait( timeleft );
if ( self isSniper() )
{
thread animscripts\shoot_behavior::sniper_glint_behavior();
}
self.changingCoverPos = false;
self.coverPosEstablishedTime = gettime();
self notify( "stop_popup_donotetracks" );
return true;
}
DoNoteTracksForPopup( animname )
{
self endon( "killanimscript" );
self endon( "stop_popup_donotetracks" );
self animscripts\shared::DoNoteTracks( animname );
}
setup_additive_aim( transTime )
{
if ( self.a.coverMode == "left" || self.a.coverMode == "right" )
aimCoverMode = "crouch";
else
aimCoverMode = self.a.coverMode;
self setAnimKnobAll( animArray( aimCoverMode + "_aim" ), %body, 1, transTime );
if ( aimCoverMode == "crouch" )
{
self setanimlimited( %covercrouch_aim2_add, 1, 0 );
self setanimlimited( %covercrouch_aim4_add, 1, 0 );
self setanimlimited( %covercrouch_aim6_add, 1, 0 );
self setanimlimited( %covercrouch_aim8_add, 1, 0 );
}
else if ( aimCoverMode == "stand" )
{
self setanimlimited( %exposed_aim_2, 1, 0 );
self setanimlimited( %exposed_aim_4, 1, 0 );
self setanimlimited( %exposed_aim_6, 1, 0 );
self setanimlimited( %exposed_aim_8, 1, 0 );
}
else if ( aimCoverMode == "lean" )
{
self setanimlimited( %exposed_aim_2, 1, 0 );
self setanimlimited( %exposed_aim_4, 1, 0 );
self setanimlimited( %exposed_aim_6, 1, 0 );
self setanimlimited( %exposed_aim_8, 1, 0 );
// these don't seem to have 45 degree aiming limits,
// so i'm using the exposed ones instead
/*self setanimlimited(%covercrouch_lean_aim2_add,1,0);
self setanimlimited(%covercrouch_lean_aim4_add,1,0);
self setanimlimited(%covercrouch_lean_aim6_add,1,0);
self setanimlimited(%covercrouch_lean_aim8_add,1,0);*/
}
else if ( aimCoverMode == "over" )
{
self setanimlimited( %coverstandaim_aim2_add, 1, 0 );
self setanimlimited( %coverstandaim_aim4_add, 1, 0 );
self setanimlimited( %coverstandaim_aim6_add, 1, 0 );
self setanimlimited( %coverstandaim_aim8_add, 1, 0 );
}
}
go_to_hide()
{
self notify( "return_to_cover" );
self.changingCoverPos = true; self notify( "done_changing_cover_pos" );
self endAimIdleThread();
animRate = pop_up_and_hide_speed();
self setFlaggedAnimKnobAll( "go_to_hide", animArray( self.a.coverMode + "_2_hide" ), %body, 1, 0.2, animRate );
self clearAnim( %exposed_modern, 0.2 );
self animscripts\shared::DoNoteTracks( "go_to_hide" );
self.a.coverMode = "hide";
if ( self.coverType == "stand" )
self.a.special = "cover_stand";
else
self.a.special = "cover_crouch";
self.changingCoverPos = false;
}
tryThrowingGrenadeStayHidden( throwAt )
{
// TODO: check suppression and add rambo grenade support
return tryThrowingGrenade( throwAt, true );
}
tryThrowingGrenade( throwAt, safe )
{
if ( isdefined( self.dontEverShoot ) || isdefined( throwAt.dontAttackMe ) )
return false;
theanim = undefined;
if ( isdefined( self.ramboChance ) && randomfloat( 1.0 ) < self.ramboChance )
{
theanim = animArrayPickRandom( "grenade_rambo" );
}
else
{
if ( isdefined( safe ) && safe )
theanim = animArrayPickRandom( "grenade_safe" );
else
theanim = animArrayPickRandom( "grenade_exposed" );
}
self animMode( "zonly_physics" );// Unlatch the feet
self.keepClaimedNodeIfValid = true;
threwGrenade = TryGrenade( throwAt, theanim );
self.keepClaimedNodeIfValid = false;
return threwGrenade;
}
blindfire()
{
if ( !animArrayAnyExist( "blind_fire" ) )
return false;
self animMode( "zonly_physics" );
self.keepClaimedNodeIfValid = true;
self setFlaggedAnimKnobAllRestart( "blindfire", animArrayPickRandom( "blind_fire" ), %body, 1, 0.2, 1 );
self animscripts\shared::DoNoteTracks( "blindfire" );
self.keepClaimedNodeIfValid = false;
return true;
}
createTurret( posEnt, weaponInfo, weaponModel )
{
turret = spawnTurret( "misc_turret", posEnt.origin, weaponInfo );
turret.angles = posEnt.angles;
turret.aiOwner = self;
turret setModel( weaponModel );
turret makeUsable();
turret setDefaultDropPitch( 0 );
if ( isDefined( posEnt.leftArc ) )
turret.leftArc = posEnt.leftArc;
if ( isDefined( posEnt.rightArc ) )
turret.rightArc = posEnt.rightArc;
if ( isDefined( posEnt.topArc ) )
turret.topArc = posEnt.topArc;
if ( isDefined( posEnt.bottomArc ) )
turret.bottomArc = posEnt.bottomArc;
return turret;
}
deleteIfNotUsed( owner )
{
self endon( "death" );
self endon( "being_used" );
wait .1;
if ( isdefined( owner ) )
{
assert( !isdefined( owner.a.usingTurret ) || owner.a.usingTurret != self );
owner notify( "turret_use_failed" );
}
self delete();
}
useSelfPlacedTurret( weaponInfo, weaponModel )
{
turret = self createTurret( self.node.turretInfo, weaponInfo, weaponModel );
if ( self useTurret( turret ) )
{
turret thread deleteIfNotUsed( self );
if ( isdefined( self.turret_function ) )
thread [[ self.turret_function ]]( turret );
// self setAnimKnob( %cover, 0, 0 );
self waittill( "turret_use_failed" );// generally this won't notify, and we'll just not do any more cover_wall for now
}
else
{
turret delete();
}
}
useStationaryTurret()
{
assert( isdefined( self.node ) );
assert( isdefined( self.node.turret ) );
turret = self.node.turret;
if ( !turret.isSetup )
return;
// turret setmode( "auto_ai" ); // auto, auto_ai, manual, manual_ai
// turret startFiring(); // seems to be a bug with the turret being in manual mode to start with
// wait( 1 );
thread maps\_mg_penetration::gunner_think( turret );
self waittill( "continue_cover_script" );
// turret thread maps\_spawner::restorePitch();
// self useturret( turret ); // dude should be near the mg42
}
get_standing_wall_cover_anim()
{
if ( IsDefined( self.customStandWallAnims ) )
{
return self.customStandWallAnims;
}
else
{
return anim.animsets.standWallAnimSet;
}
}
get_crouching_wall_cover_anim()
{
if ( IsDefined( self.customCrouchWallAnims ) )
{
return self.customCrouchWallAnims;
}
else
{
return anim.animsets.crouchWallAnimSet;
}
}
setup_crouching_anim_array( exposedAnimSet )
{
anim_array = get_crouching_wall_cover_anim();
if ( weapon_pump_action_shotgun() )
{
if ( exposedAnimSet == "lean" || exposedAnimSet == "stand" )
anim_array[ "single" ] = anim_array[ "shotgun_lean_single" ];
else
anim_array[ "single" ] = anim_array[ "shotgun_over_single" ];
}
else
{
anim_array[ "single" ] = anim_array[ "normal_single" ];
}
if ( isDefined( anim.ramboAnims ) )
{
anim_array[ "rambo" ] = anim.ramboAnims.covercrouch;
anim_array[ "rambo_fail" ] = anim.ramboAnims.covercrouchfail;
anim_array[ "grenade_rambo" ] = anim.ramboAnims.covercrouchgrenade;
}
self.a.array = anim_array;
}
setup_standing_anim_array( exposedAnimSet )
{
anim_array = get_standing_wall_cover_anim();
if ( exposedAnimSet == "over" )
{
anim_array[ "fire" ] = anim_array[ "over_fire" ];
anim_array[ "semi2" ] = anim_array[ "over_semi2" ];
anim_array[ "semi3" ] = anim_array[ "over_semi3" ];
anim_array[ "semi4" ] = anim_array[ "over_semi4" ];
anim_array[ "semi5" ] = anim_array[ "over_semi5" ];
anim_array[ "single" ] = anim_array[ "over_single" ];
anim_array[ "burst2" ] = anim_array[ "over_burst2" ];
anim_array[ "burst3" ] = anim_array[ "over_burst3" ];
anim_array[ "burst4" ] = anim_array[ "over_burst4" ];
anim_array[ "burst5" ] = anim_array[ "over_burst5" ];
anim_array[ "burst6" ] = anim_array[ "over_burst6" ];
anim_array[ "continuous" ] = anim_array[ "over_continuous" ];
}
else
{
anim_array[ "fire" ] = anim_array[ "stand_fire" ];
anim_array[ "semi2" ] = anim_array[ "stand_semi2" ];
anim_array[ "semi3" ] = anim_array[ "stand_semi3" ];
anim_array[ "semi4" ] = anim_array[ "stand_semi4" ];
anim_array[ "semi5" ] = anim_array[ "stand_semi5" ];
if ( weapon_pump_action_shotgun() )
anim_array[ "single" ] = anim_array[ "stand_shotgun_single" ];
else
anim_array[ "single" ] = anim_array[ "stand_normal_single" ];
anim_array[ "burst2" ] = anim_array[ "stand_burst2" ];
anim_array[ "burst3" ] = anim_array[ "stand_burst3" ];
anim_array[ "burst4" ] = anim_array[ "stand_burst4" ];
anim_array[ "burst5" ] = anim_array[ "stand_burst5" ];
anim_array[ "burst6" ] = anim_array[ "stand_burst6" ];
anim_array[ "continuous" ] = anim_array[ "stand_continuous" ];
}
if ( isDefined( anim.ramboAnims ) )
{
anim_array[ "rambo" ] = anim.ramboAnims.coverstand;
anim_array[ "rambo_fail" ] = anim.ramboAnims.coverstandfail;
anim_array[ "grenade_rambo" ] = anim.ramboAnims.coverstandgrenade;
}
self.a.array = anim_array;
}
loopHide( transTime )
{
if ( !isdefined( transTime ) )
transTime = .1;
self setanimknoballrestart( animArray( "hide_idle" ), %body, 1, transTime );
self.a.coverMode = "hide";
}
angleRangeThread()
{
self endon( "killanimscript" );
self notify( "newAngleRangeCheck" );
self endon( "newAngleRangeCheck" );
self endon( "return_to_cover" );
while ( 1 )
{
if ( needToChangeCoverMode() )
break;
wait( 0.1 );
}
self notify( "stopShooting" );// For changing shooting pose to compensate for player moving
}
needToChangeCoverMode()
{
if ( self.coverType != "crouch" )
return false;
pitch = getShootPosPitch( self getEye() );
if ( self.a.coverMode == "lean" )
{
return pitch < 10;
}
else
{
return pitch > 45;
}
}
getBestCoverMode()
{
modes = [];
assert( isdefined( self.coverNode ) );
if ( isdefined( self.get_valid_peekout_func ) )
{
modes = self.coverNode [[ self.get_valid_peekout_func ]]();
}
else if ( self.coverType == "stand" )
{
modes = self.coverNode GetValidCoverPeekOuts();
modes[ modes.size ] = "stand";
}
else
{
pitch = getShootPosPitch( self.coverNode.origin + getNodeOffset( self.coverNode ) );
if ( pitch > 30 )
return "lean";
if ( pitch > 15 || !self.coverNode.crouchingIsOK )
return "stand";
modes = self.coverNode GetValidCoverPeekOuts();
modes[ modes.size ] = "crouch";
}
return getRandomCoverMode( modes );
}
getShootPosPitch( fromPos )
{
shootPos = getEnemyEyePos();
return AngleClamp180( vectorToAngles( shootPos - fromPos )[ 0 ] );
}

304
animscripts/cqb.gsc Normal file
View File

@ -0,0 +1,304 @@
#include animscripts\utility;
#include animscripts\combat_utility;
#include animscripts\shared;
#include common_scripts\utility;
#using_animtree( "generic_human" );
MoveCQB()
{
animscripts\run::changeWeaponStandRun();
// any endons in this function must also be in CQBShootWhileMoving and CQBDecideWhatAndHowToShoot
if ( self.a.pose != "stand" )
{
// (get rid of any prone or other stuff that might be going on)
self clearAnim( %root, 0.2 );
if ( self.a.pose == "prone" )
self ExitProneWrapper( 1 );
self.a.pose = "stand";
}
self.a.movement = self.moveMode;
//self clearanim(%combatrun, 0.2);
self thread CQBTracking();
cqbWalkAnim = DetermineCQBAnim();
rate = self.moveplaybackrate;
if ( self.moveMode == "walk" )
rate *= 0.6;
transTime = get_cqb_blend_in_time();
// (we don't use %body because that would reset the aiming knobs)
self setFlaggedAnimKnobAll( "runanim", cqbWalkAnim, %walk_and_run_loops, 1, transTime, rate, true );
self set_move_anim_start_point();
self animscripts\run::SetMoveNonForwardAnims( GetCQBAnim("move_b"), GetCQBAnim("move_l"), GetCQBAnim("move_r") );
self thread animscripts\run::SetCombatStandMoveAnimWeights( "cqb" );
animscripts\shared::DoNoteTracksForTime( 0.2, "runanim" );
self thread animscripts\run::stopShootWhileMovingThreads();
}
DetermineCQBAnim()
{
//TagCC<NOTE>: This is rather fail. the self.MoveMode that GetRunAnim uses is used to set the anim are always run
//so effectively this line says that if a custom cqb animset is defined, don't use it, or even the normal cqb anims,
//but instead use the run anim set. Great. No one noticed this bug because cqb isn't ever overridden where run isn't
//also overriden to the same thing in mw2 (see riotshield).
//if ( isdefined( self.customMoveAnimSet ) && isdefined( self.customMoveAnimSet[ "cqb" ] ) )
// return animscripts\run::GetRunAnim();
if ( self.stairsState == "up" )
{
return GetCQBAnim( "stairs_up" );
}
if ( self.stairsState == "down" )
{
return GetCQBAnim( "stairs_down" );
}
if ( self.movemode == "walk" )
{
return GetCQBAnim( "move_f" );
}
variation = getRandomIntFromSeed( self.a.runLoopCount, 2 );
if ( variation == 0 )
{
return GetCQBAnim( "straight" );
}
return GetCQBAnim( "straight_variation" );
}
get_cqb_blend_in_time()
{
transTime = 0.1;
if ( self.stairsState == "none" )
{
transTime = 0.3;
//tagCC<NOTE>:for debugging, lets allow for this to be tweaked in script. remove at some point.
if( self.subclass == "moon" )
{
transTime = 0.8;
if( IsDefined( self.cqb_blend_finish_time ) )
{
transTime = self.cqb_blend_finish_time;
self.cqb_blend_finish_time = undefined;
}
run_blend_str = GetDvar("scr_run_blend");
if( run_blend_str != "" )
{
transTime = Float( run_blend_str );
}
}
}
else
{
transTime = 0.1; // need to transition to stairs quickly
}
return transTime;
}
GetCQBAnim( anim_name )
{
if ( IsDefined( self.customMoveAnimSet ) && IsDefined( self.customMoveAnimSet[ "cqb" ] ) && IsDefined( self.customMoveAnimSet[ "cqb" ][anim_name] ) )
{
return self.customMoveAnimSet[ "cqb" ][ anim_name ];
}
else
{
return anim.animsets.move[ "cqb" ][ anim_name ];
}
}
CQBTracking()
{
assert( isdefined( self.aim_while_moving_thread ) == isdefined( self.trackLoopThread ) );
assertex( !isdefined( self.trackLoopThread ) || (self.trackLoopThreadType == "faceEnemyAimTracking"), self.trackLoopThreadType );
if ( animscripts\move::MayShootWhileMoving() )
animscripts\run::runShootWhileMovingThreads();
animscripts\run::faceEnemyAimTracking();
}
setupCQBPointsOfInterest()
{
level._cqbPointsOfInterest = [];
pointents = getEntArray( "cqb_point_of_interest", "targetname" );
for ( i = 0; i < pointents.size; i++ )
{
level._cqbPointsOfInterest[ i ] = pointents[ i ].origin;
pointents[ i ] delete();
}
}
findCQBPointsOfInterest()
{
if ( isdefined( anim.findingCQBPointsOfInterest ) )
return;
anim.findingCQBPointsOfInterest = true;
// one AI per frame, find best point of interest.
if ( !level._cqbPointsOfInterest.size )
return;
while ( 1 )
{
ai = getaiarray();
waited = false;
foreach( guy in ai )
{
if ( isAlive( guy ) && guy isCQBWalking() )
{
moving = ( guy.a.movement != "stop" );
// if you change this, change the debug function below too
shootAtPos = (guy.origin[0], guy.origin[1], guy getShootAtPos()[2]);
lookAheadPoint = shootAtPos;
forward = anglesToForward( guy.angles );
if ( moving )
{
trace = bulletTrace( lookAheadPoint, lookAheadPoint + forward * 128, false, undefined );
lookAheadPoint = trace[ "position" ];
}
best = -1;
bestdist = 1024 * 1024;
for ( j = 0; j < level._cqbPointsOfInterest.size; j++ )
{
point = level._cqbPointsOfInterest[ j ];
dist = distanceSquared( point, lookAheadPoint );
if ( dist < bestdist )
{
if ( moving )
{
if ( distanceSquared( point, shootAtPos ) < 64 * 64 )
continue;
dot = vectorDot( vectorNormalize( point - shootAtPos ), forward );
if ( dot < 0.643 || dot > 0.966 )// 0.643 = cos( 50 ), 0.966 = cos( 15 )
continue;
}
else
{
if ( dist < 50 * 50 )
continue;
}
if ( !sightTracePassed( lookAheadPoint, point, false, undefined ) )
continue;
bestdist = dist;
best = j;
}
}
if ( best < 0 )
guy.cqb_point_of_interest = undefined;
else
guy.cqb_point_of_interest = level._cqbPointsOfInterest[ best ];
wait .05;
waited = true;
}
}
if ( !waited )
wait .25;
}
}
/#
CQBDebug()
{
self notify( "end_cqb_debug" );
self endon( "end_cqb_debug" );
self endon( "death" );
setDvarIfUninitialized( "scr_cqbdebug", "off" );
level thread CQBDebugGlobal();
while ( 1 )
{
if ( getdebugdvar( "scr_cqbdebug" ) == "on" || getdebugdvarint( "scr_cqbdebug" ) == self getentnum() )
{
shootAtPos = (self.origin[0], self.origin[1], self getShootAtPos()[2]);
if ( isdefined( self.shootPos ) )
{
line( shootAtPos, self.shootPos, ( 1, 1, 1 ) );
print3d( self.shootPos, "shootPos", ( 1, 1, 1 ), 1, 0.5 );
}
else if ( isdefined( self.cqb_target ) )
{
line( shootAtPos, self.cqb_target.origin, ( .5, 1, .5 ) );
print3d( self.cqb_target.origin, "cqb_target", ( .5, 1, .5 ), 1, 0.5 );
}
else
{
moving = ( self.a.movement != "stop" );
forward = anglesToForward( self.angles );
lookAheadPoint = shootAtPos;
if ( moving )
{
lookAheadPoint += forward * 128;
line( shootAtPos, lookAheadPoint, ( 0.7, .5, .5 ) );
right = anglesToRight( self.angles );
leftScanArea = shootAtPos + ( forward * 0.643 - right ) * 64;
rightScanArea = shootAtPos + ( forward * 0.643 + right ) * 64;
line( shootAtPos, leftScanArea, ( 0.5, 0.5, 0.5 ), 0.7 );
line( shootAtPos, rightScanArea, ( 0.5, 0.5, 0.5 ), 0.7 );
}
if ( isdefined( self.cqb_point_of_interest ) )
{
line( lookAheadPoint, self.cqb_point_of_interest, ( 1, .5, .5 ) );
print3d( self.cqb_point_of_interest, "cqb_point_of_interest", ( 1, .5, .5 ), 1, 0.5 );
}
}
wait .05;
continue;
}
wait 1;
}
}
CQBDebugGlobal()
{
if ( isdefined( level._cqbdebugglobal ) )
return;
level._cqbdebugglobal = true;
while ( 1 )
{
if ( getdebugdvar( "scr_cqbdebug" ) != "on" )
{
wait 1;
continue;
}
for ( i = 0; i < level._cqbPointsOfInterest.size; i++ )
{
print3d( level._cqbPointsOfInterest[ i ], ".", ( .7, .7, 1 ), .7, 3 );
}
wait .05;
}
}
#/

36
animscripts/custom.gsc Normal file
View File

@ -0,0 +1,36 @@
#include animscripts\Combat_utility;
#include animscripts\Utility;
#include common_scripts\Utility;
// Note that this script is called from the level script command animscripted, only for AI. If animscripted
// is done on a script model, this script is not called - startscriptedanim is called directly.
#using_animtree( "generic_human" );
main()
{
//thread [[anim.println]]("Entering animscripts\\scripted. anim: ",self.codeScripted["anim"],", notify: ",self.codeScripted["notifyName"],", dialogue: ",self.scripted_dialogue,", facial: ",self.facial_animation, "root: ", self.codeScripted["root"]);#/
self endon( "death" );
// wait (0);
self notify( "killanimscript" );
self notify( "clearSuppressionAttack" );
self.a.suppressingEnemy = false;
self.codeScripted[ "root" ] = %body; // TEMP!
self endon( "end_sequence" );
// Causes potential variable overflow in Stalingrad
// self thread DebugPrintEndSequence();
animation = %sprint_loop_distant; // Hardcoded default
if ( isdefined( self.node.script_animation ) )
{
animation = self.node.script_animation;
}
self setFlaggedAnimRestart( "custom", animation, 1, .1, 1.0 );
wait( 5.0 );
self lookForBetterCover();
}

1773
animscripts/death.gsc Normal file

File diff suppressed because it is too large Load Diff

302
animscripts/door.gsc Normal file
View File

@ -0,0 +1,302 @@
#include animscripts\combat_utility;
#include animscripts\utility;
#include animscripts\shared;
#include common_scripts\utility;
#include maps\_utility;
#using_animtree( "generic_human" );
doorGrenadeInterval = 5000;
maxDistDoorToEnemySq = 600 * 600;
doorEnterExitCheck()
{
self endon( "killanimscript" );
if ( isdefined( self.disableDoorBehavior ) )
return;
while ( 1 )
{
doorNode = self getDoorPathNode();
if ( isdefined( doorNode ) )
break;
wait 0.2;
}
goingInDoor = ( doorNode.type == "Door Interior" ) || self compareNodeDirToPathDir( doorNode );
if ( goingInDoor )
self doorEnter( doorNode );
else
self doorExit( doorNode );
// waittill doorNode changes
while ( 1 )
{
newDoorNode = self getDoorPathNode();
if ( !isdefined( newDoorNode ) || newDoorNode != doorNode )
break;
wait 0.2;
}
self thread doorEnterExitCheck();
}
teamFlashBangImmune()
{
self endon( "killanimscript" );
self.teamFlashbangImmunity = true;
wait 5;
self.teamFlashbangImmunity = undefined;
}
doDoorGrenadeThrow( node )
{
self thread teamFlashBangImmune();
if ( self.grenadeWeapon == "flash_grenade" )
self notify( "flashbang_thrown" );
self OrientMode( "face current" );
node.nextDoorGrenadeTime = gettime() + doorGrenadeInterval;
self.minInDoorTime = gettime() + 100000; // hack to not forget going indoor
self notify( "move_interrupt" );
self.update_move_anim_type = undefined;
self clearanim( %combatrun, 0.2 );
self.a.movement = "stop";
self waittill( "done_grenade_throw" );
self OrientMode( "face default" );
self.minInDoorTime = gettime() + 5000;
self.grenadeWeapon = self.oldGrenadeWeapon;
self.oldGrenadeWeapon = undefined;
self animscripts\run::endFaceEnemyAimTracking();
self thread animscripts\move::pathChangeCheck();
self thread animscripts\move::restartMoveLoop( true );
}
// try throwing grenade before entering door
doorEnter_TryGrenade( node, grenadeType, ricochet, minDistSq, checkInterval )
{
safeCheckDone = false;
throwAttempts = 3;
throwAnim = undefined;
throwAnim = %CQB_stand_grenade_throw;
doorForward = anglesToForward( node.angles );
if ( node.type == "Door Interior" && !( self compareNodeDirToPathDir( node ) ) )
doorForward = -1 * doorForward;
doorPos = ( node.origin[ 0 ], node.origin[ 1 ], node.origin[ 2 ] + 64 );
throwPos = doorPos;
if ( ricochet )
{
doorPlane = AnglesToRight( node.angles );
dirToDoor = node.origin - self.origin;
// upto 20 units to left or right of door depending on direction to door to make it likely to bounce off door edge
projLength = vectordot( doorPlane, dirToDoor );
if ( projLength > 20 )
projLength = 20;
else if ( projLength < - 20 )
projLength = -20;
throwPos = doorPos + projLength * doorPlane;
}
while ( throwAttempts > 0 )
{
if ( isdefined( self.grenade ) || !isdefined( self.enemy ) )
return;
if ( onSameSideOfDoor( node, doorForward ) )
return;
if ( !self seeRecently( self.enemy, 0.2 ) && self.a.pose == "stand" && distance2DAndHeightCheck( self.enemy.origin - node.origin, maxDistDoorToEnemySq, 128 * 128 ) )
{
if ( isdefined( node.nextDoorGrenadeTime ) && node.nextDoorGrenadeTime > gettime() )
return;
if ( self canShootEnemy() )
return;
// too close to door
dirToDoor = node.origin - self.origin;
if ( lengthSquared( dirToDoor ) < minDistSq )
return;
// don't throw backwards
if ( vectordot( dirToDoor, doorForward ) < 0 )
return;
self.oldGrenadeWeapon = self.grenadeWeapon;
self.grenadeWeapon = grenadeType;
self setActiveGrenadeTimer( self.enemy );
if ( !safeCheckDone )
{
checkPos = doorPos + ( doorForward * 100 );
if ( !( self isGrenadePosSafe( self.enemy, checkPos, 128 ) ) )
return;
}
safeCheckDone = true; // do this only once but do isGrenadePosSafe as late as possible
if ( TryGrenadeThrow( self.enemy, throwPos, throwAnim, getGrenadeThrowOffset( throwAnim ), true, false, true ) )
{
self doDoorGrenadeThrow( node );
return;
}
}
throwAttempts -- ;
wait checkInterval;
// check if door node has past
newNode = self getDoorPathNode();
if ( !isdefined( newNode ) || newNode != node )
return;
}
}
inDoorCqbToggleCheck()
{
self endon( "killanimscript" );
if ( isdefined( self.disableDoorBehavior ) )
return;
self.isInDoor = false;
while ( 1 )
{
if ( self isInDoor() && !self.doingAmbush )
{
doorEnter_enable_cqbwalk();
}
else if ( !isdefined( self.minInDoorTime ) || self.minInDoorTime < gettime() )
{
self.minInDoorTime = undefined;
doorExit_disable_cqbwalk();
}
wait 0.2;
}
}
// substitute for enable_cqbwalk so LD can always disable cqb
doorEnter_enable_cqbwalk()
{
if ( !isdefined( self.neverEnableCQB ) && !self.doingAmbush )
{
self.isInDoor = true;
if ( !isdefined( self.cqbWalking ) || !self.cqbWalking )
enable_cqbwalk( true );
}
}
// substitute for disable_cqbwalk so LD can force CQB even after exiting to outdoor
doorExit_disable_cqbwalk()
{
if ( !isdefined( self.cqbEnabled ) )
{
self.isInDoor = false;
if ( isdefined( self.cqbWalking ) && self.cqbWalking )
disable_cqbwalk();
}
}
maxFragDistSq = 750 * 750;
minFragDistSq = 550 * 550;
maxFlashDistSq = 192 * 192;
minFlashDistSq = 64 * 64;
maxFragHeightDiffSq = 160 * 160;
maxFlashHeightDiffSq = 80 * 80;
distance2DAndHeightCheck( vec, dist2DSq, heightSq )
{
return( ( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] ) < dist2DSq ) && ( ( vec[ 2 ] * vec[ 2 ] ) < heightSq );
}
onSameSideOfDoor( node, doorForward )
{
assert( isdefined( self.enemy ) );
selfToDoor = node.origin - self.origin;
enemyToDoor = node.origin - self.enemy.origin;
return( vectordot( selfToDoor, doorForward ) * vectordot( enemyToDoor, doorForward ) > 0 );
}
doorEnter( node )
{
// try frag
while ( 1 )
{
if ( isdefined( self.doorFragChance ) && ( self.doorFragChance == 0 || self.doorFragChance < randomfloat( 1 ) ) )
break;
if ( distance2DAndHeightCheck( self.origin - node.origin, maxFragDistSq, maxFragHeightDiffSq ) )
{
self doorEnter_TryGrenade( node, "fraggrenade", false, minFragDistSq, 0.3 );
node = self getDoorPathNode();
if ( !isdefined( node ) )
return;
break;
}
wait 0.1;
}
// try flashbang
while ( 1 )
{
if ( distance2DAndHeightCheck( self.origin - node.origin, maxFlashDistSq, maxFlashHeightDiffSq ) )
{
self doorEnter_enable_cqbwalk();
self.minInDoorTime = gettime() + 6000;
if ( isdefined( self.doorFlashChance ) && ( self.doorFlashChance == 0 || self.doorFlashChance < randomfloat( 1 ) ) )
return;
self doorEnter_TryGrenade( node, "flash_grenade", true, minFlashDistSq, 0.2 );
return;
}
wait 0.1;
}
}
doorExit( node )
{
while ( 1 )
{
if ( !self.isInDoor || distanceSquared( self.origin, node.origin ) < 32 * 32 )
{
//self doorExit_disable_cqbwalk();
return;
}
wait 0.1;
}
}

View File

@ -0,0 +1,75 @@
#include maps\_utility;
#include common_scripts\utility;
#using_animtree( "generic_human" );
// self = the guy using the turret
main()
{
turret = self getTurret();
self.desired_anim_pose = "stand";
animscripts\utility::UpdateAnimPose();
// .primaryTurretAnim is used by code so don't change this variable name
self.primaryTurretAnim = %LGVGunner_aim;
self.additiveTurretRotateLeft = %nx_tp_chinese_lgv_gunner_aim_2_add;
self.additiveTurretRotateRight = %nx_tp_chinese_lgv_gunner_aim_4_add;
self.additiveRotateRoot = %additive_LGVGunner_aim_leftright;
self.additiveTurretIdle = %nx_tp_chinese_lgv_gunner_idle;
self.additiveTurretDriveIdle = %nx_tp_chinese_lgv_gunner_driveidle;
self.additiveTurretFire = %nx_tp_chinese_lgv_gunner_fire;
self.additiveUsegunRoot = %additive_LGVGunner_usegun;
self.turretDeathAnimRoot = %LGVGunner_death;
self.turretDeathAnim = %nx_tp_chinese_lgv_gunner_death;
self.turretPainAnims[ 0 ] = %nx_tp_chinese_lgv_gunner_pain;
self.turretReloadAnim = %nx_tp_chinese_lgv_gunner_rechamber;
self.turretSpecialAnimsRoot = %LGVGunner;
arr = [];
arr[ "nx_tp_chinese_lgv_gunner_rechamber" ] = %nx_tp_chinese_lgv_gunner_rechamber;
self.turretSpecialAnims = arr;
turret setup_turret_anims();
self thread animscripts\hummer_turret\minigun_code::main( turret );
// Setting verious parameters for LGV turret after minigun_code::main, which sets it to hummer values.
shots_per_second = turret GetTurretShotsPerSecondAI();
if ( shots_per_second > 0.0 )
{
turret.fireInterval = 1.0 / shots_per_second;
}
turret.secsOfFiringBeforeReload = 15.0;
turret.reloadDuration = 2.17;
turret.centerTurretForReload = true;
turret.extraFireTime_min = 0;
turret.extraFireTime_max = 1;
turret.wait_duration_after_aiming_before_firing = 0.2;
turret thread reload_fx();
}
#using_animtree( "vehicles" );
setup_turret_anims()
{
self UseAnimTree( #animtree );
self.passenger2turret_anime = %nx_vh_chinese_lgv_gunner_mount_turret;
self.turret2passenger_anime = %nx_vh_chinese_lgv_gunner_getout_turret;
}
reload_fx()
{
for (;;)
{
self waittill( "starting_reload" );
playFXOnTag( level._effect[ "nx_chinese_lgv_turret_steam" ], self, "tag_origin" );
playFXOnTag( level._effect[ "nx_chinese_lgv_turret_steam_muzzle" ], self, "tag_flash" );
}
}

522
animscripts/face.gsc Normal file
View File

@ -0,0 +1,522 @@
// face.gsc
// Supposed to handle all facial and dialogue animations from regular scripts.
//#using_animtree ("generic_human"); - This file doesn't call animations directly.
InitCharacterFace()
{
if ( !anim.useFacialAnims )
return;
// Does any per-character initialization which is required by this facial animation script.
// InitLevelFace must be called before this function.
if ( !isDefined( self.a.currentDialogImportance ) )
{
self.a.currentDialogImportance = 0; // Indicates that we are not currently saying anything.
self.a.idleFace = anim.alertface;
self.faceWaiting = [];
self.faceLastNotifyNum = 0;
}
}
// Makes a character say the specified line in his voice, if he's not already saying something more
// important.
SayGenericDialogue( typeString )
{
// First pick a random voice number for our character. We have to do this every time because it's
// possible for the character to be changed after the level loads (generally right before it starts).
// Use (entity number) modulus (number of voices) to get a consistent result.
if ( ( self.voice == "multilingual" ) || ( self.voice == "italian" ) || ( self.voice == "german" ) || ( self.voice == "spanish" ) )
voiceString = "russian";
else
voiceString = self.voice;
ASSERT( isDefined( voiceString ) );
voicenum = undefined;
numVoices = undefined;
switch( voiceString )
{
case "american":
numVoices = anim.numAmericanVoices;
break;
case "seal":
voiceString = "navyseal"; // soundaliases use the string "navyseal" (not "seal")
numVoices = anim.numNavySealVoices;
break;
case "taskforce":
numVoices = anim.numTaskForceVoices;
break;
case "secretservice":
numVoices = anim.numSecretServiceVoices;
break;
case "british":
numVoices = anim.numBritishVoices;
break;
case "russian":
numVoices = anim.numRussianVoices;
break;
case "arab":
numVoices = anim.numArabVoices;
break;
case "portuguese":
numVoices = anim.numPortugueseVoices;
break;
case "shadowcompany":
numVoices = anim.numShadowCompanyVoices;
break;
case "jswc":
numVoices = anim.numJSWCVoices;
break;
case "usop":
numVoices = anim.numUSOPVoices;
break;
case "indonesian":
voiceString = "indonesian";
numVoices = anim.numIndonesianVoices;
case "mexican":
//voiceString = "mexican"; //temporarily using arab vo in sound_generic.csv
numVoices = anim.numIndonesianVoices;
break;
}
ASSERT( IsDefined( numVoices ) );
voicenum = 1 + ( self GetEntityNumber() % numVoices );
ASSERT( IsDefined( voicenum ) );
voiceString = voiceString + "_" + voicenum;
faceAnim = undefined;
switch( typeString )
{
case "meleecharge":
case "meleeattack":
// faceAnim = animscripts\face::ChooseAnimFromSet(anim.meleeFace);
importance = 0.5;
break;
case "flashbang":
// faceAnim = animscripts\face::ChooseAnimFromSet(anim.painFace);
importance = 0.7;
break;
case "pain":
// faceAnim = animscripts\face::ChooseAnimFromSet(anim.painFace);
importance = 0.9;
break;
case "death":
// faceAnim = animscripts\face::ChooseAnimFromSet(anim.deathFace);
importance = 1.0;
break;
default:
println( "Unexpected generic dialog string: " + typeString );
importance = 0.3;
break;
}
// Now assemble the sound alias and try to play it.
soundAlias = "generic_" + typeString + "_" + voiceString;
// Note that faceAnim is allowed to be undefined.
self thread PlayFaceThread( faceAnim, soundAlias, importance );
}
SetIdleFaceDelayed( facialAnimationArray )
{
self animscripts\battleChatter::playBattleChatter();
self.a.idleFace = facialAnimationArray;
}
// Sets the facial expression to return to when not saying dialogue.
// The array is animation1, weight1, animation2, weight2, etc. The animations will play in turn - each time
// one finishes a new one will be chosen randomly based on weight.
SetIdleFace( facialAnimationArray )
{
if ( !anim.useFacialAnims )
return;
self animscripts\battleChatter::playBattleChatter();
self.a.idleFace = facialAnimationArray;
self PlayIdleFace();
}
// Makes the character play the specified sound and animation. The anim and the sound are optional - you
// can just defined one if you don't have both.
// Generally, importance should be in the range of 0.6-0.8 for scripted dialogue.
// Importance is a float, from 0 to 1.
// 0.0 - Idle expressions
// 0.1-0.5 - most generic dialogue
// 0.6-0.8 - most scripted dialogue
// 0.9 - pain
// 1.0 - death
// Importance can also be one of these strings: "any", "pain" or "death", which specfies what sounds can
// interrupt this one.
SaySpecificDialogue( facialanim, soundAlias, importance, notifyString, waitOrNot, timeToWait )
{
///("SaySpecificDialog, facial: ",facialanim,", sound: ",soundAlias,", importance: "+importance+", notify: ",notifyString, ", WaitOrNot: ", waitOrNot, ", timeToWait: ", timeToWait);#/
self thread PlayFaceThread( facialanim, soundAlias, importance, notifyString, waitOrNot, timeToWait );
}
// Takes an array with a set of "anim" entries and a corresponding set of "weight" entries.
ChooseAnimFromSet( animSet )
{
return; // Facial animations are now part of full body aniamtions
/*
if (!anim.useFacialAnims)
return;
// First, normalize the weights.
totalWeight = 0;
numAnims = animSet["anim"].size;
for ( i=0 ; i<numAnims ; i++ )
{
totalWeight += animSet["weight"][i];
}
for ( i=0 ; i<numAnims ; i++ )
{
animSet["weight"][i] = animSet["weight"][i] / totalWeight;
}
// Now choose an animation.
rand = randomfloat(1);
runningTotal = 0;
chosenAnim = undefined;
for ( i=0 ; i<numAnims ; i++ )
{
runningTotal += animSet["weight"][i];
if (runningTotal >= rand)
{
chosenAnim = i;
break;
}
}
assertEX(isDefined(chosenAnim), "Logic error in ChooseAnimFromSet. Rand is " + rand + ".");
return animSet["anim"][chosenAnim];
*/
}
//-----------------------------------------------------
// Housekeeping functions - these are for internal use
//-----------------------------------------------------
// PlayIdleFace doesn't force an idle animation to play - it will interrupt a current idle animation, but it
// won't play over a more important animation, like dialogue.
PlayIdleFace()
{
return; // Idle facial animations are now in the full - body animations.
}
// PlayFaceThread is the workhorse of the system - it checks the importance, and if it's high enough, it
// plays the animation and/or sound specified.
// The waitOrNot parameter specifies what to do if another animation/sound is already playing.
// Options: "wait" or undefined. TimeToWait is an optional timeout time for waiting.
// Waiting faces are queued.
PlayFaceThread( facialanim, soundAlias, importance, notifyString, waitOrNot, timeToWait )
{
self.a.facialAnimDone = true;
self.a.facialSoundDone = true;
if ( isdefined( notifyString ) )
{
if ( isDefined( soundAlias ) )
{
self playsound( soundAlias, "animscript facesound" + notifyString, true );
// so placefacethread doesnt block
self thread WaitForFaceSound( notifyString );
}
}
else
self playsound( soundAlias );
if ( !anim.useFacialAnims )
return;
InitCharacterFace();
if ( !isDefined( facialanim ) && !isDefined( soundAlias ) )
{
// This is not actually an error condition but it might mess up the calling script, so better to catch it now.
assertEX( 0, "Either facialanim or soundAlias should be defined when calling PlayFaceThread or SaySpecificDialogue" );
if ( isDefined( notifyString ) )
{
wait( 0 ); // This allows the calling script to get to a point where it's waiting for the notify
self.faceResult = "failed";
self notify( notifyString );
}
return;
}
self endon( "death" );
if ( isString( importance ) )
{
switch( importance )
{
case "any":
importance = 0.1;
break;
case "pain":
importance = 0.9;
break;
case "death":
importance = 1.0;
break;
}
}
if ( ( importance <= self.a.currentDialogImportance ) && ( isDefined( waitOrNot ) && ( waitOrNot == "wait" ) ) )
{
//("Face: Waiting to play sound: ",soundAlias,", anim: ",facialanim,", ", notifyString,(", importance "+importance+", old one "+self.a.currentDialogImportance));#/
// Put this face at the end of the queue
thisEntryNum = self.faceWaiting.size;
thisNotifyNum = self.faceLastNotifyNum + 1;
self.faceWaiting[ thisEntryNum ][ "facialanim" ] = facialanim;
self.faceWaiting[ thisEntryNum ][ "soundAlias" ] = soundAlias;
self.faceWaiting[ thisEntryNum ][ "importance" ] = importance;
self.faceWaiting[ thisEntryNum ][ "notifyString" ] = notifyString;
self.faceWaiting[ thisEntryNum ][ "waitOrNot" ] = waitOrNot;
self.faceWaiting[ thisEntryNum ][ "timeToWait" ] = timeToWait;
self.faceWaiting[ thisEntryNum ][ "notifyNum" ] = thisNotifyNum; // Unique identifier.
// What we do now is, wait for both the notify and the time. If the time expires first, we give
// up and remove this entry from the queue. If the notify happens first, we stop waiting for the
// time and we play the face.
self thread PlayFace_WaitForNotify( ( "animscript face stop waiting " + self.faceWaiting[ thisEntryNum ][ "notifyNum" ] ), "Face done waiting", "Face done waiting" );
if ( isDefined( timeToWait ) )
self thread PlayFace_WaitForTime( timeToWait, "Face done waiting", "Face done waiting" );
self waittill( "Face done waiting" );
// First, find the entry, since it may have been moved.
thisEntryNum = undefined;
for ( i = 0 ; i < self.faceWaiting.size ; i++ )
{
if ( self.faceWaiting[ i ][ "notifyNum" ] == thisNotifyNum )
{
thisEntryNum = i;
break;
}
}
assertEX( isDefined( thisEntryNum ) );
if ( self.a.faceWaitForResult == "notify" )
{
// Play the face.
PlayFaceThread( self.faceWaiting[ thisEntryNum ][ "facialanim" ],
self.faceWaiting[ thisEntryNum ][ "soundAlias" ],
self.faceWaiting[ thisEntryNum ][ "importance" ],
self.faceWaiting[ thisEntryNum ][ "notifyString" ]
);
}
else // ie We timed out.
{
if ( isDefined( notifyString ) )
{
self.faceResult = "failed";
self notify( notifyString );
}
}
// Remove this entry from the queue. If any entries have been added after this one, move them
// forward.
for ( i = thisEntryNum + 1 ; i < self.faceWaiting.size ; i++ )
{
self.faceWaiting[ i - 1 ][ "facialanim" ] = self.faceWaiting[ i ][ "facialanim" ];
self.faceWaiting[ i - 1 ][ "soundAlias" ] = self.faceWaiting[ i ][ "soundAlias" ];
self.faceWaiting[ i - 1 ][ "importance" ] = self.faceWaiting[ i ][ "importance" ];
self.faceWaiting[ i - 1 ][ "notifyString" ] = self.faceWaiting[ i ][ "notifyString" ];
self.faceWaiting[ i - 1 ][ "waitOrNot" ] = self.faceWaiting[ i ][ "waitOrNot" ];
self.faceWaiting[ i - 1 ][ "timeToWait" ] = self.faceWaiting[ i ][ "timeToWait" ];
self.faceWaiting[ i - 1 ][ "notifyNum" ] = self.faceWaiting[ i ][ "notifyNum" ];
}
self.faceWaiting[ self.faceWaiting.size - 1 ] = undefined;
}
else if ( importance >= self.a.currentDialogImportance )
{
// End any threads that are waiting on current facial animations or sounds.
self notify( "end current face" );
self endon( "end current face" );
//("Face: Playing facial sound/animation: ", facialanim, ", ",soundAlias,", ",notifyString, ", ",importance);#/
//if (self.a.currentDialogImportance > 0)
//{
//("Face: Interrupted facial sound/animation: ",self.a.currentDialogSound,", ",self.a.currentDialogNotifyString, ", ",self.a.currentDialogImportance);#/
//}
if ( isDefined( notifyString ) )
{
if ( isDefined( self.a.currentDialogNotifyString ) )
{
self.faceResult = "interrupted";
self notify( self.a.currentDialogNotifyString );
}
}
// Remember what we're doing, so we can decide what to do if another face tries to interrupt this one.
self.a.currentDialogImportance = importance;
self.a.currentDialogSound = soundAlias; // ( This one is only used for debugging. )
self.a.currentDialogNotifyString = notifyString;
// Set finished to true so that if we don't play one of these, we don't have to wait for it to finish.
self.a.facialAnimDone = true;
self.a.facialSoundDone = true;
// Play the anim and sound, if they are defined.
if ( isDefined( facialanim ) )
{
// self setanim(%facial, 0.01, .1, 1); // This doesn't work for non-AI
self setflaggedanimknobrestart( "animscript faceanim", facialanim, 1, .1, 1 );
self.a.facialAnimDone = false;
self thread WaitForFacialAnim();
//("Face: Waiting for facial animation ", facialanim);#/
}
//else TODO play a generic, looping facial animation.
if ( isDefined( soundAlias ) )
{
// TEMP These lines break sound for most lines because of a bug in facial animation (code bug?). When that
// bug is fixed, put these lines back in.
// if ( isDefined(facialanim) && animhasnotetrack(facialanim, "dialogue"))
// {
// self waittillmatch ("animscript faceanim", "dialogue");
// }
self playsound( soundAlias, "animscript facesound", true );
self.a.facialSoundDone = false;
self thread WaitForFaceSound();
//("Face: Waiting for sound ",soundAlias);#/
}
// Now wait until both animation and sound are finished
while ( ( !self.a.facialAnimDone ) || ( !self.a.facialSoundDone ) )
{
self waittill( "animscript facedone" );
}
// Set importance to 0 so that other facial anims (like the idle) can play.
//("Face: Finished facial sound: ",soundAlias,", animation: ",facialanim," notify: ",notifyString,", importance ",importance);#/
self.a.currentDialogImportance = 0;
self.a.currentDialogSound = undefined;
self.a.currentDialogNotifyString = undefined;
if ( isDefined( notifyString ) )
{
self.faceResult = "finished";
self notify( notifyString );
}
if ( isDefined( self.faceWaiting ) && ( self.faceWaiting.size > 0 ) )
{
// Find out which face we want to play next. Look through the queue for the highest priority
// face. If we find more than one with the same importance, choose the one that was added first.
maxImportance = 0;
nextFaceNum = 1;
//("Choosing next face. List is:");#/
for ( i = 0 ; i < self.faceWaiting.size ; i++ )
{
/*
println]](" ",i," ", (self.faceWaiting[i]["facialanim"]),", ",
(self.faceWaiting[i]["soundAlias"]),", ",
(self.faceWaiting[i]["importance"]),", ",
(self.faceWaiting[i]["notifyString"])
);#/
*/
if ( self.faceWaiting[ i ][ "importance" ] > maxImportance )
{
maxImportance = self.faceWaiting[ i ][ "importance" ];
nextFaceNum = i;
}
}
//("Chose ", nextFaceNum);#/
// Notify the entry in the queue, to play.
self notify( "animscript face stop waiting " + self.faceWaiting[ nextFaceNum ][ "notifyNum" ] );
}
else
{
// We're done. Set an idle face going before we exit.
// TODO Make the idle face play whenever the animation finishes, for cases when it finishes before the sound.
if ( IsAI( self ) )
{
self PlayIdleFace();
}
}
}
else
{
if ( isDefined( notifyString ) )
{
self.faceResult = "failed";
self notify( notifyString );
}
//("Face: Didn't play facial sound: ",soundAlias,", animation: ",facialanim," notify: ",notifyString,", importance ",importance,", old one ",self.a.currentDialogImportance);#/
}
}
WaitForFacialAnim() // Used solely by PlayFaceThread
{
self endon( "death" );
self endon( "end current face" );
self animscripts\shared::DoNoteTracks( "animscript faceanim" );
self.a.facialAnimDone = true;
self notify( "animscript facedone" );
}
WaitForFaceSound( msg ) // Used solely by PlayFaceThread
{
self endon( "death" );
self waittill( "animscript facesound" + msg );
self notify( msg );
}
PlayFace_WaitForNotify( waitForString, notifyString, killmeString )
{
self endon( "death" );
self endon( killmeString );
self waittill( waitForString );
self.a.faceWaitForResult = "notify";
self notify( notifyString );
}
PlayFace_WaitForTime( time, notifyString, killmeString )
{
self endon( "death" );
self endon( killmeString );
wait( time );
self.a.faceWaitForResult = "time";
self notify( notifyString );
}
#using_animtree( "generic_human" );// This section of the file calls animations directly since it's only used on AI.
InitLevelFace()
{
// Does per-level initialization of facial stuff.
// These numbers indicate how many different sound aliases there are in dialog_generic.csv for each
// nationality. This script will assign each guy a random voice number from 1 to the number indicated
// for his voice nationality below. If we add a new voice type to sound_generic.csv, we need to update
// these numbers accordingly.
anim.numAmericanVoices = 8;
anim.numNavySealVoices = 8;
anim.numTaskForceVoices = 8;
anim.numSecretServiceVoices = 8;
anim.numBritishVoices = 8;
anim.numRussianVoices = 8;
anim.numArabVoices = 8;
anim.numPortugueseVoices = 8;
anim.numShadowCompanyVoices = 8;
anim.numJSWCVoices = 4;
anim.numUSOPVoices = 4;
anim.numIndonesianVoices = 8;
}

View File

@ -0,0 +1,17 @@
main()
{
self endon( "death" );
self endon( "stop_first_frame" );
self notify( "killanimscript" );
self.pushable = 0;
self clearAnim( self.root_anim, 0.3 );
// self setAnim( %body, 1, 0 ); // The %body node should always have weight 1.
self OrientMode( "face angle", self.angles[ 1 ] );
self setanim( level._scr_anim[ self._animname ][ self._first_frame_anim ], 1, 0, 0 );
self._first_frame_anim = undefined;
self waittill( "killanimscript" );
}

94
animscripts/flashed.gsc Normal file
View File

@ -0,0 +1,94 @@
#include animscripts\Utility;
#include animscripts\SetPoseMovement;
#include animscripts\Combat_utility;
#include maps\_anim;
#include maps\_utility;
#using_animtree( "generic_human" );
initFlashed()
{
anim.flashAnimArray[ 0 ] = %exposed_flashbang_v1;
anim.flashAnimArray[ 1 ] = %exposed_flashbang_v2;
anim.flashAnimArray[ 2 ] = %exposed_flashbang_v3;
anim.flashAnimArray[ 3 ] = %exposed_flashbang_v4;
anim.flashAnimArray[ 4 ] = %exposed_flashbang_v5;
randomizeFlashAnimArray();
anim.flashAnimIndex = 0;
}
randomizeFlashAnimArray()
{
for ( i = 0; i < anim.flashAnimArray.size; i++ )
{
switchwith = randomint( anim.flashAnimArray.size );
temp = anim.flashAnimArray[ i ];
anim.flashAnimArray[ i ] = anim.flashAnimArray[ switchwith ];
anim.flashAnimArray[ switchwith ] = temp;
}
}
getNextFlashAnim()
{
anim.flashAnimIndex++;
if ( anim.flashAnimIndex >= anim.flashAnimArray.size )
{
anim.flashAnimIndex = 0;
randomizeFlashAnimArray();
}
return anim.flashAnimArray[ anim.flashAnimIndex ];
}
flashBangAnim( animation )
{
self endon( "killanimscript" );
self setflaggedanimknoball( "flashed_anim", animation, %body, 0.2, randomFloatRange( 0.9, 1.1 ) );
self animscripts\shared::DoNoteTracks( "flashed_anim" );
}
main()
{
self endon( "death" );
self endon( "killanimscript" );
animscripts\utility::initialize( "flashed" );
flashDuration = self flashBangGetTimeLeftSec();
if ( flashDuration <= 0 )
return;
self animscripts\face::SayGenericDialogue( "flashbang" );
if ( isdefined( self.specialFlashedFunc ) )
{
self [[ self.specialFlashedFunc ]]();
return;
}
animation = getNextFlashAnim();
flashBangedLoop( animation, flashDuration );
}
flashBangedLoop( animation, duration )
{
self endon( "death" );
self endon( "killanimscript" );
assert( isDefined( animation ) );
assert( isDefined( duration ) );
assert( duration > 0 );
if ( self.a.pose == "prone" )
self ExitProneWrapper( 1 );
self.a.pose = "stand";
self.allowdeath = true;
self thread flashBangAnim( animation );
wait ( duration );
self notify( "stop_flashbang_effect" );
self.flashed = false;
}

View File

@ -0,0 +1,91 @@
#include animscripts\Utility;
#using_animtree( "generic_human" );
main()
{
self endon( "killanimscript" );
animscripts\utility::initialize( "grenadecower" );
if ( isdefined( self.grenadeCowerFunction ) )
{
self [[ self.grenadeCowerFunction ]]();
return;
}
if ( self.a.pose == "prone" )
{
// TODO: use an i-just-dived loop?
animscripts\stop::main();
return; // Should never get to here
}
self AnimMode( "zonly_physics" );
self OrientMode( "face angle", self.angles[ 1 ] );
grenadeAngle = 0;
if ( isdefined( self.grenade ) )// failsafe
grenadeAngle = AngleClamp180( vectorToAngles( self.grenade.origin - self.origin )[ 1 ] - self.angles[ 1 ] );
else
grenadeAngle = self.angles[ 1 ];
if ( self.a.pose == "stand" )
{
if ( isdefined( self.grenade ) && TryDive( grenadeAngle ) )
return;
self setFlaggedAnimKnobAllRestart( "cowerstart", %exposed_squat_down_grenade_F, %body, 1, 0.2 );
self animscripts\shared::DoNoteTracks( "cowerstart" );
}
self.a.pose = "crouch";
self.a.movement = "stop";
self setFlaggedAnimKnobAllRestart( "cower", %exposed_squat_idle_grenade_F, %body, 1, 0.2 );
self animscripts\shared::DoNoteTracks( "cower" );
self waittill( "never" );
}
end_script()
{
self.safeToChangeScript = true;
}
TryDive( grenadeAngle )
{
if ( randomint( 2 ) == 0 )
return false;
if ( self.stairsState != "none" )
return false;
diveAnim = undefined;
if ( abs( grenadeAngle ) > 90 )
{
// grenade behind us
diveAnim = %exposed_dive_grenade_B;
}
else
{
// grenade in front of us
diveAnim = %exposed_dive_grenade_F;
}
// when the dives are split into a dive, idle, and get up,
// maybe we can get a better point to do the moveto check with
moveBy = getMoveDelta( diveAnim, 0, 0.5 );
diveToPos = self localToWorldCoords( moveBy );
if ( !self MayMoveToPoint( diveToPos ) )
return false;
self.safeToChangeScript = false;
self setFlaggedAnimKnobAllRestart( "cowerstart", diveAnim, %body, 1, 0.2 );
self animscripts\shared::DoNoteTracks( "cowerstart" );
self.safeToChangeScript = true;
return true;
}

View File

@ -0,0 +1,148 @@
#include animscripts\Utility;
#using_animtree( "generic_human" );
// Grenade_return_throw
// Picks up a grenade from 32 units in front of the character, and throws it.
main()
{
/#
if ( getdvar( "scr_forcegrenadecower" ) == "on" && isdefined( self.grenade ) )
{
self OrientMode( "face angle", randomfloat( 360 ) );
self animmode( "gravity" );
wait .2;
animscripts\grenade_cower::main();
return;
}
#/
self orientMode( "face default" );
self endon( "killanimscript" );
animscripts\utility::initialize( "grenade_return_throw" );
self animMode( "zonly_physics" );// Unlatch the feet
throwAnim = undefined;
throwDist = 1000;
if ( isdefined( self.enemy ) )
throwDist = distance( self.origin, self.enemy.origin );
// unused: grenade_return_running_kick_forward_1; kicks don't read well to player
// unused: grenade_return_running_kick_forward_2
// unused: %grenade_return_standing_throw_forward_2; similar to other ones
animArray = [];
if ( throwDist < 600 && isLowThrowSafe() )
{
if ( throwDist < 300 )
{
// really short range
animArray[ 0 ] = %grenade_return_running_throw_forward;
animArray[ 1 ] = %grenade_return_standing_throw_forward_1;
}
else
{
// long range
animArray[ 0 ] = %grenade_return_running_throw_forward;
animArray[ 1 ] = %grenade_return_standing_throw_overhand_forward;
}
}
if ( animArray.size == 0 )
{
// really long range or can't do low throw
animArray[ 0 ] = %grenade_return_standing_throw_overhand_forward;
}
assert( animArray.size );
throwAnim = animArray[ randomint( animArray.size ) ];
/#
if ( getdvar( "scr_grenadereturnanim" ) != "" )
{
val = getdvar( "scr_grenadereturnanim" );
//if ( val == "kick1")
// throwAnim = %grenade_return_running_kick_forward_1;
//else if ( val == "kick2")
// throwAnim = %grenade_return_running_kick_forward_2;
//else
if ( val == "throw1" )
throwAnim = %grenade_return_running_throw_forward;
else if ( val == "throw2" )
throwAnim = %grenade_return_standing_throw_forward_1;
//else if ( val == "throw3")
// throwAnim = %grenade_return_standing_throw_forward_2;
else if ( val == "throw4" )
throwAnim = %grenade_return_standing_throw_overhand_forward;
}
#/
assert( isdefined( throwAnim ) );
self setFlaggedAnimKnoballRestart( "throwanim", throwAnim, %body, 1, .3 );
hasPickup = ( animHasNotetrack( throwAnim, "grenade_left" ) || animHasNotetrack( throwAnim, "grenade_right" ) );
if ( hasPickup )
{
self animscripts\shared::placeWeaponOn( self.weapon, "left" );
self thread putWeaponBackInRightHand();
self thread notifyGrenadePickup( "throwanim", "grenade_left" );
self thread notifyGrenadePickup( "throwanim", "grenade_right" );
self waittill( "grenade_pickup" );
self pickUpGrenade();
self animscripts\battleChatter_ai::evaluateAttackEvent( "grenade" );
self waittillmatch( "throwanim", "grenade_throw" );
}
else
{
// kick animations don't have pickup.
self waittillmatch( "throwanim", "grenade_throw" );
self pickUpGrenade();
self animscripts\battleChatter_ai::evaluateAttackEvent( "grenade" );
}
if ( isDefined( self.grenade ) ) // it may have exploded and we may have magic bullet shield
self throwGrenade();
// TODO: replace with a notetrack?
wait 1;
if ( hasPickup )
{
self notify( "put_weapon_back_in_right_hand" );
self animscripts\shared::placeWeaponOn( self.weapon, "right" );
}
}
isLowThrowSafe()
{
start = ( self.origin[ 0 ], self.origin[ 1 ], self.origin[ 2 ] + 20 );
end = start + anglesToForward( self.angles ) * 50;
return sightTracePassed( start, end, false, undefined );
}
putWeaponBackInRightHand()
{
self endon( "death" );
self endon( "put_weapon_back_in_right_hand" );
self waittill( "killanimscript" );
self animscripts\shared::placeWeaponOn( self.weapon, "right" );
}
notifyGrenadePickup( animFlag, notetrack )
{
self endon( "killanimscript" );
self endon( "grenade_pickup" );
self waittillmatch( animFlag, notetrack );
self notify( "grenade_pickup" );
}

View File

@ -0,0 +1,981 @@
#include maps\_utility;
#include common_scripts\utility;
#include maps\_anim;
#using_animtree( "generic_human" );
humvee_turret_init( turret, turretType )
{
self endon( "killanimscript" );// code
Assert( IsDefined( turret ) );
animscripts\utility::initialize( turretType );
self.no_ai = true;
self.noDrop = true;
self.a.movement = "stop";
self.a.special = turretType;
self.a.usingTurret = turret;
self.ignoreme = true;
self.isCustomAnimating = false;
self SetTurretAnim( self.primaryTurretAnim );
self SetAnimKnobRestart( self.primaryTurretAnim, 1, 0.2, 1 );
if ( IsDefined( self.weapon ) )
{
self animscripts\shared::placeWeaponOn( self.weapon, "none" );
}
self.onRotatingVehicleTurret = true;
self.getOffVehicleFunc = ::turret_cleanup_on_unload;
// end some _vehicle and _mgturret threads that we don't want
self notify( "guy_man_turret_stop" );
turret notify( "stop_burst_fire_unmanned" );
// setup the turret
turret.turretState = "start";
turret.aiOwner = self;
turret.fireTime = 0;
turret SetMode( "sentry" );
turret SetSentryOwner( self );
turret SetDefaultDropPitch( 0 );
turret SetTurretCanAIDetach( false );
if ( IsDefined( turret.hummer_turret_intial_mode ) )
{
turret SetMode( turret.hummer_turret_intial_mode );
}
self gunner_pain_init();
level thread handle_gunner_pain( self, turret );
level thread handle_gunner_death( self, turret );
// start tracking the turret rotation
turret thread turret_track_rotatedirection( self );
// start turret fire director
turret.doFiring = false;
self thread fireDirector( turret );
wait( 0.05 );
if ( IsAlive( self ) )
{
self thread gunner_turning_anims( turret );
}
}
gunner_pain_init()
{
self.allowPain = false; // we're going to handle it ourselves
self setFlashbangImmunity( true );
self.og_health = self.health;
self.health = 200;
}
gunner_pain_reset()
{
self.allowPain = true;
self setFlashbangImmunity( false );
self.health = self.og_health;
}
handle_gunner_pain( gunner, turret )
{
gunner endon( "death" );
turret endon( "death" );
gunner endon( "dismount" );
gunner endon( "jumping_out" );
while ( 1 )
{
flashedNotify = "flashbang";
//gunner waittill( "damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, dflags );
msg = gunner waittill_any_return( "damage", flashedNotify );
/* custom anim pre-empts pain or flash
if( gunner.isCustomAnimating )
{
continue;
}
*/
painAnim = random( gunner.turretPainAnims );
if ( msg == flashedNotify )
{
painAnim = gunner.turretFlashbangedAnim;
gunner animscripts\face::SayGenericDialogue( "flashbang" );
}
//turret thread turret_recenter();
gunner DoCustomAnim( turret, painAnim, false );
turret notify( "pain_done" );
}
}
turret_recenter()
{
self turret_aim_straight();
self waittill( "pain_done" );
self turret_aim_restore();
}
handle_gunner_death( gunner, turret )
{
gunner endon( "dismount" );
turret endon( "turret_cleanup" );
gunner.deathanim = gunner.turretDeathAnim;
gunner.noragdoll = true;
gunner waittill( "death" );
level thread turret_cleanup( gunner, turret );
}
// for when _vehicle_aianim wants to unload the gunner, it doesn't know as much as this script yet
turret_cleanup_on_unload()
{
Assert( IsDefined( self.ridingVehicle ) );
turret = self.ridingVehicle.mgturret[ 0 ];
Assert( IsDefined( turret ) );
// clean up AI - moved it here since it's only needed for unloading.
if ( IsAlive( self ) )
{
self.no_ai = undefined;
self.noDrop = undefined;
self.ignoreme = false;
self.a.special = "none";
self.a.usingTurret = undefined;
self.deathanim = undefined;
self gunner_pain_reset();
self.isCustomAnimating = undefined;
self.turretSpecialAnims = undefined;
self.turretPainAnims = undefined;
self.onRotatingVehicleTurret = undefined;
self.getOffVehicleFunc = undefined;
self StopUseTurret();
if ( IsDefined( self.weapon ) )
{
self animscripts\shared::placeWeaponOn( self.weapon, "right" );
}
}
level thread turret_cleanup( self, turret );
}
turret_cleanup( gunner, turret )
{
if ( !IsDefined( turret ) )
{
return;
}
turret notify( "kill_fireController" );
turret notify( "turret_cleanup" );
turret SetMode( "manual" );
turret ClearTargetEntity();
turret SetDefaultDropPitch( turret.default_drop_pitch );
if ( IsDefined( gunner ) )
{
gunner ClearAnim( gunner.additiveUsegunRoot, 0 );
gunner ClearAnim( gunner.additiveRotateRoot, 0 );
gunner ClearAnim( gunner.turretSpecialAnimsRoot, 0 );
}
// clean up turret
turret.fireInterval = undefined;
turret.closeEnoughAimDegrees = undefined;
turret.fireControllerFunc = undefined;
turret.turretState = "free";
turret.aiOwner = undefined;
turret.fireTime = undefined;
if ( IsDefined( turret.specialCleanupFunc ) )
{
level [[ turret.specialCleanupFunc ]]( gunner, turret );
}
}
// tracks the rotational direction of the turret
turret_track_rotatedirection( gunner )
{
self endon( "turret_cleanup" );
self endon( "death" );
gunner endon( "death" );
gunner endon( "detach" );
tag = "tag_aim";
lastAngles = self GetTagAngles( tag );
self turret_update_rotatedirection( "none" );
while ( 1 )
{
currentAngles = self GetTagAngles( tag );
// the vectordot of the old right angles and the current forward angles is going to tell us whether
// the turret is rotating left, right, or not at all
oldRight = AnglesToRight( lastAngles );
currentForward = AnglesToForward( currentAngles );
dot = VectorDot( oldRight, currentForward );
if ( dot == 0 )
{
self turret_update_rotatedirection( "none" );
}
else if ( dot > 0 )
{
self turret_update_rotatedirection( "right" );
}
else
{
self turret_update_rotatedirection( "left" );
}
lastAngles = self GetTagAngles( tag );
wait( 0.05 );
}
}
turret_update_rotatedirection( direction )
{
if ( !IsDefined( self.rotateDirection ) || self.rotateDirection != direction )
{
self.rotateDirection = direction;
//println( "spin direction change: " + self.rotateDirection );
}
}
gunner_turning_anims( turret )
{
self endon( "death" );
turret endon( "death" );
self endon( "dismount" );
turret endon( "turret_cleanup" );
blendInTime = 0.3;
blendOutTime = 0.3;
while ( 1 )
{
turret waittill( "new_fireTarget" );
wait( 0.05 );// give him a chance to start rotating to the new target so the direction updates
if ( !IsDefined( turret.fireTarget ) || self.isCustomAnimating )
{
continue;
}
anime = undefined;
if ( !turret turret_aiming_near_target( turret.fireTarget, turret.closeEnoughAimDegrees ) )
{
if ( turret.rotateDirection == "right" )
{
anime = self.additiveTurretRotateRight;
//println( "gunner anim RIGHT" );
}
else if ( turret.rotateDirection == "left" )
{
anime = self.additiveTurretRotateLeft;
//println( "gunner anim LEFT" );
}
if ( IsDefined( anime ) )
{
// dial the parent branch up
self SetAnimLimited( self.additiveRotateRoot, 1, blendInTime, 1 );
// also tell it which leaf anim to use
// (this is inheriting its parent's blend in time so we can set the time to 0)
self SetAnimKnobLimited( anime, 1, 0, 1 );
while ( IsDefined( turret.fireTarget ) && !turret turret_aiming_near_target( turret.fireTarget, turret.closeEnoughAimDegrees ) )
{
if ( self.isCustomAnimating )
{
break;
}
wait( 0.05 );
}
//println( "gunner anim CLEAR" );
self ClearAnim( self.additiveRotateRoot, blendOutTime );
}
}
}
}
// makes a passenger into the turret gunner - call instead of UseTurret()
vehicle_passenger_2_turret( vehicle, pos, turret, animation )
{
vehicle.usedPositions[ self.vehicle_position ] = false;
//vehicle.riders = array_remove( vehicle.riders, self );
self maps\_vehicle_aianim::guy_cleanup_vehiclevars();
guy_gets_on_turret( vehicle, pos, turret, animation );
}
// makes a passenger into the turret gunner - call instead of UseTurret()
guy_goes_directly_to_turret( vehicle, pos, turret, animation )
{
guy_gets_on_turret( vehicle, pos, turret, animation );
}
guy_gets_on_turret( vehicle, pos, turret, animation )
{
self endon( "death" );
turret endon( "death" );
// forget about being a regular vehicle rider
self StopAnimScripted();
self notify( "newanim" );
self.drivingVehicle = undefined;
self.no_ai = true;
animation = %humvee_passenger_2_turret;
if ( !isdefined( animation ) )
animation = self.passenger_2_turret_anim;
// get the origin/angles of the vehicle tag where this guy is riding
animpos = maps\_vehicle_aianim::anim_pos( vehicle, pos );
org = vehicle GetTagOrigin( animpos.sittag );
angles = vehicle GetTagAngles( animpos.sittag );
turret SetDefaultDropPitch( 0 );
turret thread turret_animate( turret.passenger2turret_anime );
// animate into position
self AnimScripted( "passenger2turret", org, angles, animation );
wait( GetAnimLength( animation ) );
self StopAnimScripted();
turret turret_aim_restore();
// now start running the regular turret scripts - GDT points to minigun_hummer\stand::main()
self UseTurret( turret );
}
turret_animate( anime )
{
if ( IsDefined( self.idleAnim ) )
{
self ClearAnim( self.idleAnim, 0 );
self.idleAnim = undefined;
}
self SetFlaggedAnimKnobRestart( "minigun_turret", anime, 1, 0, 1 );
self waittillmatch( "minigun_turret", "end" );
self ClearAnim( anime, 0 );
}
turret_animfirstframe( anime )
{
self SetAnimKnobRestart( anime, 1, 0, 0 );
self.idleAnim = anime;
}
// "directs" the turret about whether it should be firing or not
// note: works with either code-controlled sentry targets or manually setting turret target
// - to make an AI aim without firing, set his .ignoreall to true
fireDirector( turret )
{
self endon( "death" );
turret endon( "death" );
self endon( "dismount" );
turret endon( "kill_fireController" );
turret thread turret_target_updater( self );
wait( 0.05 );// let the target updater kick off
self thread [[ turret.fireControllerFunc ]]( turret );
target = undefined;
wait_duration_after_aiming_before_firing = 0.0;
if ( IsDefined( turret.wait_duration_after_aiming_before_firing ) )
{
wait_duration_after_aiming_before_firing = turret.wait_duration_after_aiming_before_firing;
}/*
while ( 1 )
{
// get a target
target = turret.fireTarget;
// wait for the right time to start shooting
while ( turret target_confirm( target ) )
{
// tried a CanSee check here too, didn't seem necessary after testing
if ( turret turret_aiming_near_target( target, turret.closeEnoughAimDegrees ) )
{
break;
}
wait( 0.05 );
}
// wait while aiming at target before firing
if ( wait_duration_after_aiming_before_firing > 0.0 )
{
wait( wait_duration_after_aiming_before_firing );
}
//TagCC<NOTE>: What if the state changes between the time target_confirmed was true and was aiming towards target and now?
if ( turret target_confirm( target ) && !self.ignoreall )
{
// shoot at him
turret.doFiring = true;
}
// wait for his death, or for the code/script to pick/designate a new target
while ( turret target_confirm( target ) && !self.ignoreall && !self.isCustomAnimating )
{
wait( 0.05 );
}
// stop shooting
if ( turret.Dofiring || self.ignoreall )
{
turret.doFiring = false;
}
wait( 0.05 );
}
*/
while( true )
{
target = turret.fireTarget;
//short circuit the loop if self is ignore all.
if( self.ignoreall || !IsDefined( target ) )
{
wait 0.05;
continue;
}
//wait until target is confirmed and the turret is aiming towards the actor.
while( !IsDefined( target ) || !( (turret target_confirm( target )) && (turret turret_aiming_near_target( target, turret.closeEnoughAimDegrees )) ) )
{
wait 0.05;
target = turret.fireTarget;
}
if ( wait_duration_after_aiming_before_firing > 0.0 )
{
wait wait_duration_after_aiming_before_firing;
}
turret.doFiring = true;
//once firing begins, wait until target is no longer confirmed (usually death of target), then stop.
while ( turret target_confirm( target ) && !self.ignoreall && !self.isCustomAnimating )
{
wait 0.05;
}
turret.doFiring = false;
wait 0.05;
}
}
// makes sure the target that the fireDirector is thinking about is still synced with turret_target_updater
target_confirm( target )
{
if ( IsDefined( self.dontshoot ) )
{
AssertEx( self.dontshoot, ".dontshoot must be true or undefined." );
return false;
}
// maybe the turret can't see the target anymore
if ( !IsDefined( self.fireTarget ) )
{
return false;
}
if ( !turret_target_validate( target ) )
{
return false;
}
if ( target != self.fireTarget )
{
return false;
}
return true;
}
// make sure the script knows about the most recent turret target
// (this is necessary because code sets the turret target silently and behind the scenes)
turret_target_updater( gunner )
{
gunner endon( "death" );
self endon( "death" );
gunner endon( "dismount" );
self endon( "kill_fireController" );
// initialize this, other threads are looking for it
self.fireTarget = undefined;
target = undefined;
lastTarget = undefined;
while ( 1 )
{
target = self GetTurretTarget( false );
doUpdate = false;
// target can come back undefined if the turret loses sight of its target
if ( turret_target_validate( target ) || !IsDefined( target ) )
{
// if the old target was defined and the new target is undefined
// (e.g., the turret lost its target) we want to update
if ( !IsDefined( target ) && IsDefined( lastTarget ) )
{
doUpdate = true;
}
// or, if the new target is defined and the old one isn't, do the update
else if ( IsDefined( target ) && !IsDefined( lastTarget ) )
{
doUpdate = true;
}
// or, if the new target is defined and different from before, do the update
else if ( IsDefined( target ) && target != lastTarget )
{
doUpdate = true;
}
if ( doUpdate )
{
self.fireTarget = target;
lastTarget = target;
self notify( "new_fireTarget" );
}
}
wait( 0.05 );
}
}
turret_target_validate( target )
{
if ( !IsDefined( target ) )
{
return false;
}
if ( IsDefined( target.ignoreme ) && target.ignoreme )
{
return false;
}
// can't use IsSentient because the sentient AIs will turn into non-sentient corpses
if ( IsSubStr( target.code_classname, "actor" ) && !IsAlive( target ) )
{
return false;
}
return true;
}
// manually designate a target for the turret
// - fireTime_min: minimum amount of time to fire once the turret has centered on the target
// - fireTime_max (optional): if set, function will pick a random time between min and max
// - fireTime_message (optional): will fire until the turret is notified the message. will ignore min and max time.
set_manual_target( target, fireTime_min, fireTime_max, fireTime_message )
{
AssertEx( IsDefined( target ), "undefined target passed to set_manual_target()." );
self endon( "turret_cleanup" );
oldMode = self GetMode();
if ( oldMode != "manual" )
{
self SetMode( "manual" );
}
if ( !IsDefined( fireTime_min ) && !IsDefined( fireTime_max ) )
{
fireTime_min = 1.5;
fireTime_max = 3;
}
self animscripts\hummer_turret\common::custom_anim_wait();
self SetTargetEntity( target );
//println( "target set" );
self waittill( "turret_on_target" );
//println( "turret on target" );
if ( IsDefined( fireTime_message ) )
{
self waittill( fireTime_message );
}
else if ( IsDefined( fireTime_max ) )
{
wait( RandomFloatRange( fireTime_min, fireTime_max ) );
}
else
{
wait( fireTime_min );
}
self custom_anim_wait();
self ClearTargetEntity( target );
if ( IsDefined( oldMode ) )
{
self SetMode( oldMode );
}
}
DoShoot( turret )
{
self notify( "doshoot_starting" );
self SetAnimLimited( self.additiveUsegunRoot, 1, .1 );
self SetAnimKnobLimited( self.additiveTurretFire, 1, .1 );
turret.turretState = "fire";
turret thread fire( self );
}
fire( gunner )
{
gunner endon( "death" );
self endon( "death" );
gunner endon( "dismount" );
self endon( "kill_fireController" );
self endon( "stopfiring" );
self endon( "custom_anim" );
while ( 1 )
{
self ShootTurret();
wait( self.fireInterval );
}
}
DoAim( turret )
{
turret.turretState = "aim";
turret notify( "stopfiring" );
self thread DoAim_idle_think( turret );
}
DoAim_idle_think( turret )
{
self notify( "doaim_idle_think" );
self endon( "doaim_idle_think" );
self endon( "custom_anim" );
self endon( "doshoot_starting" );
self endon( "death" );
turret endon( "death" );
assertex( isdefined( turret ), "The turret is gone!" );
assertex( isalive( self ), "No, I can't die!" );
Assert( IsDefined( turret.ownervehicle ) );
vehicle = turret.ownervehicle;
assertex( isdefined( vehicle ), "There is no vehicle!" );
idle = -1;
for ( ;; )
{
if ( vehicle Vehicle_GetSpeed() < 1 && idle )
{
self SetAnimLimited( self.additiveUsegunRoot, 1, 0.1 );
self SetAnimKnobLimited( self.additiveTurretIdle, 1, 0.1 );
idle = 0;
}
else
if ( vehicle Vehicle_GetSpeed() >= 1 && !idle )
{
self SetAnimLimited( self.additiveUsegunRoot, 1, 0.1 );
self SetAnimKnobLimited( self.additiveTurretDriveIdle, 1, 0.1 );
idle = 1;
}
wait( 0.05 );
}
}
/*
=============
///ScriptDocBegin
"Name: turret_gunner_custom_anim( <turret> , <animStr> , <centerTurretFirst> )"
"Summary: Call on a turret gunner do one of his predefined custom animations. All the custom anims for a turret gunner get set up in the array self.turretSpecialAnims, in the main script for the turret type - for example, animscripts\hummer_turret\minigun_stand.gsc."
"Module: Entity"
"CallOn: An AI using a vehicle turret. (Note: this only works for 360 degree vehicle turrets, for example those on the hummer or the suburban.)"
"MandatoryArg: <turret> The turret the AI is using."
"MandatoryArg: <animStr> The name of the animation, as a string. used as the lookup index for self.turretSpecialAnims."
"OptionalArg: <centerTurretFirst>: Whether the turret should re-center to its "home" location before the animation plays. Defaults to false."
"Example: gunner animscripts\hummer_turret\common::turret_gunner_custom_anim( turret, anime, true );"
"SPMP: singleplayer"
///ScriptDocEnd
=============
*/
turret_gunner_custom_anim( turret, animStr, centerTurretFirst )
{
// this section of endons should be identical to the ones in the function below
self endon( "death" );
turret endon( "death" );
self endon( "dismount" );
self endon( "jumping_out" );
anime = self.turretSpecialAnims[ animStr ];
Assert( IsDefined( anime ) );
self custom_anim_wait();
disabledReload = turret reload_disable_safe();
self DoCustomAnim( turret, anime, centerTurretFirst );
if ( disabledReload )
{
turret reload_enable();
}
}
reload_disable_safe()
{
disabledReload = false;
if ( !IsDefined( self.disableReload ) || !self.disableReload )
{
disabledReload = true;
self.disableReload = true;
}
return disabledReload;
}
reload_enable()
{
self.disableReload = false;
}
DoReload( turret )
{
if ( IsDefined( turret.disableReload ) )
{
return;
}
// this section of endons should be identical to the ones in the function above
self endon( "death" );
turret endon( "death" );
self endon( "dismount" );
self endon( "jumping_out" );
self thread custom_battlechatter( "inform_reloading" );
turret notify( "starting_reload" );
self DoCustomAnim( turret, self.turretReloadAnim, turret.centerTurretForReload, turret.reloadDuration );
}
DoCustomAnim( turret, anime, centerTurretFirst, duration )
{
// NOTE! To stop behavior, don't notify do_custom_anim, do self notify( "special_anim", "end" );
self notify( "do_custom_anim" );
self endon( "do_custom_anim" );
if ( IsDefined( duration ) )
{
anim_rate = GetAnimLength( anime ) / duration;
}
else
{
anim_rate = 1.0;
}
/*
// these endons are dupes
self endon( "death" );
turret endon( "death" );
self endon( "dismount" );
self endon( "jumping_out" );
*/
Assert( IsDefined( anime ) );
self.isCustomAnimating = true;
self.customAnim = anime;
turret.turretState = "customanim";
turret TurretFireDisable();
if ( turret GetBarrelSpinRate() > 0 )
{
turret StopBarrelSpin();
}
// turn off threads that can mess up the animtree
turret notify( "kill_fireController" );
self notify( "custom_anim" );
if ( IsDefined( centerTurretFirst ) && centerTurretFirst )
{
turret turret_aim_straight();
}
// "knob" dials down all the siblings of the specialanimsroot, so we don't need to manually
// dial down self.primaryTurretAnim or self.additiveUsegunRoot right here
self SetAnimKnobLimitedRestart( self.turretSpecialAnimsRoot, 1, 0.2 );
self SetFlaggedAnimKnobRestart( "special_anim", anime, 1, 0, anim_rate );
for ( ;; )
{
// broke into a loop so I can debug the notetracks
self waittill( "special_anim", notetrack );
if ( notetrack == "end" )
break;
}
// turn the ROOT down, not the anim under the root
self ClearAnim( self.turretSpecialAnimsRoot, 0.2 );
// dial these up individually - can't use "knob" cause we want them both to be active
self SetAnimLimited( self.primaryTurretAnim, 1 ); // 0.2 blend time is the default
self SetAnimLimited( self.additiveUsegunRoot, 1 );
if ( IsDefined( centerTurretFirst ) && centerTurretFirst )
{
turret turret_aim_restore();
}
self.customAnim = undefined;
self.isCustomAnimating = false;
turret TurretFireEnable();
// turn those animtree-messing-up threads back on
self thread fireDirector( turret );
}
// use this if you're manually setting the turret target entity - call this first (non-threaded)
// to make sure that the DoCustomAnim function doesn't clear out your custom target
custom_anim_wait()
{
self endon( "death" );
if ( !IsDefined( self.isCustomAnimating ) )
{
return;
}
while ( self.isCustomAnimating )
{
wait( 0.05 );
}
}
turret_aim_straight( straightAngles )
{
if ( !IsDefined( straightAngles ) )
{
currentAngles = self GetTagAngles( "tag_flash" );
straightAngles = ( 0, currentAngles[ 1 ], currentAngles[ 2 ] );// just keep the yaw
}
self.oldMode = self GetMode();
self SetMode( "manual" );
// use a temp target to make the gun point straight forward
forward = AnglesToForward( straightAngles );
scalevec = vector_multiply( forward, 96 );
targetOrigin = self GetTagOrigin( "tag_aim" ) + scalevec;
self.tempTarget = Spawn( "script_origin", targetOrigin );
self.tempTarget.ignoreme = true;
self.tempTarget LinkTo( self.ownerVehicle );// if the vehicle is moving we have to link the target to the gun so the gun doesn't rotate around as the vehicle angles change
self ClearTargetEntity();
self SetTargetEntity( self.tempTarget );
self waittill( "turret_on_target" );
}
turret_aim_restore()
{
self ClearTargetEntity();
if ( IsDefined( self.tempTarget ) )
{
self.tempTarget Unlink();
self.tempTarget Delete();
}
if ( IsDefined( self.oldMode ) )
{
self SetMode( self.oldMode );
self.oldMode = undefined;
}
}
// - closeEnoughAngle: we want to be pointing within [+/- of this value in degrees]
// to the target to return true
turret_aiming_near_target( target, closeEnoughAngle )
{
//delta = self turret_get_angle_to_target( target );
turret_angles = AnglesToForward( self GetTagAngles( "tag_flash" ) );
delta = acos(VectorDot( VectorNormalize(target.origin - self.origin), turret_angles ));
if ( delta <= closeEnoughAngle )
{
return true;
}
return false;
}
turret_get_angle_to_target( target )
{
// get the yaw angle of the vector between the target origin and the turret origin
yawAngleToTarget = VectorToYaw( target.origin - self.origin ); //tagCC<NOTE>: I don't think this is being used right. Doesn't take into account self's angles.
// normalize the difference between the yaw angle and the angles of the end of the barrel:
// this tells us how far away we are from being perfectly centered on the target
turretYawAngle = self GetTagAngles( "tag_flash" )[ 1 ];
delta = animscripts\utility::AbsAngleClamp180( turretYawAngle - yawAngleToTarget );
return delta;
}
lerp_out_drop_pitch( time )
{
blend = self create_blend( ::blend_dropPitch, 20, 0 );
blend.time = time;
}
blend_dropPitch( progress, start, end )
{
val = start * ( 1 - progress ) + end * progress;
self SetDefaultDropPitch( val );
}

View File

@ -0,0 +1,203 @@
#include maps\_utility;
#include common_scripts\utility;
#include animscripts\hummer_turret\common;
main( turret )
{
turret.fireInterval = 0.1; // time between shots
turret.closeEnoughAimDegrees = 35; // how many degrees away from aiming exactly at the target should we be before we start doing "on/near target" stuff
turret.fireControllerFunc = ::fireController_minigun; // the function that tells the turret how exactly to shoot when the fireDirector tells it that it should be firing
turret.specialCleanupFunc = ::minigun_cleanup_func; // gets called when the turret is no longer in use
turret.default_drop_pitch = 20;
turret.secsOfFiringBeforeReload = 15; // secs; the weapon will need periodic operator "maintenance"
humvee_turret_init( turret, "minigun" );
wait( 0.05 );
turret notify( "turret_ready" );
}
minigun_cleanup_func( gunner, turret )
{
if ( turret GetBarrelSpinRate() > 0 )
{
turret StopBarrelSpin();
}
// could be disabled if we're in a custom anim when the actor dies
turret TurretFireEnable();
}
// controls spinning & firing the minigun, responding to commands from fireDirector()
fireController_minigun( turret )
{
self endon( "death" );
self endon( "dismount" );
assert( isdefined( turret ) );
turret endon( "kill_fireController" );
turret endon( "death" );
// "extra" fire time makes the operator look like he has human reaction time
extraFireTime_min = 600; // ms
extraFireTime_max = 900;
if ( IsDefined( turret.extraFireTime_min ) )
{
extraFireTime_min = turret.extraFireTime_min;
}
if ( IsDefined( turret.extraFireTime_max ) )
{
extraFireTime_max = turret.extraFireTime_max;
}
startFireTime = -1;
ceaseFireTime = undefined;
extraFireTime = undefined;
// extra spin time makes it look like the operator is scanning for more targets
turret.extraSpinTime_min = 250;
turret.extraSpinTime_max = 2250;
startExtraSpinningTime = -1;
extraSpinTime = undefined;
isFiring = false;
isSpinning = false;
turret.fireTime = 0;
self DoAim( turret );
while ( 1 )
{
// if we're supposed to be firing but we're not, and if we're not doing a custom anim...
if ( turret.doFiring && !isFiring && !self.isCustomAnimating )
{
isFiring = true;
// spin the barrel if need be
if ( !isSpinning )
{
//println( "start spin" );
turret minigun_spinup();
isSpinning = true;
}
// start firing
//println( "start firing" );
turret notify( "startfiring" );
startFireTime = GetTime();
self DoShoot( turret );
wait( 0.05 ); // let the shooting thread start before potentially killing it on the same frame
}
// if we're currently not supposed to be firing but still actually are...
else if ( !turret.doFiring && isFiring )
{
if ( !IsDefined( ceaseFireTime ) )
{
ceaseFireTime = GetTime(); // time when the turret stops firing
}
if ( !IsDefined( extraFireTime ) )
{
extraFireTime = RandomFloatRange( extraFireTime_min, extraFireTime_max );
}
// have we fired long enough after being told to stop?
if ( GetTime() - ceaseFireTime >= extraFireTime )
{
isFiring = false;
//println( "stop firing" );
self DoAim( turret );
startExtraSpinningTime = GetTime();
// reset counters
ceaseFireTime = undefined;
extraFireTime = undefined;
}
}
// if all we're still doing is spinning...
else if ( !turret.doFiring && !isFiring && isSpinning )
{
if ( !IsDefined( extraSpinTime ) )
{
extraSpinTime = RandomFloatRange( turret.extraSpinTime_min, turret.extraSpinTime_max );
}
// stop spin immediately for custom anims, or wait for extra spin time
if ( self.isCustomAnimating || ( GetTime() - startExtraSpinningTime >= extraSpinTime ) )
{
//println( "stop spin" );
turret StopBarrelSpin();
isSpinning = false;
extraSpinTime = undefined; // reset
}
}
if ( turret.turretstate == "fire" )
turret.fireTime += 0.05;// ( GetTime() - startFireTime ) / 1000;
if ( turret.fireTime > turret.secsOfFiringBeforeReload )
{
//println( "reload" );
turret.doFiring = false;
isFiring = false;
self DoAim( turret );
startExtraSpinningTime = -1;
ceaseFireTime = undefined;
extraFireTime = undefined;
self thread DoReload( turret );
turret.fireTime = 0; // reset counter
}
wait( 0.05 );
if ( !isdefined( turret ) )
break;
}
}
// spins the minigun up to the full rate needed to fire
minigun_spinup()
{
if ( self GetBarrelSpinRate() == 1 )
{
return;
}
self StartBarrelSpin();
wait( 0.05 );
// Dan: Wait for spin up only if this weapon actually spins up.
if ( self GetBarrelSpinRate() == 0 )
{
return;
}
else if ( self GetBarrelSpinRate() == 1 )
{
return;
}
wait( 0.05 );
while ( self GetBarrelSpinRate() < 1 )
{
wait( 0.05 );
}
}
//=====================================
// SRS TEMP - so I don't clutter generic_human with stuff I'm not using atm
/*
humveeGunner : complete nonloopsync
{
//humvee_turret_2_passenger
//humvee_turret_duck
//humvee_turret_duck_left
//humvee_turret_duck_right
//humvee_turret_death
}
*/

View File

@ -0,0 +1,63 @@
#include maps\_utility;
#include common_scripts\utility;
#using_animtree( "generic_human" );
// self = the guy using the turret
main()
{
turret = self getTurret();
self.desired_anim_pose = "stand";
animscripts\utility::UpdateAnimPose();
// .primaryTurretAnim is used by code so don't change this variable name
self.primaryTurretAnim = %humveeGunner_aim;
self.additiveTurretRotateLeft = %humvee_turret_aim_6_add;
self.additiveTurretRotateRight = %humvee_turret_aim_4_add;
self.additiveRotateRoot = %additive_humveeGunner_aim_leftright;
self.additiveTurretIdle = %humvee_turret_idle;
self.additiveTurretDriveIdle = %humvee_turret_driveidle;
self.additiveTurretFire = %humvee_turret_fire;
self.additiveUsegunRoot = %additive_humveeGunner_usegun;
self.turretDeathAnimRoot = %humveeGunner_death;
self.turretDeathAnim = %humvee_turret_death;
self.turretPainAnims[ 0 ] = %humvee_turret_painA;
self.turretPainAnims[ 1 ] = %humvee_turret_painB;
self.turretFlashbangedAnim = %humvee_turret_flinchA;
self.turretReloadAnim = %humvee_turret_rechamber;
self.turretSpecialAnimsRoot = %humveeGunner;
arr = [];
arr[ "humvee_turret_bounce" ] = %humvee_turret_bounce;
arr[ "humvee_turret_idle_lookback" ] = %humvee_turret_idle_lookback;
arr[ "humvee_turret_idle_lookbackB" ] = %humvee_turret_idle_lookbackB;
arr[ "humvee_turret_idle_signal_forward" ] = %humvee_turret_idle_signal_forward;
arr[ "humvee_turret_idle_signal_side" ] = %humvee_turret_idle_signal_side;
arr[ "humvee_turret_radio" ] = %humvee_turret_radio;
arr[ "humvee_turret_flinchA" ] = %humvee_turret_flinchA;
arr[ "humvee_turret_flinchB" ] = %humvee_turret_flinchB;
arr[ "humvee_turret_rechamber" ] = %humvee_turret_rechamber;
self.turretSpecialAnims = arr;
turret setup_turret_anims();
self thread animscripts\hummer_turret\minigun_code::main( turret );
turret.reloadDuration = 2.0;
turret.centerTurretForReload = true;
}
#using_animtree( "vehicles" );
setup_turret_anims()
{
self UseAnimTree( #animtree );
self.passenger2turret_anime = %humvee_passenger_2_turret_minigun;
self.turret2passenger_anime = %humvee_turret_2_passenger_minigun;
}

35
animscripts/init.gsc Normal file
View File

@ -0,0 +1,35 @@
#include animscripts\init_common;
main()
{
prof_begin( "animscript_init" );
pre_first_init();
firstInit();
post_first_init();
prof_end( "animscript_init" );
}
firstInit()
{
// Initialization that should happen once per level
if ( isDefined( anim.NotFirstTime ) )// Use this to trigger the first init
{
return false;
}
pre_anim_init();
animscripts\animset::init_anim_sets();
animscripts\init_move_transitions::initMoveStartStopTransitions();
anim.lastGibTime = 0;
anim.gibDelay = 3 * 1000; // 3 seconds
anim.minGibs = 2;
anim.maxGibs = 4;
anim.totalGibs = RandomIntRange( anim.minGibs, anim.maxGibs );
post_anim_init();
}

926
animscripts/init_common.gsc Normal file
View File

@ -0,0 +1,926 @@
// Notes about scripts
//=====================
//
// Anim variables
// --------------
// Anim variables keep track of what the character is doing with respect to his
// animations. They know if he's standing, crouching, kneeling, walking, running, etc,
// so that he can play appropriate transitions to get to the animation he wants.
// anim_movement - "stop", "walk", "run"
// anim_pose - "stand", "crouch", "prone", some others for pain poses.
// I'm putting functions to do the basic animations to change these variables in
// SetPoseMovement.gsc,
//
// Error Reporting
// ---------------
// To report a script error condition (similar to assert(0)), I assign a non-existent variable to
// the variable homemade_error I use the name of the non-existent variable to try to explain the
// error. For example:
// homemade_error = Unexpected_anim_pose_value + self.a.pose;
// I also have a kind of assert, called as follows:
// [[anim.assertEX(condition, message_string);
// If condition evaluates to 0, the assert fires, prints message_string and stops the server. Since
// I don't have stack traces of any kind, the message string needs to say from where the assert was
// called.
#include animscripts\Utility;
#include maps\_utility;
#include animscripts\Combat_utility;
#include common_scripts\Utility;
#using_animtree( "generic_human" );
initWeapon( weapon )
{
self.weaponInfo[ weapon ] = spawnstruct();
self.weaponInfo[ weapon ].position = "none";
self.weaponInfo[ weapon ].hasClip = true;
self.weaponInfo[ weapon ].recharges = ( weapon != "none" && WeaponAmmoRecharges( weapon ) );
if ( getWeaponClipModel( weapon ) != "" )
self.weaponInfo[ weapon ].useClip = true;
else
self.weaponInfo[ weapon ].useClip = false;
}
isWeaponInitialized( weapon )
{
return isDefined( self.weaponInfo[ weapon ] );
}
// Persistent global aiming limits / tolerances
setGlobalAimSettings()
{
anim.coverCrouchLeanPitch = 55;
// Used by 'Explosed' combat (combat scirpt)
anim.aimYawDiffFarTolerance = 10;
anim.aimYawDiffCloseDistSQ = 64 * 64;
anim.aimYawDiffCloseTolerance = 45;
anim.aimPitchDiffTolerance = 20;
// Used by LastStand (pain script)
anim.painYawDiffFarTolerance = 25;
anim.painYawDiffCloseDistSQ = anim.aimYawDiffCloseDistSQ;
anim.painYawDiffCloseTolerance = anim.aimYawDiffCloseTolerance;
anim.painPitchDiffTolerance = 30;
// Absolute maximum trackLoop angles after which the weights are reset to 0
// These must be greater than the maximum possible aiming limit for all stances
anim.maxAngleCheckYawDelta = 65;
anim.maxAngleCheckPitchDelta = 65;
}
everUsesSecondaryWeapon()
{
if ( isShotgun( self.secondaryweapon ) )
return true;
if ( weaponClass( self.primaryweapon ) == "rocketlauncher" )
return true;
return false;
}
pre_first_init()
{
self.a = spawnStruct();
self.a.laserOn = false;
self.primaryweapon = self.weapon;
}
post_first_init()
{
if ( self.primaryweapon == "" )
self.primaryweapon = "none";
if ( self.secondaryweapon == "" )
self.secondaryweapon = "none";
if ( self.sidearm == "" )
self.sidearm = "none";
self initWeapon( self.primaryweapon );
self initWeapon( self.secondaryweapon );
self initWeapon( self.sidearm );
// this will cause us to think we're using our sidearm when we're not. the aitype should not allow this.
assertex( self.primaryweapon != self.sidearm || self.primaryweapon == "none", "AI \"" + self.classname + "\" with export " + self.export + " has both a sidearm and primaryweapon of \"" + self.primaryweapon + "\"." );
assertex( self.secondaryweapon != self.sidearm || self.secondaryweapon == "none" || !self everUsesSecondaryWeapon(), "AI \"" + self.classname + "\" with export " + self.export + " has both a sidearm and secondaryweapon of \"" + self.primaryweapon + "\"." );
self setDefaultAimLimits();
self.a.weaponPos[ "left" ] = "none";
self.a.weaponPos[ "right" ] = "none";
self.a.weaponPos[ "chest" ] = "none";
self.a.weaponPos[ "back" ] = "none";
self.a.weaponPosDropping[ "left" ] = "none";
self.a.weaponPosDropping[ "right" ] = "none";
self.a.weaponPosDropping[ "chest" ] = "none";
self.a.weaponPosDropping[ "back" ] = "none";
self.lastWeapon = self.weapon;
self.root_anim = %root;
self thread beginGrenadeTracking();
hasRocketLauncher = usingRocketLauncher();
self.a.neverLean = hasRocketLauncher;
if ( hasRocketLauncher )
self thread animscripts\shared::rpgPlayerRepulsor();
// TODO: proper ammo tracking
self.a.rockets = 3;
self.a.rocketVisible = true;
// SetWeaponDist();
// Set initial states for poses
self.a.pose = "stand";
self.a.grenadeThrowPose = "stand";
self.a.movement = "stop";
self.a.state = "stop";
self.a.special = "none";
self.a.gunHand = "none"; // Initialize so that PutGunInHand works properly.
self.a.PrevPutGunInHandTime = -1;
self.dropWeapon = true;
self.minExposedGrenadeDist = 750;
animscripts\shared::placeWeaponOn( self.primaryweapon, "right" );
if ( isShotgun( self.secondaryweapon ) )
animscripts\shared::placeWeaponOn( self.secondaryweapon, "back" );
self.a.needsToRechamber = 0;
self.a.combatEndTime = gettime();
self.a.lastEnemyTime = gettime();
self.a.suppressingEnemy = false;
self.a.disableLongDeath = !( self isBadGuy() );
self.a.lookangle = 0;
self.a.painTime = 0;
self.a.lastShootTime = 0;
self.a.nextGrenadeTryTime = 0;
self.a.reactToBulletChance = 0.8;
if ( self.team != "allies" )
{
// only select allies have IR laser and beacon
self.has_no_ir = true;
}
self.a.postScriptFunc = undefined;
self.a.stance = "stand";
self.choosePoseFunc = animscripts\utility::choosePose;
//self.a.state = "idle";
self._animActive = 0;
self._lastAnimTime = 0;
self thread enemyNotify();
self.baseAccuracy = 1;
self.a.missTime = 0;
self.a.nodeath = false;
self.a.missTime = 0;
self.a.missTimeDebounce = 0;
self.a.disablePain = false;
self.accuracyStationaryMod = 1;
self.chatInitialized = false;
self.sightPosTime = 0;
self.sightPosLeft = true;
self.needRecalculateGoodShootPos = true;
self.defaultTurnThreshold = 55;
self.painPlaybackRate = 1.0;
self.a.nextStandingHitDying = false;
// Makes AI able to throw grenades at other AI.
if ( !isdefined( self.script_forcegrenade ) )
self.script_forcegrenade = 0;
/# self.a.lastDebugPrint = ""; #/
SetupUniqueAnims();
/# thread animscripts\utility::UpdateDebugInfo(); #/
self animscripts\weaponList::RefillClip(); // Start with a full clip.
// state tracking
self.lastEnemySightTime = 0;// last time we saw our current enemy
self.combatTime = 0;// how long we've been in / out of combat
self.suppressed = false;// if we're currently suppressed
self.suppressedTime = 0;// how long we've been in / out of suppression
if ( self.team == "allies" )
self.suppressionThreshold = 0.5;
else
self.suppressionThreshold = 0.0;
// Random range makes the grenades less accurate and do less damage, but also makes it difficult to throw back.
if ( self.team == "allies" )
self.randomGrenadeRange = 0;
else
self.randomGrenadeRange = 256;
self.ammoCheatInterval = 8000; // if out of ammo and it's been this long since last time, do an instant reload
self.ammoCheatTime = 0;
animscripts\init_common::set_animset_run_n_gun();
self.exception = [];
self.exception[ "corner" ] = 1;
self.exception[ "cover_crouch" ] = 1;
self.exception[ "stop" ] = 1;
self.exception[ "stop_immediate" ] = 1;
self.exception[ "move" ] = 1;
self.exception[ "exposed" ] = 1;
self.exception[ "corner_normal" ] = 1;
keys = getArrayKeys( self.exception );
for ( i = 0; i < keys.size; i++ )
{
clear_exception( keys[ i ] );
}
self.reacquire_state = 0;
self thread setNameAndRank_andAddToSquad();
self.shouldConserveAmmoTime = 0;
/#
self thread printEyeOffsetFromNode();
self thread showLikelyEnemyPathDir();
#/
self thread monitorFlash();
self thread onDeath();
}
weapons_with_ir( weapon )
{
weapons[ 0 ] = "m4_grenadier";
weapons[ 1 ] = "m4_grunt";
weapons[ 2 ] = "m4_silencer";
weapons[ 3 ] = "m4m203";
if ( !isdefined( weapon ) )
return false;
for ( i = 0 ; i < weapons.size ; i++ )
{
if ( issubstr( weapon, weapons[ i ] ) )
return true;
}
return false;
}
/#
printEyeOffsetFromNode()
{
self endon( "death" );
while ( 1 )
{
if ( getdvarint( "scr_eyeoffset" ) == self getentnum() )
{
if ( isdefined( self.coverNode ) )
{
offset = self geteye() - self.coverNode.origin;
forward = anglestoforward( self.coverNode.angles );
right = anglestoright( self.coverNode.angles );
trueoffset = ( vectordot( right, offset ), vectordot( forward, offset ), offset[ 2 ] );
println( trueoffset );
}
}
else
wait 2;
wait .1;
}
}
showLikelyEnemyPathDir()
{
self endon( "death" );
setDvarIfUninitialized( "scr_showlikelyenemypathdir", "-1" );
while ( 1 )
{
if ( getdvarint( "scr_showlikelyenemypathdir" ) == self getentnum() )
{
yaw = self.angles[ 1 ];
dir = self getAnglesToLikelyEnemyPath();
if ( isdefined( dir ) )
yaw = dir[ 1 ];
printpos = self.origin + ( 0, 0, 60 ) + anglestoforward( ( 0, yaw, 0 ) ) * 100;
line( self.origin + ( 0, 0, 60 ), printpos );
if ( isdefined( dir ) )
print3d( printpos, "likelyEnemyPathDir: " + yaw, ( 1, 1, 1 ), 1, 0.5 );
else
print3d( printpos, "likelyEnemyPathDir: undefined", ( 1, 1, 1 ), 1, 0.5 );
wait .05;
}
else
wait 2;
}
}
#/
setNameAndRank_andAddToSquad()
{
self endon( "death" );
if ( !isdefined( level._loadoutComplete ) )
level waittill( "loadout complete" );
self maps\_names::get_name();
// Init BC location cache
self.bc_last_get_location_time = 0;
self.bc_cache_time = 0;
self.bc_locations = [];
// needs to run after the name has been set since bcs changes self.voice from "multilingual"
// to something more specific
self thread animscripts\squadManager::addToSquad();// slooooow
}
// Debug thread to see when stances are being allowed
PollAllowedStancesThread()
{
for ( ;; )
{
if ( self isStanceAllowed( "stand" ) )
{
line[ 0 ] = "stand allowed";
color[ 0 ] = ( 0, 1, 0 );
}
else
{
line[ 0 ] = "stand not allowed";
color[ 0 ] = ( 1, 0, 0 );
}
if ( self isStanceAllowed( "crouch" ) )
{
line[ 1 ] = "crouch allowed";
color[ 1 ] = ( 0, 1, 0 );
}
else
{
line[ 1 ] = "crouch not allowed";
color[ 1 ] = ( 1, 0, 0 );
}
if ( self isStanceAllowed( "prone" ) )
{
line[ 2 ] = "prone allowed";
color[ 2 ] = ( 0, 1, 0 );
}
else
{
line[ 2 ] = "prone not allowed";
color[ 2 ] = ( 1, 0, 0 );
}
aboveHead = self getshootatpos() + ( 0, 0, 30 );
offset = ( 0, 0, -10 );
for ( i = 0 ; i < line.size ; i++ )
{
textPos = ( aboveHead[ 0 ] + ( offset[ 0 ] * i ), aboveHead[ 1 ] + ( offset[ 1 ] * i ), aboveHead[ 2 ] + ( offset[ 2 ] * i ) );
print3d( textPos, line[ i ], color[ i ], 1, 0.75 ); // origin, text, RGB, alpha, scale
}
wait 0.05;
}
}
SetupUniqueAnims()
{
if ( !isDefined( self.animplaybackrate ) || !isDefined( self.moveplaybackrate ) )
{
set_anim_playback_rate();
}
}
set_anim_playback_rate()
{
self.animplaybackrate = 0.9 + randomfloat( 0.2 );
self.moveTransitionRate = 0.9 + randomfloat( 0.2 );
self.moveplaybackrate = 1;
self.sideStepRate = 1.35;
}
infiniteLoop( one, two, three, whatever )
{
anim waittill( "new exceptions" );
}
empty( one, two, three, whatever )
{
}
enemyNotify()
{
self endon( "death" );
if ( 1 ) return;
for ( ;; )
{
self waittill( "enemy" );
if ( !isalive( self.enemy ) )
continue;
while ( isplayer( self.enemy ) )
{
if ( hasEnemySightPos() )
level._lastPlayerSighted = gettime();
wait( 2 );
}
}
}
initWindowTraverse()
{
// used to blend the traverse window_down smoothly at the end
level._window_down_height[ 0 ] = -36.8552;
level._window_down_height[ 1 ] = -27.0095;
level._window_down_height[ 2 ] = -15.5981;
level._window_down_height[ 3 ] = -4.37769;
level._window_down_height[ 4 ] = 17.7776;
level._window_down_height[ 5 ] = 59.8499;
level._window_down_height[ 6 ] = 104.808;
level._window_down_height[ 7 ] = 152.325;
level._window_down_height[ 8 ] = 201.052;
level._window_down_height[ 9 ] = 250.244;
level._window_down_height[ 10 ] = 298.971;
level._window_down_height[ 11 ] = 330.681;
}
pre_anim_init()
{
anim.NotFirstTime = true;
anim.useFacialAnims = false;// remove me when facial anims are fixed
maps\_load::init_level_players();
level._player.invul = false;
level._nextGrenadeDrop = randomint( 3 );
level._lastPlayerSighted = 100;
anim.defaultException = animscripts\init_common::empty;
initDeveloperDvars();
setdvar( "scr_expDeathMayMoveCheck", "on" );
maps\_names::setup_names();
anim.animFlagNameIndex = 0;
}
post_anim_init()
{
anim.combatMemoryTimeConst = 10000;
anim.combatMemoryTimeRand = 6000;
initAdvanceToEnemy();
setEnv( "none" );
if ( !isdefined( anim.optionalStepEffectFunction ) )
{
anim.optionalStepEffectSmallFunction = animscripts\shared::playFootStepEffectSmall;
anim.optionalStepEffectFunction = animscripts\shared::playFootStepEffect;
}
if ( !isdefined( anim.optionalStepEffects ) )
anim.optionalStepEffects = [];
if ( !isdefined( anim.optionalStepEffectsSmall ) )
anim.optionalStepEffectsSmall = [];
anim.shootEnemyWrapper_func = ::shootEnemyWrapper_shootNotify;
// scripted mode uses a special function. Faster to use a function pointer based on script than use an if statement in a popular loop.
anim.fire_notetrack_functions[ "scripted" ] = animscripts\shared::fire_straight;
anim.fire_notetrack_functions[ "custom" ] = animscripts\shared::fire_straight;
anim.fire_notetrack_functions[ "cover_right" ] = animscripts\shared::shootNotetrack;
anim.fire_notetrack_functions[ "cover_left" ] = animscripts\shared::shootNotetrack;
anim.fire_notetrack_functions[ "cover_crouch" ] = animscripts\shared::shootNotetrack;
anim.fire_notetrack_functions[ "cover_stand" ] = animscripts\shared::shootNotetrack;
anim.fire_notetrack_functions[ "move" ] = animscripts\shared::shootNotetrack;
// string based array for notetracks
animscripts\shared::registerNoteTracks();
/#
setDvarIfUninitialized( "debug_delta", "off" );
#/
if ( !isdefined( level._flag ) )
common_scripts\utility::init_flags();
maps\_gameskill::setSkill();
level._painAI = undefined;
animscripts\SetPoseMovement::InitPoseMovementFunctions();
animscripts\face::InitLevelFace();
// probabilities of burst fire shots
anim.burstFireNumShots = array( 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5 );
anim.fastBurstFireNumShots = array( 2, 3, 3, 3, 4, 4, 4, 5, 5 );
anim.semiFireNumShots = array( 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 5 );
anim.badPlaces = [];// queue for animscript badplaces
anim.badPlaceInt = 0;// assigns unique names to animscript badplaces since we cant save a badplace as an entity
anim.player = getentarray( "player", "classname" )[ 0 ];
initBattlechatter();
initWindowTraverse();
animscripts\flashed::initFlashed();
animscripts\cqb::setupCQBPointsOfInterest();
initDeaths();
setGlobalAimSettings();
anim.lastCarExplosionTime = -100000;
setupRandomTable();
level._player thread watchReloading();
thread AITurnNotifies();
}
initDeveloperDvars()
{
/#
if ( getdebugdvar( "debug_noanimscripts" ) == "" )
setdvar( "debug_noanimscripts", "off" );
else if ( getdebugdvar( "debug_noanimscripts" ) == "on" )
anim.defaultException = animscripts\init_common::infiniteLoop;
if ( getdebugdvar( "debug_grenadehand" ) == "" )
setdvar( "debug_grenadehand", "off" );
if ( getdebugdvar( "anim_dotshow" ) == "" )
setdvar( "anim_dotshow", "-1" );
if ( getdebugdvar( "anim_debug" ) == "" )
setdvar( "anim_debug", "" );
if ( getdebugdvar( "debug_misstime" ) == "" )
setdvar( "debug_misstime", "" );
#/
}
initBattlechatter()
{
animscripts\squadmanager::init_squadManager();
anim.player thread animscripts\squadManager::addPlayerToSquad();
animscripts\battleChatter::init_battleChatter();
anim.player thread animscripts\battleChatter_ai::addToSystem();
anim thread animscripts\battleChatter::bcsDebugWaiter();
}
initDeaths()
{
anim.numDeathsUntilCrawlingPain = randomintrange( 0, 15 );
anim.numDeathsUntilCornerGrenadeDeath = randomintrange( 0, 10 );
anim.nextCrawlingPainTime = gettime() + randomintrange( 0, 20000 );
anim.nextCrawlingPainTimeFromLegDamage = gettime() + randomintrange( 0, 10000 );
anim.nextCornerGrenadeDeathTime = gettime() + randomintrange( 0, 15000 );
}
initAdvanceToEnemy()
{
// use team ID for now. Should be done per group of AI or something more specific
level._lastAdvanceToEnemyTime = [];
level._lastAdvanceToEnemyTime[ "axis" ] = 0;
level._lastAdvanceToEnemyTime[ "allies" ] = 0;
level._lastAdvanceToEnemyTime[ "team3" ] = 0;
level._lastAdvanceToEnemyTime[ "neutral" ] = 0;
level._lastAdvanceToEnemyDest = [];
level._lastAdvanceToEnemyDest[ "axis" ] = ( 0, 0, 0 );
level._lastAdvanceToEnemyDest[ "allies" ] = ( 0, 0, 0 );
level._lastAdvanceToEnemyDest[ "team3" ] = ( 0, 0, 0 );
level._lastAdvanceToEnemyDest[ "neutral" ] = ( 0, 0, 0 );
level._lastAdvanceToEnemySrc = [];
level._lastAdvanceToEnemySrc[ "axis" ] = ( 0, 0, 0 );
level._lastAdvanceToEnemySrc[ "allies" ] = ( 0, 0, 0 );
level._lastAdvanceToEnemySrc[ "team3" ] = ( 0, 0, 0 );
level._lastAdvanceToEnemySrc[ "neutral" ] = ( 0, 0, 0 );
level._lastAdvanceToEnemyAttacker = [];
level._advanceToEnemyGroup = [];
level._advanceToEnemyGroup[ "axis" ] = 0;
level._advanceToEnemyGroup[ "allies" ] = 0;
level._advanceToEnemyGroup[ "team3" ] = 0;
level._advanceToEnemyGroup[ "neutral" ] = 0;
level._advanceToEnemyInterval = 30000; // how often AI will try to run directly to their enemy if the enemy is not visible
level._advanceToEnemyGroupMax = 3; // group size for AI running to their enemy
}
AITurnNotifies()
{
numTurnsThisFrame = 0;
maxAIPerFrame = 3;
while ( 1 )
{
ai = getAIArray();
if ( ai.size == 0 )
{
wait .05;
numTurnsThisFrame = 0;
continue;
}
for ( i = 0; i < ai.size; i++ )
{
if ( !isdefined( ai[ i ] ) )
continue;
ai[ i ] notify( "do_slow_things" );
numTurnsThisFrame++ ;
if ( numTurnsThisFrame == maxAIPerFrame )
{
wait .05;
numTurnsThisFrame = 0;
}
}
}
}
setNextPlayerGrenadeTime()
{
assert( isPlayer( self ) );
waittillframeend;
// might not be defined if maps\_load::main() wasn't called
if ( isdefined( self.gs.playerGrenadeRangeTime ) )
{
maxTime = int( self.gs.playerGrenadeRangeTime * 0.7 );
if ( maxTime < 1 )
maxTime = 1;
self.grenadeTimers[ "fraggrenade" ] = randomIntRange( 0, maxTime );
self.grenadeTimers[ "flash_grenade" ] = randomIntRange( 0, maxTime );
}
if ( isdefined( self.gs.playerDoubleGrenadeTime ) )
{
maxTime = int( self.gs.playerDoubleGrenadeTime );
minTime = int( maxTime / 2 );
if ( maxTime <= minTime )
maxTime = minTime + 1;
self.grenadeTimers[ "double_grenade" ] = randomIntRange( minTime, maxTime );
}
}
beginGrenadeTracking()
{
self endon( "death" );
for ( ;; )
{
self waittill( "grenade_fire", grenade, weaponName );
grenade thread grenade_earthQuake();
}
}
setupRandomTable()
{
// 60 is chosen because it is divisible by 1,2,3,4,5, and 6,
// and it's also high enough to get some good randomness over different seed values
anim.randomIntTableSize = 60;
// anim.randomIntTable is a permutation of integers 0 through anim.randomIntTableSize - 1
anim.randomIntTable = [];
for ( i = 0; i < anim.randomIntTableSize; i++ )
anim.randomIntTable[ i ] = i;
for ( i = 0; i < anim.randomIntTableSize; i++ )
{
switchwith = randomint( anim.randomIntTableSize );
temp = anim.randomIntTable[ i ];
anim.randomIntTable[ i ] = anim.randomIntTable[ switchwith ];
anim.randomIntTable[ switchwith ] = temp;
}
}
onDeath()
{
self waittill( "death" );
if ( !isdefined( self ) )
{
// we were deleted and we're not running the death script.
// still safe to access our variables as a removed entity though:
if ( isdefined( self.a.usingTurret ) )
self.a.usingTurret delete();
}
}
init_animset_custom_stand( fireAnim, aimStraight, idleAnim, reloadAnim )
{
assert( isdefined( anim.animsets ) && isdefined( anim.animsets.defaultStand ) );
anim.initAnimSet = anim.animsets.defaultStand;
if ( isdefined( aimStraight ) )
anim.initAnimSet[ "straight_level" ] = aimStraight;
if ( isdefined( fireAnim ) )
{
anim.initAnimSet[ "fire" ] = fireAnim;
anim.initAnimSet[ "single" ] = array( fireAnim );
set_animarray_custom_burst_and_semi_fire_stand( fireAnim );
}
if ( isdefined( idleAnim ) )
anim.initAnimSet[ "exposed_idle" ] = array( idleAnim );
if ( isdefined( reloadAnim ) )
{
anim.initAnimSet[ "reload" ] = array( reloadAnim );
anim.initAnimSet[ "reload_crouchhide" ] = array( reloadAnim );
}
self.combatStandAnims = anim.initAnimSet;
}
////////////////////////////////////////////
// Crouch
////////////////////////////////////////////
set_animarray_crouching()
{
if ( usingSidearm() )
animscripts\shared::placeWeaponOn( self.primaryweapon, "right" );
if ( isdefined( self.combatCrouchAnims ) )
{
assert( isArray( self.combatCrouchAnims ) );
self.a.array = self.combatCrouchAnims;
}
else if ( usingRocketLauncher() )
{
self.a.array = anim.animsets.rpgCrouch;
}
else if ( isdefined( self.weapon ) && weapon_pump_action_shotgun() )
{
self.a.array = anim.animsets.shotgunCrouch;
}
else
{
self.a.array = anim.animsets.defaultCrouch;
}
}
////////////////////////////////////////////
// Stand
////////////////////////////////////////////
set_animarray_standing()
{
if ( usingSidearm() )
{
self.a.array = anim.animsets.pistolStand;
}
else if ( isdefined( self.combatStandAnims ) )
{
assert( isArray( self.combatStandAnims ) );
self.a.array = self.combatStandAnims;
}
else if ( isdefined( self.heat ) )
{
self.a.array = anim.animsets.heatStand;
}
else if ( usingRocketLauncher() )
{
self.a.array = anim.animsets.rpgStand;
}
else if ( isdefined( self.weapon ) && weapon_pump_action_shotgun() )
{
self.a.array = anim.animsets.shotgunStand;
}
else if ( self isCQBWalking() )
{
if ( isdefined( self.combatStandCQBAnims ) )
{
assert( isArray( self.combatStandCQBAnims ) );
self.a.array = self.combatStandCQBAnims;
}
else
{
self.a.array = anim.animsets.cqbStand;
}
}
else
{
self.a.array = anim.animsets.defaultStand;
}
}
////////////////////////////////////////////
// Prone
////////////////////////////////////////////
set_animarray_prone()
{
if ( usingSidearm() )
animscripts\shared::placeWeaponOn( self.primaryweapon, "right" );
self.a.array = anim.animsets.defaultProne;
}
MAX_RUN_N_GUN_ANGLE = 130;
RUN_N_GUN_TRANSITION_POINT = 60 / MAX_RUN_N_GUN_ANGLE;
set_animset_run_n_gun()
{
self.maxRunNGunAngle = MAX_RUN_N_GUN_ANGLE;
self.runNGunTransitionPoint = RUN_N_GUN_TRANSITION_POINT;
self.runNGunIncrement = 0.3;
self.runNGunAnims = anim.runNGunAnims;
}
set_ambush_sidestep_anims()
{
assert( isdefined( self.a.moveAnimSet ) );
self.a.moveAnimSet = array_combine_keys( self.a.moveAnimSet, anim.moveAnimSet );
}
set_animarray_custom_burst_and_semi_fire_stand( fireAnim )
{
anim.initAnimSet[ "burst2" ] = fireAnim;
anim.initAnimSet[ "burst3" ] = fireAnim;
anim.initAnimSet[ "burst4" ] = fireAnim;
anim.initAnimSet[ "burst5" ] = fireAnim;
anim.initAnimSet[ "burst6" ] = fireAnim;
anim.initAnimSet[ "semi2" ] = fireAnim;
anim.initAnimSet[ "semi3" ] = fireAnim;
anim.initAnimSet[ "semi4" ] = fireAnim;
anim.initAnimSet[ "semi5" ] = fireAnim;
}
set_animset_complete_custom_stand( completeSet )
{
self.combatStandAnims = completeSet;
}
set_animset_complete_custom_crouch( completeSet )
{
self.combatCrouchAnims = completeSet;
}
clear_custom_animset()
{
self.customMoveAnimSet = undefined;
self.customIdleAnimSet = undefined;
self.combatStandAnims = undefined;
self.combatCrouchAnims = undefined;
self.combatStandCQBAnims = undefined;
self.customTurnAnimSet = undefined;
self.customAnimFunc = undefined;
self.customCoverEnterTrans = undefined;
self.customCoverExitTrans = undefined;
self.customDeathAnimSet = undefined;
self.customPainAnimSet = undefined;
}
addGrenadeThrowAnimOffset( throwAnim, offset )
{
if ( !isdefined( anim.grenadeThrowAnims ) )
{
anim.grenadeThrowAnims = [];
anim.grenadeThrowOffsets = [];
}
assert( anim.grenadeThrowAnims.size == anim.grenadeThrowOffsets.size );
index = anim.grenadeThrowAnims.size;
anim.grenadeThrowAnims[ index ] = throwAnim;
anim.grenadeThrowOffsets[ index ] = offset;
}

View File

@ -0,0 +1,950 @@
#include animscripts\Utility;
#include maps\_utility;
#include animscripts\Combat_utility;
#include common_scripts\Utility;
#using_animtree( "generic_human" );
init_move_transition_arrays()
{
if ( isdefined( anim.move_transition_arrays ) )
return;
anim.move_transition_arrays = 1;
anim.coverTrans = [];
anim.coverExit = [];
anim.maxDirections = [];
anim.excludeDir = [];
anim.traverseInfo = [];
anim.coverTransLongestDist = [];
anim.coverTransDist = [];
anim.coverExitDist = [];
// this is the distance moved to get around corner for 7, 8, 9 directions
anim.coverExitPostDist = [];
// this is the distance moved to get around corner for 7, 8, 9 directions
anim.coverTransPreDist = [];
anim.coverTransAngles = [];
anim.coverExitAngles = [];
anim.coverExitSplit = [];
anim.coverTransSplit = [];
anim.arrivalEndStance = [];
}
initMoveStartStopTransitions()
{
init_move_transition_arrays();
// TEMP, remove this flag
level._newArrivals = true;
transTypes = [];
transTypes[ 0 ] = "left";
transTypes[ 1 ] = "right";
transTypes[ 2 ] = "left_crouch";
transTypes[ 3 ] = "right_crouch";
transTypes[ 4 ] = "crouch";
transTypes[ 5 ] = "stand";
transTypes[ 6 ] = "exposed";
transTypes[ 7 ] = "exposed_crouch";
transTypes[ 8 ] = "stand_saw";
transTypes[ 9 ] = "prone_saw";
transTypes[ 10 ] = "crouch_saw";
transTypes[ 11 ] = "wall_over_40";
transTypes[ 12 ] = "right_cqb";
transTypes[ 13 ] = "right_crouch_cqb";
transTypes[ 14 ] = "left_cqb";
transTypes[ 15 ] = "left_crouch_cqb";
transTypes[ 16 ] = "exposed_cqb";
transTypes[ 17 ] = "exposed_crouch_cqb";
transTypes[ 18 ] = "heat";
transTypes[ 19 ] = "heat_left";
transTypes[ 20 ] = "heat_right";
lastCoverTrans = 6;
// tagJW<NOTE>: Non-lunar movements do not use move transition notes
// Moon_actor's main is called before load, so don't override these if they exist
if ( !isdefined( anim.run_transition_notes ) )
{
anim.cqb_transition_notes = [];
anim.cqb_transition_points = [];
anim.run_transition_notes = [];
anim.run_transition_points = [];
}
anim.approach_types = [];
anim.approach_types[ "Cover Left" ] = [];
anim.approach_types[ "Cover Left" ][ "stand" ] = "left";
anim.approach_types[ "Cover Left" ][ "crouch" ] = "left_crouch";
anim.maxDirections[ "Cover Left" ] = 9;
anim.excludeDir[ "Cover Left" ] = 9;
anim.approach_types[ "Cover Right" ] = [];
anim.approach_types[ "Cover Right" ][ "stand" ] = "right";
anim.approach_types[ "Cover Right" ][ "crouch" ] = "right_crouch";
anim.maxDirections[ "Cover Right" ] = 9;
anim.excludeDir[ "Cover Right" ] = 7;
anim.approach_types[ "Cover Crouch" ] = [];
anim.approach_types[ "Cover Crouch" ][ "stand" ] = "crouch";
anim.approach_types[ "Cover Crouch" ][ "crouch" ] = "crouch";
anim.approach_types[ "Conceal Crouch" ] = anim.approach_types[ "Cover Crouch" ];
anim.approach_types[ "Cover Crouch Window" ] = anim.approach_types[ "Cover Crouch" ];
anim.maxDirections[ "Cover Crouch" ] = 6;
anim.excludeDir[ "Cover Crouch" ] = -1;
anim.maxDirections[ "Conceal Crouch" ] = 6;
anim.excludeDir[ "Conceal Crouch" ] = -1;
anim.approach_types[ "Cover Stand" ] = [];
anim.approach_types[ "Cover Stand" ][ "stand" ] = "stand";
anim.approach_types[ "Cover Stand" ][ "crouch" ] = "stand";
anim.approach_types[ "Conceal Stand" ] = anim.approach_types[ "Cover Stand" ];
anim.maxDirections[ "Cover Stand" ] = 6;
anim.excludeDir[ "Cover Stand" ] = -1;
anim.maxDirections[ "Conceal Stand" ] = 6;
anim.excludeDir[ "Conceal Stand" ] = -1;
anim.approach_types[ "Cover Prone" ] = [];
anim.approach_types[ "Cover Prone" ][ "stand" ] = "exposed";
anim.approach_types[ "Cover Prone" ][ "crouch" ] = "exposed";
anim.approach_types[ "Conceal Prone" ] = anim.approach_types[ "Cover Prone" ];
anim.excludeDir[ "Conceal Prone" ] = -1;
anim.approach_types[ "Path" ] = [];
anim.approach_types[ "Path" ][ "stand" ] = "exposed";
anim.approach_types[ "Path" ][ "crouch" ] = "exposed_crouch";
anim.approach_types[ "Guard" ] = anim.approach_types[ "Path" ];
anim.approach_types[ "Ambush" ] = anim.approach_types[ "Path" ];
anim.approach_types[ "Scripted" ] = anim.approach_types[ "Path" ];
anim.approach_types[ "Custom" ] = anim.approach_types[ "Path" ];
anim.approach_types[ "Exposed" ] = anim.approach_types[ "Path" ];
anim.isCombatPathNode[ "Guard" ] = true;
anim.isCombatPathNode[ "Ambush" ] = true;
anim.isCombatPathNode[ "Exposed" ] = true;
// used by level script to orient AI in certain ways at a node
anim.isCombatScriptNode[ "Guard" ] = true;
anim.isCombatScriptNode[ "Exposed" ] = true;
// CORNER TRANSITIONS ANIMS
// indicies indicate the keyboard numpad directions (8 is forward)
// 7 8 9
// 4 6 <- 5 is invalid
// 1 2 3
/*************************************************
* Entrance Animations
*************************************************/
anim.coverTrans[ "right" ][ 1 ] = %corner_standR_trans_IN_1;
anim.coverTrans[ "right" ][ 2 ] = %corner_standR_trans_IN_2;
anim.coverTrans[ "right" ][ 3 ] = %corner_standR_trans_IN_3;
anim.coverTrans[ "right" ][ 4 ] = %corner_standR_trans_IN_4;
anim.coverTrans[ "right" ][ 6 ] = %corner_standR_trans_IN_6;
//im.coverTrans[ "right" ][ 7 ] = can't approach from this direction;
anim.coverTrans[ "right" ][ 8 ] = %corner_standR_trans_IN_8;
anim.coverTrans[ "right" ][ 9 ] = %corner_standR_trans_IN_9;
anim.coverTrans[ "right_crouch" ][ 1 ] = %CornerCrR_trans_IN_ML;
anim.coverTrans[ "right_crouch" ][ 2 ] = %CornerCrR_trans_IN_M;
anim.coverTrans[ "right_crouch" ][ 3 ] = %CornerCrR_trans_IN_MR;
anim.coverTrans[ "right_crouch" ][ 4 ] = %CornerCrR_trans_IN_L;
anim.coverTrans[ "right_crouch" ][ 6 ] = %CornerCrR_trans_IN_R;
//im.coverTrans[ "right_crouch" ][ 7 ] = can't approach from this direction;
anim.coverTrans[ "right_crouch" ][ 8 ] = %CornerCrR_trans_IN_F;
anim.coverTrans[ "right_crouch" ][ 9 ] = %CornerCrR_trans_IN_MF;
anim.coverTrans[ "right_cqb" ][ 1 ] = %corner_standR_trans_CQB_IN_1;
anim.coverTrans[ "right_cqb" ][ 2 ] = %corner_standR_trans_CQB_IN_2;
anim.coverTrans[ "right_cqb" ][ 3 ] = %corner_standR_trans_CQB_IN_3;
anim.coverTrans[ "right_cqb" ][ 4 ] = %corner_standR_trans_CQB_IN_4;
anim.coverTrans[ "right_cqb" ][ 6 ] = %corner_standR_trans_CQB_IN_6;
//im.coverTrans[ "right_cqb" ][ 7 ] = can't approach from this direction;
anim.coverTrans[ "right_cqb" ][ 8 ] = %corner_standR_trans_CQB_IN_8;
anim.coverTrans[ "right_cqb" ][ 9 ] = %corner_standR_trans_CQB_IN_9;
anim.coverTrans[ "right_crouch_cqb" ][ 1 ] = %CornerCrR_CQB_trans_IN_1;
anim.coverTrans[ "right_crouch_cqb" ][ 2 ] = %CornerCrR_CQB_trans_IN_2;
anim.coverTrans[ "right_crouch_cqb" ][ 3 ] = %CornerCrR_CQB_trans_IN_3;
anim.coverTrans[ "right_crouch_cqb" ][ 4 ] = %CornerCrR_CQB_trans_IN_4;
anim.coverTrans[ "right_crouch_cqb" ][ 6 ] = %CornerCrR_CQB_trans_IN_6;
//im.coverTrans[ "right_crouch_cqb" ][ 7 ] = can't approach from this direction;
anim.coverTrans[ "right_crouch_cqb" ][ 8 ] = %CornerCrR_CQB_trans_IN_8;
anim.coverTrans[ "right_crouch_cqb" ][ 9 ] = %CornerCrR_CQB_trans_IN_9;
anim.coverTrans[ "left" ][ 1 ] = %corner_standL_trans_IN_1;
anim.coverTrans[ "left" ][ 2 ] = %corner_standL_trans_IN_2;
anim.coverTrans[ "left" ][ 3 ] = %corner_standL_trans_IN_3;
anim.coverTrans[ "left" ][ 4 ] = %corner_standL_trans_IN_4;
anim.coverTrans[ "left" ][ 6 ] = %corner_standL_trans_IN_6;
anim.coverTrans[ "left" ][ 7 ] = %corner_standL_trans_IN_7;
anim.coverTrans[ "left" ][ 8 ] = %corner_standL_trans_IN_8;
//im.coverTrans[ "left" ][ 9 ] = can't approach from this direction;
anim.coverTrans[ "left_crouch" ][ 1 ] = %CornerCrL_trans_IN_ML;
anim.coverTrans[ "left_crouch" ][ 2 ] = %CornerCrL_trans_IN_M;
anim.coverTrans[ "left_crouch" ][ 3 ] = %CornerCrL_trans_IN_MR;
anim.coverTrans[ "left_crouch" ][ 4 ] = %CornerCrL_trans_IN_L;
anim.coverTrans[ "left_crouch" ][ 6 ] = %CornerCrL_trans_IN_R;
anim.coverTrans[ "left_crouch" ][ 7 ] = %CornerCrL_trans_IN_MF;
anim.coverTrans[ "left_crouch" ][ 8 ] = %CornerCrL_trans_IN_F;
//im.coverTrans[ "left_crouch" ][ 9 ] = can't approach from this direction;
anim.coverTrans[ "left_cqb" ][ 1 ] = %corner_standL_trans_CQB_IN_1;
anim.coverTrans[ "left_cqb" ][ 2 ] = %corner_standL_trans_CQB_IN_2;
anim.coverTrans[ "left_cqb" ][ 3 ] = %corner_standL_trans_CQB_IN_3;
anim.coverTrans[ "left_cqb" ][ 4 ] = %corner_standL_trans_CQB_IN_4;
anim.coverTrans[ "left_cqb" ][ 6 ] = %corner_standL_trans_CQB_IN_6;
anim.coverTrans[ "left_cqb" ][ 7 ] = %corner_standL_trans_CQB_IN_7;
anim.coverTrans[ "left_cqb" ][ 8 ] = %corner_standL_trans_CQB_IN_8;
//im.coverTrans[ "left_cqb" ][ 9 ] = can't approach from this direction;
anim.coverTrans[ "left_crouch_cqb" ][ 1 ] = %CornerCrL_CQB_trans_IN_1;
anim.coverTrans[ "left_crouch_cqb" ][ 2 ] = %CornerCrL_CQB_trans_IN_2;
anim.coverTrans[ "left_crouch_cqb" ][ 3 ] = %CornerCrL_CQB_trans_IN_3;
anim.coverTrans[ "left_crouch_cqb" ][ 4 ] = %CornerCrL_CQB_trans_IN_4;
anim.coverTrans[ "left_crouch_cqb" ][ 6 ] = %CornerCrL_CQB_trans_IN_6;
anim.coverTrans[ "left_crouch_cqb" ][ 7 ] = %CornerCrL_CQB_trans_IN_7;
anim.coverTrans[ "left_crouch_cqb" ][ 8 ] = %CornerCrL_CQB_trans_IN_8;
//im.coverTrans[ "left_crouch_cqb" ][ 9 ] = can't approach from this direction;
anim.coverTrans[ "crouch" ][ 1 ] = %covercrouch_run_in_ML;
anim.coverTrans[ "crouch" ][ 2 ] = %covercrouch_run_in_M;
anim.coverTrans[ "crouch" ][ 3 ] = %covercrouch_run_in_MR;
anim.coverTrans[ "crouch" ][ 4 ] = %covercrouch_run_in_L;
anim.coverTrans[ "crouch" ][ 6 ] = %covercrouch_run_in_R;
//im.coverTrans[ "crouch" ][ 7 ] = can't approach from this direction;
//im.coverTrans[ "crouch" ][ 8 ] = can't approach from this direction;
//im.coverTrans[ "crouch" ][ 9 ] = can't approach from this direction;
anim.coverTrans[ "stand" ][ 1 ] = %coverstand_trans_IN_ML;
anim.coverTrans[ "stand" ][ 2 ] = %coverstand_trans_IN_M;
anim.coverTrans[ "stand" ][ 3 ] = %coverstand_trans_IN_MR;
anim.coverTrans[ "stand" ][ 4 ] = %coverstand_trans_IN_L;
anim.coverTrans[ "stand" ][ 6 ] = %coverstand_trans_IN_R;
//im.coverTrans[ "stand" ][ 7 ] = can't approach from this direction;
//im.coverTrans[ "stand" ][ 8 ] = can't approach from this direction;
//im.coverTrans[ "stand" ][ 9 ] = can't approach from this direction;
anim.coverTrans[ "stand_saw" ][ 1 ] = %saw_gunner_runin_ML;
anim.coverTrans[ "stand_saw" ][ 2 ] = %saw_gunner_runin_M;
anim.coverTrans[ "stand_saw" ][ 3 ] = %saw_gunner_runin_MR;
anim.coverTrans[ "stand_saw" ][ 4 ] = %saw_gunner_runin_L;
anim.coverTrans[ "stand_saw" ][ 6 ] = %saw_gunner_runin_R;
anim.coverTrans[ "crouch_saw" ][ 1 ] = %saw_gunner_lowwall_runin_ML;
anim.coverTrans[ "crouch_saw" ][ 2 ] = %saw_gunner_lowwall_runin_M;
anim.coverTrans[ "crouch_saw" ][ 3 ] = %saw_gunner_lowwall_runin_MR;
anim.coverTrans[ "crouch_saw" ][ 4 ] = %saw_gunner_lowwall_runin_L;
anim.coverTrans[ "crouch_saw" ][ 6 ] = %saw_gunner_lowwall_runin_R;
anim.coverTrans[ "prone_saw" ][ 1 ] = %saw_gunner_prone_runin_ML;
anim.coverTrans[ "prone_saw" ][ 2 ] = %saw_gunner_prone_runin_M;
anim.coverTrans[ "prone_saw" ][ 3 ] = %saw_gunner_prone_runin_MR;
// we need 45 degree angle approaches for exposed...
anim.coverTrans[ "exposed" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverTrans[ "exposed" ][ 1 ] = %CQB_stop_1;
anim.coverTrans[ "exposed" ][ 2 ] = %run_2_stand_F_6;
anim.coverTrans[ "exposed" ][ 3 ] = %CQB_stop_3;
anim.coverTrans[ "exposed" ][ 4 ] = %run_2_stand_90L;
anim.coverTrans[ "exposed" ][ 6 ] = %run_2_stand_90R;
anim.coverTrans[ "exposed" ][ 7 ] = %CQB_stop_7;
anim.coverTrans[ "exposed" ][ 8 ] = %run_2_stand_180L;
anim.coverTrans[ "exposed" ][ 9 ] = %CQB_stop_9;
anim.coverTrans[ "exposed_crouch" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverTrans[ "exposed_crouch" ][ 1 ] = %CQB_crouch_stop_1;
anim.coverTrans[ "exposed_crouch" ][ 2 ] = %run_2_crouch_F;
anim.coverTrans[ "exposed_crouch" ][ 3 ] = %CQB_crouch_stop_3;
anim.coverTrans[ "exposed_crouch" ][ 4 ] = %run_2_crouch_90L;
anim.coverTrans[ "exposed_crouch" ][ 6 ] = %run_2_crouch_90R;
anim.coverTrans[ "exposed_crouch" ][ 7 ] = %CQB_crouch_stop_7;
anim.coverTrans[ "exposed_crouch" ][ 8 ] = %run_2_crouch_180L;
anim.coverTrans[ "exposed_crouch" ][ 9 ] = %CQB_crouch_stop_9;
anim.coverTrans[ "exposed_cqb" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverTrans[ "exposed_cqb" ][ 1 ] = %CQB_stop_1;
anim.coverTrans[ "exposed_cqb" ][ 2 ] = %CQB_stop_2; // %CQB_stop_2_signal
anim.coverTrans[ "exposed_cqb" ][ 3 ] = %CQB_stop_3;
anim.coverTrans[ "exposed_cqb" ][ 4 ] = %CQB_stop_4;
anim.coverTrans[ "exposed_cqb" ][ 6 ] = %CQB_stop_6;
anim.coverTrans[ "exposed_cqb" ][ 7 ] = %CQB_stop_7;
anim.coverTrans[ "exposed_cqb" ][ 8 ] = %CQB_stop_8;
anim.coverTrans[ "exposed_cqb" ][ 9 ] = %CQB_stop_9;
anim.coverTrans[ "exposed_crouch_cqb" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverTrans[ "exposed_crouch_cqb" ][ 1 ] = %CQB_crouch_stop_1;
anim.coverTrans[ "exposed_crouch_cqb" ][ 2 ] = %CQB_crouch_stop_2;
anim.coverTrans[ "exposed_crouch_cqb" ][ 3 ] = %CQB_crouch_stop_3;
anim.coverTrans[ "exposed_crouch_cqb" ][ 4 ] = %CQB_crouch_stop_4;
anim.coverTrans[ "exposed_crouch_cqb" ][ 6 ] = %CQB_crouch_stop_6;
anim.coverTrans[ "exposed_crouch_cqb" ][ 7 ] = %CQB_crouch_stop_7;
anim.coverTrans[ "exposed_crouch_cqb" ][ 8 ] = %CQB_crouch_stop_8;
anim.coverTrans[ "exposed_crouch_cqb" ][ 9 ] = %CQB_crouch_stop_9;
anim.coverTrans[ "heat" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverTrans[ "heat" ][ 1 ] = %heat_approach_1;
anim.coverTrans[ "heat" ][ 2 ] = %heat_approach_2;
anim.coverTrans[ "heat" ][ 3 ] = %heat_approach_3;
anim.coverTrans[ "heat" ][ 4 ] = %heat_approach_4;
anim.coverTrans[ "heat" ][ 6 ] = %heat_approach_6;
//anim.coverTrans[ "heat" ][ 7 ] = %heat_approach_8;
anim.coverTrans[ "heat" ][ 8 ] = %heat_approach_8;
//anim.coverTrans[ "heat" ][ 9 ] = %heat_approach_8;
anim.coverTrans[ "heat_left" ] = [];
anim.coverTrans[ "heat_right" ] = [];
/*************************************************
* Step in position Animations
*************************************************/
anim.coverStepInAnim = [];
anim.coverStepInAnim[ "right" ] = %corner_standR_trans_B_2_alert;
anim.coverStepInAnim[ "right_crouch" ] = %CornerCrR_trans_B_2_alert;
anim.coverStepInAnim[ "left" ] = %corner_standL_trans_B_2_alert_v2;
anim.coverStepInAnim[ "left_crouch" ] = %CornerCrL_trans_B_2_alert;
anim.coverStepInAnim[ "crouch" ] = %covercrouch_aim_2_hide;
anim.coverStepInAnim[ "stand" ] = %coverstand_aim_2_hide;
anim.coverStepInOffsets = [];
anim.coverStepInAngles = [];
for( i = 0; i < lastCoverTrans; i++ )
{
trans = transTypes[i];
anim.coverStepInOffsets[ trans ] = getMoveDelta( anim.coverStepInAnim[ trans ], 0, 1 );
anim.coverStepInAngles[ trans ] = getAngleDelta( anim.coverStepInAnim[ trans ], 0, 1 );
}
anim.coverStepInAngles[ "right" ] += 90;
anim.coverStepInAngles[ "right_crouch" ] += 90;
anim.coverStepInAngles[ "left" ] -= 90;
anim.coverStepInAngles[ "left_crouch" ] -= 90;
/*************************************************
* Traverse Animations
*************************************************/
anim.coverTrans[ "wall_over_96" ][ 1 ] = %traverse90_IN_ML;
anim.coverTrans[ "wall_over_96" ][ 2 ] = %traverse90_IN_M;
anim.coverTrans[ "wall_over_96" ][ 3 ] = %traverse90_IN_MR;
anim.traverseInfo[ "wall_over_96" ][ "height" ] = 96;
anim.coverTrans[ "wall_over_40" ][ 1 ] = %traverse_window_M_2_run;
anim.coverTrans[ "wall_over_40" ][ 2 ] = %traverse_window_M_2_run;
anim.coverTrans[ "wall_over_40" ][ 3 ] = %traverse_window_M_2_run;
/*
anim.coverTrans["wall_over_40"][1] = %traverse40_IN_ML;
anim.coverTrans["wall_over_40"][2] = %traverse40_IN_M;
anim.coverTrans["wall_over_40"][3] = %traverse40_IN_MR;
*/
/*************************************************
* Exit Animations
*************************************************/
anim.coverExit[ "right" ][ 1 ] = %corner_standR_trans_OUT_1;
anim.coverExit[ "right" ][ 2 ] = %corner_standR_trans_OUT_2;
anim.coverExit[ "right" ][ 3 ] = %corner_standR_trans_OUT_3;
anim.coverExit[ "right" ][ 4 ] = %corner_standR_trans_OUT_4;
anim.coverExit[ "right" ][ 6 ] = %corner_standR_trans_OUT_6;
//im.coverExit[ "right" ][ 7 ] = can't approach from this direction;
anim.coverExit[ "right" ][ 8 ] = %corner_standR_trans_OUT_8;
anim.coverExit[ "right" ][ 9 ] = %corner_standR_trans_OUT_9;
anim.coverExit[ "right_crouch" ][ 1 ] = %CornerCrR_trans_OUT_ML;
anim.coverExit[ "right_crouch" ][ 2 ] = %CornerCrR_trans_OUT_M;
anim.coverExit[ "right_crouch" ][ 3 ] = %CornerCrR_trans_OUT_MR;
anim.coverExit[ "right_crouch" ][ 4 ] = %CornerCrR_trans_OUT_L;
anim.coverExit[ "right_crouch" ][ 6 ] = %CornerCrR_trans_OUT_R;
//im.coverExit[ "right_crouch" ][ 7 ] = can't approach from this direction;
anim.coverExit[ "right_crouch" ][ 8 ] = %CornerCrR_trans_OUT_F;
anim.coverExit[ "right_crouch" ][ 9 ] = %CornerCrR_trans_OUT_MF;
anim.coverExit[ "right_cqb" ][ 1 ] = %corner_standR_trans_CQB_OUT_1;
anim.coverExit[ "right_cqb" ][ 2 ] = %corner_standR_trans_CQB_OUT_2;
anim.coverExit[ "right_cqb" ][ 3 ] = %corner_standR_trans_CQB_OUT_3;
anim.coverExit[ "right_cqb" ][ 4 ] = %corner_standR_trans_CQB_OUT_4;
anim.coverExit[ "right_cqb" ][ 6 ] = %corner_standR_trans_CQB_OUT_6;
//im.coverExit[ "right_cqb" ][ 7 ] = can't approach from this direction;
anim.coverExit[ "right_cqb" ][ 8 ] = %corner_standR_trans_CQB_OUT_8;
anim.coverExit[ "right_cqb" ][ 9 ] = %corner_standR_trans_CQB_OUT_9;
anim.coverExit[ "right_crouch_cqb" ][ 1 ] = %CornerCrR_CQB_trans_OUT_1;
anim.coverExit[ "right_crouch_cqb" ][ 2 ] = %CornerCrR_CQB_trans_OUT_2;
anim.coverExit[ "right_crouch_cqb" ][ 3 ] = %CornerCrR_CQB_trans_OUT_3;
anim.coverExit[ "right_crouch_cqb" ][ 4 ] = %CornerCrR_CQB_trans_OUT_4;
anim.coverExit[ "right_crouch_cqb" ][ 6 ] = %CornerCrR_CQB_trans_OUT_6;
//im.coverExit[ "right_crouch_cqb" ][ 7 ] = can't approach from this direction;
anim.coverExit[ "right_crouch_cqb" ][ 8 ] = %CornerCrR_CQB_trans_OUT_8;
anim.coverExit[ "right_crouch_cqb" ][ 9 ] = %CornerCrR_CQB_trans_OUT_9;
anim.coverExit[ "left" ][ 1 ] = %corner_standL_trans_OUT_1;
anim.coverExit[ "left" ][ 2 ] = %corner_standL_trans_OUT_2;
anim.coverExit[ "left" ][ 3 ] = %corner_standL_trans_OUT_3;
anim.coverExit[ "left" ][ 4 ] = %corner_standL_trans_OUT_4;
anim.coverExit[ "left" ][ 6 ] = %corner_standL_trans_OUT_6;
anim.coverExit[ "left" ][ 7 ] = %corner_standL_trans_OUT_7;
anim.coverExit[ "left" ][ 8 ] = %corner_standL_trans_OUT_8;
//im.coverExit[ "left" ][ 9 ] = can't approach from this direction;
anim.coverExit[ "left_crouch" ][ 1 ] = %CornerCrL_trans_OUT_ML;
anim.coverExit[ "left_crouch" ][ 2 ] = %CornerCrL_trans_OUT_M;
anim.coverExit[ "left_crouch" ][ 3 ] = %CornerCrL_trans_OUT_MR;
anim.coverExit[ "left_crouch" ][ 4 ] = %CornerCrL_trans_OUT_L;
anim.coverExit[ "left_crouch" ][ 6 ] = %CornerCrL_trans_OUT_R;
anim.coverExit[ "left_crouch" ][ 7 ] = %CornerCrL_trans_OUT_MF;
anim.coverExit[ "left_crouch" ][ 8 ] = %CornerCrL_trans_OUT_F;
//im.coverExit[ "left_crouch" ][ 9 ] = can't approach from this direction;
anim.coverExit[ "left_cqb" ][ 1 ] = %corner_standL_trans_CQB_OUT_1;
anim.coverExit[ "left_cqb" ][ 2 ] = %corner_standL_trans_CQB_OUT_2;
anim.coverExit[ "left_cqb" ][ 3 ] = %corner_standL_trans_CQB_OUT_3;
anim.coverExit[ "left_cqb" ][ 4 ] = %corner_standL_trans_CQB_OUT_4;
anim.coverExit[ "left_cqb" ][ 6 ] = %corner_standL_trans_CQB_OUT_6;
anim.coverExit[ "left_cqb" ][ 7 ] = %corner_standL_trans_CQB_OUT_7;
anim.coverExit[ "left_cqb" ][ 8 ] = %corner_standL_trans_CQB_OUT_8;
//im.coverExit[ "left_cqb" ][ 9 ] = can't approach from this direction;
anim.coverExit[ "left_crouch_cqb" ][ 1 ] = %CornerCrL_CQB_trans_OUT_1;
anim.coverExit[ "left_crouch_cqb" ][ 2 ] = %CornerCrL_CQB_trans_OUT_2;
anim.coverExit[ "left_crouch_cqb" ][ 3 ] = %CornerCrL_CQB_trans_OUT_3;
anim.coverExit[ "left_crouch_cqb" ][ 4 ] = %CornerCrL_CQB_trans_OUT_4;
anim.coverExit[ "left_crouch_cqb" ][ 6 ] = %CornerCrL_CQB_trans_OUT_6;
anim.coverExit[ "left_crouch_cqb" ][ 7 ] = %CornerCrL_CQB_trans_OUT_7;
anim.coverExit[ "left_crouch_cqb" ][ 8 ] = %CornerCrL_CQB_trans_OUT_8;
//im.coverExit[ "left_crouch_cqb" ][ 9 ] = can't approach from this direction;
anim.coverExit[ "crouch" ][ 1 ] = %covercrouch_run_out_ML;
anim.coverExit[ "crouch" ][ 2 ] = %covercrouch_run_out_M;
anim.coverExit[ "crouch" ][ 3 ] = %covercrouch_run_out_MR;
anim.coverExit[ "crouch" ][ 4 ] = %covercrouch_run_out_L;
anim.coverExit[ "crouch" ][ 6 ] = %covercrouch_run_out_R;
//im.coverExit[ "crouch" ][ 7 ] = can't approach from this direction;
//im.coverExit[ "crouch" ][ 8 ] = can't approach from this direction;
//im.coverExit[ "crouch" ][ 9 ] = can't approach from this direction;
anim.coverExit[ "stand" ][ 1 ] = %coverstand_trans_OUT_ML;
anim.coverExit[ "stand" ][ 2 ] = %coverstand_trans_OUT_M;
anim.coverExit[ "stand" ][ 3 ] = %coverstand_trans_OUT_MR;
anim.coverExit[ "stand" ][ 4 ] = %coverstand_trans_OUT_L;
anim.coverExit[ "stand" ][ 6 ] = %coverstand_trans_OUT_R;
//im.coverExit[ "stand" ][ 7 ] = can't approach from this direction;
//im.coverExit[ "stand" ][ 8 ] = can't approach from this direction;
//im.coverExit[ "stand" ][ 9 ] = can't approach from this direction;
anim.coverExit[ "stand_saw" ][ 1 ] = %saw_gunner_runout_ML;
anim.coverExit[ "stand_saw" ][ 2 ] = %saw_gunner_runout_M;
anim.coverExit[ "stand_saw" ][ 3 ] = %saw_gunner_runout_MR;
anim.coverExit[ "stand_saw" ][ 4 ] = %saw_gunner_runout_L;
anim.coverExit[ "stand_saw" ][ 6 ] = %saw_gunner_runout_R;
// anim.coverExit["prone_saw" ][1] = %saw_gunner_prone_runout_ML;
anim.coverExit[ "prone_saw" ][ 2 ] = %saw_gunner_prone_runout_M;
// anim.coverExit["prone_saw" ][3] = %saw_gunner_prone_runout_MR;
anim.coverExit[ "prone_saw" ][ 4 ] = %saw_gunner_prone_runout_L;
anim.coverExit[ "prone_saw" ][ 6 ] = %saw_gunner_prone_runout_R;
// anim.coverExit["prone_saw" ][7] = %saw_gunner_prone_runout_F; // need this anim or a way to exclude it
anim.coverExit[ "prone_saw" ][ 8 ] = %saw_gunner_prone_runout_F;
anim.coverExit[ "crouch_saw" ][ 1 ] = %saw_gunner_lowwall_runout_ML;
anim.coverExit[ "crouch_saw" ][ 2 ] = %saw_gunner_lowwall_runout_M;
anim.coverExit[ "crouch_saw" ][ 3 ] = %saw_gunner_lowwall_runout_MR;
anim.coverExit[ "crouch_saw" ][ 4 ] = %saw_gunner_lowwall_runout_L;
anim.coverExit[ "crouch_saw" ][ 6 ] = %saw_gunner_lowwall_runout_R;
// we need 45 degree angle exits for exposed...
anim.coverExit[ "exposed" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverExit[ "exposed" ][ 1 ] = %CQB_start_1;
anim.coverExit[ "exposed" ][ 2 ] = %stand_2_run_180L;
anim.coverExit[ "exposed" ][ 3 ] = %CQB_start_3;
anim.coverExit[ "exposed" ][ 4 ] = %stand_2_run_L;
anim.coverExit[ "exposed" ][ 6 ] = %stand_2_run_R;
anim.coverExit[ "exposed" ][ 7 ] = %CQB_start_7;
anim.coverExit[ "exposed" ][ 8 ] = %surprise_start_v1; // %stand_2_run_F_2;
anim.coverExit[ "exposed" ][ 9 ] = %CQB_start_9;
anim.coverExit[ "exposed_crouch" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverExit[ "exposed_crouch" ][ 1 ] = %CQB_crouch_start_1;
anim.coverExit[ "exposed_crouch" ][ 2 ] = %crouch_2run_180;
anim.coverExit[ "exposed_crouch" ][ 3 ] = %CQB_crouch_start_3;
anim.coverExit[ "exposed_crouch" ][ 4 ] = %crouch_2run_L;
anim.coverExit[ "exposed_crouch" ][ 6 ] = %crouch_2run_R;
anim.coverExit[ "exposed_crouch" ][ 7 ] = %CQB_crouch_start_7;
anim.coverExit[ "exposed_crouch" ][ 8 ] = %crouch_2run_F;
anim.coverExit[ "exposed_crouch" ][ 9 ] = %CQB_crouch_start_9;
anim.coverExit[ "exposed_cqb" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverExit[ "exposed_cqb" ][ 1 ] = %CQB_start_1;
anim.coverExit[ "exposed_cqb" ][ 2 ] = %CQB_start_2;
anim.coverExit[ "exposed_cqb" ][ 3 ] = %CQB_start_3;
anim.coverExit[ "exposed_cqb" ][ 4 ] = %CQB_start_4;
anim.coverExit[ "exposed_cqb" ][ 6 ] = %CQB_start_6;
anim.coverExit[ "exposed_cqb" ][ 7 ] = %CQB_start_7;
anim.coverExit[ "exposed_cqb" ][ 8 ] = %CQB_start_8;
anim.coverExit[ "exposed_cqb" ][ 9 ] = %CQB_start_9;
anim.coverExit[ "exposed_crouch_cqb" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverExit[ "exposed_crouch_cqb" ][ 1 ] = %CQB_crouch_start_1;
anim.coverExit[ "exposed_crouch_cqb" ][ 2 ] = %CQB_crouch_start_2;
anim.coverExit[ "exposed_crouch_cqb" ][ 3 ] = %CQB_crouch_start_3;
anim.coverExit[ "exposed_crouch_cqb" ][ 4 ] = %CQB_crouch_start_4;
anim.coverExit[ "exposed_crouch_cqb" ][ 6 ] = %CQB_crouch_start_6;
anim.coverExit[ "exposed_crouch_cqb" ][ 7 ] = %CQB_crouch_start_7;
anim.coverExit[ "exposed_crouch_cqb" ][ 8 ] = %CQB_crouch_start_8;
anim.coverExit[ "exposed_crouch_cqb" ][ 9 ] = %CQB_crouch_start_9;
anim.coverExit[ "heat" ] = [];
anim.coverExit[ "heat" ][ 1 ] = %heat_exit_1;
anim.coverExit[ "heat" ][ 2 ] = %heat_exit_2;
anim.coverExit[ "heat" ][ 3 ] = %heat_exit_3;
anim.coverExit[ "heat" ][ 4 ] = %heat_exit_4;
anim.coverExit[ "heat" ][ 6 ] = %heat_exit_6; //%heat_exit_6a
anim.coverExit[ "heat" ][ 7 ] = %heat_exit_7;
anim.coverExit[ "heat" ][ 8 ] = %heat_exit_8; //%heat_exit_8a
anim.coverExit[ "heat" ][ 9 ] = %heat_exit_9;
anim.coverExit[ "heat_left" ] = [];
anim.coverExit[ "heat_left" ][ 1 ] = %heat_exit_1;
anim.coverExit[ "heat_left" ][ 2 ] = %heat_exit_2;
anim.coverExit[ "heat_left" ][ 3 ] = %heat_exit_3;
anim.coverExit[ "heat_left" ][ 4 ] = %heat_exit_4;
anim.coverExit[ "heat_left" ][ 6 ] = %heat_exit_6;
anim.coverExit[ "heat_left" ][ 7 ] = %heat_exit_8L;
anim.coverExit[ "heat_left" ][ 8 ] = %heat_exit_8L;
anim.coverExit[ "heat_left" ][ 9 ] = %heat_exit_8R;
anim.coverExit[ "heat_right" ] = [];
anim.coverExit[ "heat_right" ][ 1 ] = %heat_exit_1;
anim.coverExit[ "heat_right" ][ 2 ] = %heat_exit_2;
anim.coverExit[ "heat_right" ][ 3 ] = %heat_exit_3;
anim.coverExit[ "heat_right" ][ 4 ] = %heat_exit_4;
anim.coverExit[ "heat_right" ][ 6 ] = %heat_exit_6;
anim.coverExit[ "heat_right" ][ 7 ] = %heat_exit_8L;
anim.coverExit[ "heat_right" ][ 8 ] = %heat_exit_8R;
anim.coverExit[ "heat_right" ][ 9 ] = %heat_exit_8R;
for ( i = 1; i <= 6; i++ )
{
if ( i == 5 )
continue;
for ( j = 0; j < transTypes.size; j++ )
{
trans = transTypes[ j ];
if ( isdefined( anim.coverTrans[ trans ][ i ] ) )
{
anim.coverTransDist [ trans ][ i ] = getMoveDelta( anim.coverTrans[ trans ][ i ], 0, 1 );
anim.coverTransAngles[ trans ][ i ] = getAngleDelta( anim.coverTrans[ trans ][ i ], 0, 1 );
}
if ( isdefined( anim.coverExit [ trans ] ) && isdefined( anim.coverExit [ trans ][ i ] ) )
{
// get exit dist only to code_move
if ( animHasNotetrack( anim.coverExit[ trans ][ i ], "code_move" ) )
codeMoveTime = getNotetrackTimes( anim.coverExit[ trans ][ i ], "code_move" )[ 0 ];
else
codeMoveTime = 1;
anim.coverExitDist [ trans ][ i ] = getMoveDelta( anim.coverExit [ trans ][ i ], 0, codeMoveTime );
anim.coverExitAngles [ trans ][ i ] = getAngleDelta( anim.coverExit [ trans ][ i ], 0, 1 );
}
}
}
for ( j = 0; j < transTypes.size; j++ )
{
trans = transTypes[ j ];
anim.coverTransLongestDist[ trans ] = 0;
for ( i = 1; i <= 6; i++ )
{
if ( i == 5 || !isdefined( anim.coverTrans[ trans ][ i ] ) )
continue;
lengthSq = lengthSquared( anim.coverTransDist[ trans ][ i ] );
if ( anim.coverTransLongestDist[ trans ] < lengthSq )
anim.coverTransLongestDist[ trans ] = lengthSq;
}
anim.coverTransLongestDist[ trans ] = sqrt( anim.coverTransLongestDist[ trans ] );
}
anim.exposedTransition[ "exposed" ] = true;
anim.exposedTransition[ "exposed_crouch" ] = true;
anim.exposedTransition[ "exposed_cqb" ] = true;
anim.exposedTransition[ "exposed_crouch_cqb" ] = true;
anim.exposedTransition[ "heat" ] = true;
anim.longestExposedApproachDist = 0;
foreach ( trans, transType in anim.exposedTransition )
{
for ( i = 7; i <= 9; i++ )
{
if ( isdefined( anim.coverTrans[ trans ][ i ] ) )
{
anim.coverTransDist [ trans ][ i ] = getMoveDelta( anim.coverTrans[ trans ][ i ], 0, 1 );
anim.coverTransAngles[ trans ][ i ] = getAngleDelta( anim.coverTrans[ trans ][ i ], 0, 1 );
}
if ( isdefined( anim.coverExit [ trans ][ i ] ) )
{
// get exit dist only to code_move
assert( animHasNotetrack( anim.coverExit[ trans ][ i ], "code_move" ) );
codeMoveTime = getNotetrackTimes( anim.coverExit[ trans ][ i ], "code_move" )[ 0 ];
anim.coverExitDist [ trans ][ i ] = getMoveDelta( anim.coverExit [ trans ][ i ], 0, codeMoveTime );
anim.coverExitAngles [ trans ][ i ] = getAngleDelta( anim.coverExit [ trans ][ i ], 0, 1 );
}
}
for ( i = 1; i <= 9; i++ )
{
if ( !isdefined( anim.coverTrans[ trans ][ i ] ) )
continue;
len = length( anim.coverTransDist[ trans ][ i ] );
if ( len > anim.longestExposedApproachDist )
anim.longestExposedApproachDist = len;
}
}
// the FindBestSplitTime calls below are used to find these values.
// all of this is for corner nodes.
anim.coverTransSplit[ "left" ][ 7 ] = 0.369369;// delta of( 35.5356, 3.27114, 0 )
anim.coverTransSplit[ "left_crouch" ][ 7 ] = 0.319319; // delta of (32.2281, 0.356673, 0)
anim.coverTransSplit[ "left_cqb" ][ 7 ] = 0.451451; // delta of (33.1115, 1.05645, 0)
anim.coverTransSplit[ "left_crouch_cqb" ][ 7 ] = 0.246246; // delta of (34.2986, 2.32586, 0)
anim.coverExitSplit[ "left" ][ 7 ] = 0.547548;// delta of( 37.5652, 5.61999, 0 )
anim.coverExitSplit[ "left_crouch" ][ 7 ] = 0.593594;// delta of( 35.9166, 3.88091, 0 )
anim.coverExitSplit[ "left_cqb" ][ 7 ] = 0.702703; // delta of (32.9692, 0.881301, 0)
anim.coverExitSplit[ "left_crouch_cqb" ][ 7 ] = 0.718719; // delta of (33.6642, 1.70904, 0)
anim.coverExitSplit[ "heat_left" ][ 7 ] = 0.42;
anim.coverTransSplit[ "left" ][ 8 ] = 0.525526;// delta of( 32.9863, 0.925748, 0 )
anim.coverTransSplit[ "left_crouch" ][ 8 ] = 0.428428;// delta of( 38.4125, 6.445, 0 )
anim.coverTransSplit[ "left_cqb" ][ 8 ] = 0.479479; // delta of (33.892, 1.86121, 0)
anim.coverTransSplit[ "left_crouch_cqb" ][ 8 ] = 0.33033; // delta of (35.8107, 3.70985, 0)
anim.coverExitSplit[ "left" ][ 8 ] = 0.614615;// delta of( 34.298, 2.26239, 0 )
anim.coverExitSplit[ "left_crouch" ][ 8 ] = 0.451451; // delta of (33.0388, 0.964628, 0)
anim.coverExitSplit[ "left_cqb" ][ 8 ] = 0.439439; // delta of (35.6563, 3.64754, 0))
anim.coverExitSplit[ "left_crouch_cqb" ][ 8 ] = 0.603604; // delta of (33.0797, 1.14774, 0)
anim.coverExitSplit[ "heat_left" ][ 8 ] = 0.42;
anim.coverTransSplit[ "right" ][ 8 ] = 0.458458;// delta of( 35.6571, 3.63511, 0 )
anim.coverTransSplit[ "right_crouch" ][ 8 ] = 0.248248; // delta of (34.6368, 2.67554, 0)
anim.coverTransSplit[ "right_cqb" ][ 8 ] = 0.458458; // delta of (35.6571, 3.63511, 0)
anim.coverTransSplit[ "right_crouch_cqb" ][ 8 ] = 0.311311; // delta of (34.2736, 2.32471, 0)
anim.coverExitSplit[ "right" ][ 8 ] = 0.457457;// delta of( 36.3085, 4.34586, 0 )
anim.coverExitSplit[ "right_crouch" ][ 8 ] = 0.545546; // delta of (33.1181, 1.14301, -0.0001)
anim.coverExitSplit[ "right_cqb" ][ 8 ] = 0.540541; // delta of (33.0089, 1.0005, 0)
anim.coverExitSplit[ "right_crouch_cqb" ][ 8 ] = 0.399399; // delta of (34.7739, 2.41176, 0)
anim.coverExitSplit[ "heat_right" ][ 8 ] = 0.4;
anim.coverTransSplit[ "right" ][ 9 ] = 0.546547;// delta of( 37.7732, 5.76641, 0 )
anim.coverTransSplit[ "right_crouch" ][ 9 ] = 0.2002; // delta of (36.3871, 4.39434, 0)
anim.coverTransSplit[ "right_cqb" ][ 9 ] = 0.546547;// delta of( 37.7732, 5.76641, 0 )
anim.coverTransSplit[ "right_crouch_cqb" ][ 9 ] = 0.232232; // delta of (35.8102, 3.81592, 0)
anim.coverExitSplit[ "right" ][ 9 ] = 0.483483; // delta of (35.251, 3.31115, 0)
anim.coverExitSplit[ "right_crouch" ][ 9 ] = 0.493493; // delta of (34.4959, 2.45688, -0.0001)
anim.coverExitSplit[ "right_cqb" ][ 9 ] = 0.565566; // delta of (35.4487, 3.42926, 0)
anim.coverExitSplit[ "right_crouch_cqb" ][ 9 ] = 0.518519; // delta of (35.4592, 1.47273, 0)
anim.coverExitSplit[ "heat_right" ][ 9 ] = 0.4;
/#
setDvarIfUninitialized( "scr_findsplittimes", "0" );
#/
splitArrivals = [];
splitArrivals[ "left" ] = 1;
splitArrivals[ "left_crouch" ] = 1;
splitArrivals[ "left_crouch_cqb" ] = 1;
splitArrivals[ "left_cqb" ] = 1;
splitExits = [];
splitExits[ "left" ] = 1;
splitExits[ "left_crouch" ] = 1;
splitExits[ "left_crouch_cqb" ] = 1;
splitExits[ "left_cqb" ] = 1;
splitExits[ "heat_left" ] = 1;
GetSplitTimes( 7, 8, false, splitArrivals, splitExits );
splitArrivals = [];
splitArrivals[ "right" ] = 1;
splitArrivals[ "right_crouch" ] = 1;
splitArrivals[ "right_cqb" ] = 1;
splitArrivals[ "right_crouch_cqb" ] = 1;
splitExits = [];
splitExits[ "right" ] = 1;
splitExits[ "right_crouch" ] = 1;
splitExits[ "right_cqb" ] = 1;
splitExits[ "right_crouch_cqb" ] = 1;
splitExits[ "heat_right" ] = 1;
GetSplitTimes( 8, 9, true, splitArrivals, splitExits );
/#
//thread checkApproachAngles( transTypes );
#/
anim.arrivalEndStance["left"] = "stand";
anim.arrivalEndStance["left_cqb"] = "stand";
anim.arrivalEndStance["right"] = "stand";
anim.arrivalEndStance["right_cqb"] = "stand";
anim.arrivalEndStance["stand"] = "stand";
anim.arrivalEndStance["stand_saw"] = "stand";
anim.arrivalEndStance["exposed"] = "stand";
anim.arrivalEndStance["exposed_cqb"] = "stand";
anim.arrivalEndStance["heat"] = "stand";
anim.arrivalEndStance["left_crouch"] = "crouch";
anim.arrivalEndStance["left_crouch_cqb"] = "crouch";
anim.arrivalEndStance["right_crouch"] = "crouch";
anim.arrivalEndStance["right_crouch_cqb"] = "crouch";
anim.arrivalEndStance["crouch_saw"] = "crouch";
anim.arrivalEndStance["crouch"] = "crouch";
anim.arrivalEndStance["exposed_crouch"] = "crouch";
anim.arrivalEndStance["exposed_crouch_cqb"] = "crouch";
anim.arrivalEndStance["prone_saw"] = "prone";
anim.requiredExitStance[ "Cover Stand" ] = "stand";
anim.requiredExitStance[ "Conceal Stand" ] = "stand";
anim.requiredExitStance[ "Cover Crouch" ] = "crouch";
anim.requiredExitStance[ "Conceal Crouch" ] = "crouch";
}
GetSplitTimes( begin, end, isRightSide, splitArrivals, splitExits )
{
for ( i = begin; i <= end; i++ )
{
foreach ( type, val in splitArrivals )
{
anim.coverTransPreDist[ type ][ i ] = getMoveDelta( anim.coverTrans[ type ][ i ], 0, getTransSplitTime( type, i ) );
anim.coverTransDist [ type ][ i ] = getMoveDelta( anim.coverTrans[ type ][ i ], 0, 1 ) - anim.coverTransPreDist[ type ][ i ];
anim.coverTransAngles [ type ][ i ] = getAngleDelta( anim.coverTrans[ type ][ i ], 0, 1 );
}
foreach ( type, val in splitExits )
{
anim.coverExitDist [ type ][ i ] = getMoveDelta( anim.coverExit [ type ][ i ], 0, getExitSplitTime( type, i ) );
anim.coverExitPostDist[ type ][ i ] = getMoveDelta( anim.coverExit [ type ][ i ], 0, 1 ) - anim.coverExitDist[ type ][ i ];
anim.coverExitAngles [ type ][ i ] = getAngleDelta( anim.coverExit [ type ][ i ], 0, 1 );
}
/#
if ( getdebugdvar( "scr_findsplittimes" ) != "0" )
{
foreach ( type, val in splitArrivals )
{
if ( isSubStr( type, "heat" ) )
continue;
FindBestSplitTime( anim.coverTrans[ type ][ i ], true, isRightSide, "anim.coverTransSplit[ \"" + type + "\" ][ " + i + " ]", type + " arrival in dir " + i );
AssertIsValidSplitDelta( DeltaRotate( anim.coverTransDist[ type ][ i ], 180 - anim.coverTransAngles[ type ][ i ] ), isRightSide, type + " arrival in dir " + i );
}
foreach ( type, val in splitExits )
{
if ( isSubStr( type, "heat" ) )
continue;
FindBestSplitTime( anim.coverExit [ type ][ i ], false, isRightSide, "anim.coverExitSplit[ \"" + type + "\" ][ " + i + " ]", type + " exit in dir " + i );
AssertIsValidSplitDelta( anim.coverExitDist[ type ][ i ], isRightSide, type + " exit in dir " + i );
}
}
#/
}
}
/#
FindBestSplitTime( exitanim, isapproach, isright, arrayname, debugname )
{
angleDelta = getAngleDelta( exitanim, 0, 1 );
fullDelta = getMoveDelta( exitanim, 0, 1 );
numiter = 1000;
bestsplit = -1;
bestvalue = -100000000;
bestdelta = ( 0, 0, 0 );
for ( i = 0; i < numiter; i++ )
{
splitTime = 1.0 * i / ( numiter - 1 );
delta = getMoveDelta( exitanim, 0, splitTime );
if ( isapproach )
delta = DeltaRotate( fullDelta - delta, 180 - angleDelta );
if ( isright )
delta = ( delta[ 0 ], 0 - delta[ 1 ], delta[ 2 ] );
val = min( delta[ 0 ] - 32, delta[ 1 ] );
if ( val > bestvalue || bestsplit < 0 )
{
bestvalue = val;
bestsplit = splitTime;
bestdelta = delta;
}
}
if ( bestdelta[ 0 ] < 32 || bestdelta[ 1 ] < 0 )
{
println( "^0 ^1" + debugname + " has no valid split time available! Best was at " + bestsplit + ", delta of " + bestdelta );
return;
}
//println("^0 ^2" + debugname + " has best split time at " + bestsplit + ", delta of " + bestdelta );
println( "^0 ^2" + arrayname + " = " + bestsplit + "; // delta of " + bestdelta );
}
DeltaRotate( delta, yaw )
{
cosine = cos( yaw );
sine = sin( yaw );
return( delta[ 0 ] * cosine - delta[ 1 ] * sine, delta[ 1 ] * cosine + delta[ 0 ] * sine, 0 );
}
AssertIsValidSplitDelta( delta, isRightSide, debugname )
{
if ( isRightSide )
delta = ( delta[ 0 ], 0 - delta[ 1 ], delta[ 2 ] );
// in a delta, x is forward and y is left
// assert the delta goes out far enough from the node
if ( delta[ 0 ] < 32 )
println( "^0 ^1" + debugname + " doesn't go out from the node far enough in the given split time (delta = " + delta + ")" );
// assert the delta doesn't go into the wall
if ( delta[ 1 ] < 0 )
println( "^0 ^1" + debugname + " goes into the wall during the given split time (delta = " + delta + ")" );
}
checkApproachAngles( transTypes )
{
idealTransAngles[ 1 ] = 45;
idealTransAngles[ 2 ] = 0;
idealTransAngles[ 3 ] = -45;
idealTransAngles[ 4 ] = 90;
idealTransAngles[ 6 ] = -90;
idealTransAngles[ 7 ] = 135;
idealTransAngles[ 8 ] = 180;
idealTransAngles[ 9 ] = -135;
wait .05;
for ( i = 1; i <= 9; i++ )
{
for ( j = 0; j < transTypes.size; j++ )
{
trans = transTypes[ j ];
idealAdd = 0;
if ( trans == "left" || trans == "left_crouch" )
idealAdd = 90;
else if ( trans == "right" || trans == "right_crouch" )
idealAdd = -90;
if ( isdefined( anim.coverTransAngles[ trans ][ i ] ) )
{
correctAngle = AngleClamp180( idealTransAngles[ i ] + idealAdd );
actualAngle = AngleClamp180( anim.coverTransAngles[ trans ][ i ] );
if ( AbsAngleClamp180( actualAngle - correctAngle ) > 7 )
{
println( "^1Cover approach animation has bad yaw delta: anim.coverTrans[\"" + trans + "\"][" + i + "]; is ^2" + actualAngle + "^1, should be closer to ^2" + correctAngle + "^1." );
}
}
}
}
for ( i = 1; i <= 9; i++ )
{
for ( j = 0; j < transTypes.size; j++ )
{
trans = transTypes[ j ];
idealAdd = 0;
if ( trans == "left" || trans == "left_crouch" )
idealAdd = 90;
else if ( trans == "right" || trans == "right_crouch" )
idealAdd = -90;
if ( isdefined( anim.coverExitAngles[ trans ][ i ] ) )
{
correctAngle = AngleClamp180( -1 * ( idealTransAngles[ i ] + idealAdd + 180 ) );
actualAngle = AngleClamp180( anim.coverExitAngles[ trans ][ i ] );
if ( AbsAngleClamp180( actualAngle - correctAngle ) > 7 )
{
println( "^1Cover exit animation has bad yaw delta: anim.coverTrans[\"" + trans + "\"][" + i + "]; is ^2" + actualAngle + "^1, should be closer to ^2" + correctAngle + "^1." );
}
}
}
}
}
#/
getExitSplitTime( approachType, dir )
{
exitAnim = anim.coverExit[ approachType ][ dir ];
if ( animHasNotetrack( exitAnim, "split_time" ) )
{
exitAlignTimes = getNotetrackTimes( exitAnim, "split_time" );
assert( exitAlignTimes.size == 1 );
if ( exitAlignTimes.size == 0 )
{
return anim.coverExitSplit[ approachType ][ dir ];
}
return exitAlignTimes[0];
}
return anim.coverExitSplit[ approachType ][ dir ];
}
getTransSplitTime( approachType, dir )
{
arrivalAnim = anim.coverTrans[ approachType ][ dir ];
if ( animHasNotetrack( arrivalAnim, "split_time" ) )
{
arrivalSplitTimes = getNotetrackTimes( arrivalAnim, "split_time" );
assert( arrivalSplitTimes.size == 1 );
if ( arrivalSplitTimes.size == 0 )
{
return anim.coverTransSplit[ approachType ][ dir ];
}
return arrivalSplitTimes[0];
}
return anim.coverTransSplit[ approachType ][ dir ];
}

View File

@ -0,0 +1,638 @@
//****************************************************************************
// **
// Confidential - (C) Activision Publishing, Inc. 2011 **
// **
//****************************************************************************
// **
// Module: Actor locked combat system **
// Created: 7/13/11 - John Webb **
// **
//****************************************************************************
#include common_scripts\utility;
#include animscripts\combat_utility;
#include animscripts\utility;
#using_animtree( "generic_human" );
//*******************************************************************
// *
// *
//*******************************************************************
locked_combat()
{
self notify( "killanimscript" );
self endon( "death" );
self endon( "killanimscript" );
self endon( "locked_combat_transition" );
animscripts\utility::initialize( "locked_combat" );
self.noRunNGun = true;
self.dontMelee = true;
self.disableExits = true;
self.disableArrivals = true;
self.disableBulletWhizbyReaction = true;
self.keepClaimedNode = false;
self.combatMode = "no_cover";
self animmode( "point_relative" );
// Setup the locked covernode
self locked_setup_covernode( level._locked_combat.nodes[ self.current_node_key ] );
// Run the cover behavior
while ( 1 )
{
self [[ level._locked_combat.coverTypes[ self.coverType ].behavior_func ]]();
wait 0.05;
}
}
locked_setup_covernode( node )
{
self.coverNode = node;
self.coverType = self.coverNode.type;
self.a.coverMode = "hide";
self.a.atConcealmentNode = false;
self.locked_combat = true;
self.fixed_node = true; // Need to use something else
self.a.pose = "stand";
self.fixedNode = false;
AssertEx( isdefined( level._locked_combat.coverTypes[ self.coverType ] ), "Locked Combat Cover Type " + self.coverType + " has not been initialized." );
self.hideYawOffset = 0;
self.a.leanAim = undefined;
self [[ level._locked_combat.coverTypes[ self.coverType ].init_func ]]();
locked_combat_orient( self.hideYawOffset );
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_combat_orient( nodeAngleOffset )
{
node = self.coverNode;
self orientmode( "face angle", self.angles[1] );
//self animmode( "point_relative" );
relYaw = AngleClamp180( self.angles[1] - ( node.angles[1] + nodeAngleOffset ) );
self thread maintain_orientation();
}
//*******************************************************************
// *
// *
//*******************************************************************
maintain_orientation()
{
self endon( "killanimscript" );
while ( 1 )
{
self OrientMode( "face angle", self.coverNode.angles[ 1 ] );
wait 0.05;
}
}
//*******************************************************************
// *
// *
//*******************************************************************
get_valid_peekouts()
{
modes = [];
modes[ modes.size ] = "stand";
modes[ modes.size ] = "crouch";
return modes;
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_popUpAndShoot()
{
self.keepClaimedNodeIfValid = true;
locked_combat_orient( self.hideYawOffset );
if ( !locked_pop_up() )
return false;
locked_shoot();
self endFireAndAnimIdleThread();
locked_go_to_hide();
self.coverCrouchLean_aimmode = undefined;
self.keepClaimedNodeIfValid = false;
return true;
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_shoot()
{
self endon( "return_to_cover" );
self maps\_gameskill::didSomethingOtherThanShooting();
while ( 1 )
{
if ( isdefined( self.shouldReturnToCover ) )
break;
if ( !isdefined( self.shootPos ) )
{
assert( !isdefined( self.shootEnt ) );
// give shoot_behavior a chance to iterate
self waittill( "do_slow_things" );
waittillframeend;
if ( isdefined( self.shootPos ) )
{
continue;
}
break;
}
if ( !self.bulletsInClip )
break;
self thread aimIdleThread();
//println( "Shooting" );
shootUntilShootBehaviorChange();
self clearAnim( %add_fire, .2 );
}
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_go_to_hide()
{
self notify( "return_to_cover" );
self.changingCoverPos = true;
self notify( "done_changing_cover_pos" );
self endAimIdleThread();
animRate = 1.0;
//animRate = pop_up_and_hide_speed();
animation = animArray( self.a.coverMode + "_2_hide" );
self clearAnim( %body, 0.2 );
if ( isdefined( self.current_node_key ) )
{
node = level._locked_combat.nodes[ self.current_node_key ];
assert( isdefined( node ) );
self animrelative( "go_to_hide", self.origin, self.angles, animation );
}
//println( "Returning to hide" );
self animscripts\shared::DoNoteTracks( "go_to_hide" );
self StopAnimScripted();
self.a.coverMode = "hide";
self animmode( "point_relative" );
if ( self.coverType == "stand" )
self.a.special = "cover_stand";
else
self.a.special = "cover_crouch";
self.changingCoverPos = false;
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_pop_up()
{
assert( !isdefined( self.a.coverMode ) || self.a.coverMode == "hide" );
newCoverMode = self [[ level._locked_combat.coverTypes[ self.coverType ].cover_mode_func ]]();
if ( !isdefined( newCoverMode ) )
{
//println( "No valid coverMode found" );
return false;
}
//println( "Entering coverMode " + newCoverMode );
timeleft = .1;
popupAnim = animArray( "hide_2_" + newCoverMode );
//if ( !self mayMoveToPoint( getAnimEndPos( popupAnim ) ) )
//return false;
if ( self.script == "cover_crouch" && newCoverMode == "lean" )
self.coverCrouchLean_aimmode = true;
self.a.special = "none";
self.specialDeathFunc = undefined;
if ( self.coverType == "stand" )
self.a.special = "cover_stand_aim";
else if ( self.coverType == "crouch" )
self.a.special = "cover_crouch_aim";
self.changingCoverPos = true;
self notify( "done_changing_cover_pos" );
self animmode( "point_relative" );
animRate = animscripts\cover_wall::pop_up_and_hide_speed();
node = level._locked_combat.nodes[ self.current_node_key ];
assert( isdefined( node ) );
offset_angles = node.angles + ( 0, self.hideYawOffset, 0 );
self animrelative( "pop_up", node.origin, offset_angles, popUpAnim );
self thread animscripts\cover_wall::DoNoteTracksForPopup( "pop_up" );
if ( animHasNoteTrack( popupAnim, "start_aim" ) )
{
// Store our final step out angle so that we may use it when doing track loop aiming
self.stepOutYaw = self.angles[1] + getAngleDelta( popupAnim, 0, 1 );
self waittillmatch( "pop_up", "start_aim" );
timeleft = getAnimLength( popupAnim ) / animRate * ( 1 - self getAnimTime( popupAnim ) );
}
else
{
self waittillmatch( "pop_up", "end" );
timeleft = .1;
}
//self clearAnim( %cover, timeleft + 0.05 );
self.a.coverMode = newCoverMode;
self.a.prevAttack = newCoverMode;
self locked_setup_additive_aim( timeleft );
self thread animscripts\shared::trackShootEntOrPos();
wait( timeleft );
self StopAnimScripted();
//self clearAnim( popupAnim, 0.1 );
if ( self isSniper() )
{
thread animscripts\shoot_behavior::sniper_glint_behavior();
}
self.changingCoverPos = false;
self.coverPosEstablishedTime = gettime();
self notify( "stop_popup_donotetracks" );
return true;
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_setup_additive_aim( transTime )
{
if ( self.a.coverMode == "left" || self.a.coverMode == "right" )
aimCoverMode = "crouch";
else
aimCoverMode = self.a.coverMode;
self setAnimKnobAll( animArray( aimCoverMode + "_aim" ), %body, 1, transTime );
self setanimlimited( animArray( aimCoverMode + "_aim2" ), 1, 0 );
self setanimlimited( animArray( aimCoverMode + "_aim4" ), 1, 0 );
self setanimlimited( animArray( aimCoverMode + "_aim6" ), 1, 0 );
self setanimlimited( animArray( aimCoverMode + "_aim8" ), 1, 0 );
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_aim_idle()
{
self endon( "killanimscript" );
self endon( "end_aim_idle_thread" );
mode = self.a.coverMode;
if ( isdefined( self.a.aimIdleThread ) )
return;
self.a.aimIdleThread = true;
// wait a bit before starting idle since firing will end the idle thread
wait 0.1;
// this used to be setAnim, but it caused problems with turning on its parent nodes when they were supposed to be off (like during pistol pullout).
self setAnimLimited( %add_idle, 1, .2 );
for ( i = 0; ; i++ )
{
flagname = "idle" + i;
idleanim = animArrayPickRandom( mode + "_idle" );
self setFlaggedAnimKnobLimitedRestart( flagname, idleanim, 1, 0.2 );
self waittillmatch( flagname, "end" );
}
self clearAnim( %add_idle, .1 );
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_corner_think( direction, nodeAngleOffset )
{
self.animArrayFuncs[ "exposed" ][ "stand" ] = animscripts\corner::set_standing_animarray_aiming;
self.animArrayFuncs[ "exposed" ][ "crouch" ] = animscripts\corner::set_crouching_animarray_aiming;
if ( IsDefined( self.customAnimFunc ) && IsDefined( self.customAnimFunc[ "corner_exposed" ] ) )
{
if ( IsDefined( self.customAnimFunc[ "corner_exposed" ][ "stand" ] ) )
{
self.animArrayFuncs[ "exposed" ][ "stand" ] = self.customAnimFunc[ "corner_exposed" ][ "stand" ];
}
if ( IsDefined( self.customAnimFunc[ "corner_exposed" ][ "crouch" ] ) )
{
self.animArrayFuncs[ "exposed" ][ "crouch" ] = self.customAnimFunc[ "corner_exposed" ][ "crouch" ];
}
}
self.cornerDirection = direction;
self.a.cornerMode = "unknown";
self.a.aimIdleThread = undefined;
animscripts\cover_behavior::turnToMatchNodeDirection( nodeAngleOffset );
animscripts\corner::set_corner_anim_array();
self.isshooting = false;
self.tracking = false;
self.cornerAiming = false;
animscripts\shared::setAnimAimWeight( 0 );
self.haveGoneToCover = false;
behaviorCallbacks = spawnstruct();
if ( !self.fixedNode )
behaviorCallbacks.moveToNearByCover = animscripts\cover_behavior::moveToNearbyCover;
behaviorCallbacks.mainLoopStart = ::locked_corner_mainLoopStart;
behaviorCallbacks.reload = animscripts\corner::cornerReload;
behaviorCallbacks.leaveCoverAndShoot = animscripts\corner::stepOutAndShootEnemy;
behaviorCallbacks.look = animscripts\corner::lookForEnemy;
behaviorCallbacks.fastlook = animscripts\corner::fastlook;
behaviorCallbacks.idle = animscripts\corner::idle;
behaviorCallbacks.grenade = ::return_false;
behaviorCallbacks.grenadehidden = ::return_false;
behaviorCallbacks.blindfire = animscripts\corner::blindfire;
animscripts\cover_behavior::main( behaviorCallbacks );
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_corner_mainLoopStart()
{
desiredStance = "stand";
/#
if ( getdvarint( "scr_cornerforcecrouch" ) == 1 )
desiredStance = "crouch";
#/
self animscripts\corner::transitionToStance( desiredStance );
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_moveToNearbyCover()
{
return false;
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_reload()
{
return Reload( 2.0, animArray( "reload" ) );
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_look( lookTime )
{
if ( !isdefined( self.a.array[ "hide_to_look" ] ) )
return false;
if ( !locked_peekOut() )
return false;
animscripts\shared::playLookAnimation( animArray( "look_idle" ), lookTime );// TODO: replace
lookanim = undefined;
if ( self isSuppressedWrapper() )
lookanim = animArray( "look_to_hide_fast" );
else
lookanim = animArray( "look_to_hide" );
self setflaggedanimknoballrestart( "looking_end", lookanim, %body, 1, .1 );
animscripts\shared::DoNoteTracks( "looking_end" );
return true;
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_peekOut()
{
if ( isdefined( self.coverNode.script_dontpeek ) )
return false;
// assuming no delta, so no maymovetopoint check
self setFlaggedAnimKnobAll( "looking_start", animArray( "hide_to_look" ), %body, 1, .2 );
animscripts\shared::DoNoteTracks( "looking_start" );
return true;
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_fastlook()
{
self setFlaggedAnimKnobAllRestart( "look", animArrayPickRandom( "look" ), %body, 1, .1 );
self animscripts\shared::DoNoteTracks( "look" );
return true;
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_idle()
{
self endon( "end_idle" );
while ( 1 )
{
useTwitch = ( randomint( 2 ) == 0 && animArrayAnyExist( "hide_idle_twitch" ) );
if ( useTwitch )
idleanim = animArrayPickRandom( "hide_idle_twitch" );
else
idleanim = animarray( "hide_idle" );
locked_playIdleAnimation( idleAnim, useTwitch );
}
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_playIdleAnimation( idleAnim, needsRestart )
{
if ( needsRestart )
self setFlaggedAnimKnobAllRestart( "idle", idleAnim, %body, 1, 0.25, 1 );
else
self setFlaggedAnimKnobAll( "idle", idleAnim, %body, 1, 0.25, 1 );
self.a.coverMode = "hide";
self animscripts\shared::DoNoteTracks( "idle" );
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_flinch()
{
if ( !animArrayAnyExist( "hide_idle_flinch" ) )
return false;
forward = anglesToForward( self.angles );
stepto = self.origin + vector_multiply( forward, -16 );
if ( !self mayMoveToPoint( stepto ) )
return false;
self animmode( "point_relative" );
self.keepClaimedNodeIfValid = true;
flinchanim = animArrayPickRandom( "hide_idle_flinch" );
locked_playIdleAnimation( flinchanim, true );
self.keepClaimedNodeIfValid = false;
return true;
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_blindfire()
{
if ( !animArrayAnyExist( "blind_fire" ) )
return false;
self animMode( "point_relative" );
self.keepClaimedNodeIfValid = true;
self setFlaggedAnimKnobAllRestart( "blindfire", animArrayPickRandom( "blind_fire" ), %body, 1, 0.2, 1 );
self animscripts\shared::DoNoteTracks( "blindfire" );
self.keepClaimedNodeIfValid = false;
return true;
}
//*******************************************************************
// *
// *
//*******************************************************************
return_false( param1 )
{
return false;
}
//*******************************************************************
// *
// *
//*******************************************************************
locked_grenade( throwAt, safe )
{
if ( !isPlayer( throwAt ) ) // Only throw grenades at players for now
{
return false;
}
if ( isdefined( self.dontEverShoot ) || isdefined( throwAt.dontAttackMe ) )
return false;
// We want to only throw locked_combat grenades if the player is trying to hide
if ( !(throwAt should_grenade_player()) )
{
return false;
}
theanim = undefined;
if ( isdefined( safe ) && safe )
theanim = animArrayPickRandom( "grenade_safe" );
else
theanim = animArrayPickRandom( "grenade_exposed" );
threwGrenade = TryGrenade( throwAt, theanim );
return threwGrenade;
}
should_grenade_player()
{
assert( isPlayer( self ) );
assert( isDefined( self.locked_shouldGrenade ) );
return self.locked_shouldGrenade;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
#include animscripts\init_common;
main()
{
prof_begin( "animscript_init" );
pre_first_init();
firstInit();
post_first_init();
prof_end( "animscript_init" );
}
firstInit()
{
// Initialization that should happen once per level
if ( isDefined( anim.NotFirstTime ) )// Use this to trigger the first init
{
return false;
}
pre_anim_init();
animscripts\lunar\animset::init_anim_sets();//lunar version
animscripts\lunar\init_move_transitions::initMoveStartStopTransitions();
anim.lastGibTime = 0;
anim.gibDelay = 3 * 1000; // 3 seconds
anim.minGibs = 2;
anim.maxGibs = 4;
anim.totalGibs = RandomIntRange( anim.minGibs, anim.maxGibs );
post_anim_init();
}

View File

@ -0,0 +1,982 @@
#include animscripts\Utility;
#include maps\_utility;
#include animscripts\Combat_utility;
#include common_scripts\Utility;
#using_animtree( "generic_human" );
//The LUNAR version.
init_move_transition_arrays()
{
if ( isdefined( anim.move_transition_arrays ) )
return;
anim.move_transition_arrays = 1;
anim.coverTrans = [];
anim.coverExit = [];
anim.maxDirections = [];
anim.excludeDir = [];
anim.traverseInfo = [];
anim.coverTransLongestDist = [];
anim.coverTransDist = [];
anim.coverExitDist = [];
// this is the distance moved to get around corner for 7, 8, 9 directions
anim.coverExitPostDist = [];
// this is the distance moved to get around corner for 7, 8, 9 directions
anim.coverTransPreDist = [];
anim.coverTransAngles = [];
anim.coverExitAngles = [];
anim.coverExitSplit = [];
anim.coverTransSplit = [];
anim.arrivalEndStance = [];
}
initMoveStartStopTransitions()
{
init_move_transition_arrays();
// Move transition points
init_moon_transition_points();
// TEMP, remove this flag
level._newArrivals = true;
transTypes = [];
transTypes[ 0 ] = "left";
transTypes[ 1 ] = "right";
transTypes[ 2 ] = "left_crouch";
transTypes[ 3 ] = "right_crouch";
transTypes[ 4 ] = "crouch";
transTypes[ 5 ] = "stand";
transTypes[ 6 ] = "exposed";
transTypes[ 7 ] = "exposed_crouch";
transTypes[ 8 ] = "stand_saw";
transTypes[ 9 ] = "prone_saw";
transTypes[ 10 ] = "crouch_saw";
transTypes[ 11 ] = "wall_over_40";
transTypes[ 12 ] = "right_cqb";
transTypes[ 13 ] = "right_crouch_cqb";
transTypes[ 14 ] = "left_cqb";
transTypes[ 15 ] = "left_crouch_cqb";
transTypes[ 16 ] = "exposed_cqb";
transTypes[ 17 ] = "exposed_crouch_cqb";
transTypes[ 18 ] = "heat";
transTypes[ 19 ] = "heat_left";
transTypes[ 20 ] = "heat_right";
lastCoverTrans = 6;
// tagJW<NOTE>: Non-lunar movements do not use move transition notes
// Moon_actor's main is called before load, so don't override these if they exist
if ( !isdefined( anim.run_transition_notes ) )
{
anim.cqb_transition_notes = [];
anim.cqb_transition_points = [];
anim.run_transition_notes = [];
anim.run_transition_points = [];
}
anim.approach_types = [];
anim.approach_types[ "Cover Left" ] = [];
anim.approach_types[ "Cover Left" ][ "stand" ] = "left";
anim.approach_types[ "Cover Left" ][ "crouch" ] = "left_crouch";
anim.maxDirections[ "Cover Left" ] = 9;
anim.excludeDir[ "Cover Left" ] = 9;
anim.approach_types[ "Cover Right" ] = [];
anim.approach_types[ "Cover Right" ][ "stand" ] = "right";
anim.approach_types[ "Cover Right" ][ "crouch" ] = "right_crouch";
anim.maxDirections[ "Cover Right" ] = 9;
anim.excludeDir[ "Cover Right" ] = 7;
anim.approach_types[ "Cover Crouch" ] = [];
anim.approach_types[ "Cover Crouch" ][ "stand" ] = "crouch";
anim.approach_types[ "Cover Crouch" ][ "crouch" ] = "crouch";
anim.approach_types[ "Conceal Crouch" ] = anim.approach_types[ "Cover Crouch" ];
anim.approach_types[ "Cover Crouch Window" ] = anim.approach_types[ "Cover Crouch" ];
anim.maxDirections[ "Cover Crouch" ] = 6;
anim.excludeDir[ "Cover Crouch" ] = -1;
anim.maxDirections[ "Conceal Crouch" ] = 6;
anim.excludeDir[ "Conceal Crouch" ] = -1;
anim.approach_types[ "Cover Stand" ] = [];
anim.approach_types[ "Cover Stand" ][ "stand" ] = "stand";
anim.approach_types[ "Cover Stand" ][ "crouch" ] = "stand";
anim.approach_types[ "Conceal Stand" ] = anim.approach_types[ "Cover Stand" ];
anim.maxDirections[ "Cover Stand" ] = 6;
anim.excludeDir[ "Cover Stand" ] = -1;
anim.maxDirections[ "Conceal Stand" ] = 6;
anim.excludeDir[ "Conceal Stand" ] = -1;
anim.approach_types[ "Cover Prone" ] = [];
anim.approach_types[ "Cover Prone" ][ "stand" ] = "exposed";
anim.approach_types[ "Cover Prone" ][ "crouch" ] = "exposed";
anim.approach_types[ "Conceal Prone" ] = anim.approach_types[ "Cover Prone" ];
anim.excludeDir[ "Conceal Prone" ] = -1;
anim.approach_types[ "Path" ] = [];
anim.approach_types[ "Path" ][ "stand" ] = "exposed";
anim.approach_types[ "Path" ][ "crouch" ] = "exposed_crouch";
anim.approach_types[ "Guard" ] = anim.approach_types[ "Path" ];
anim.approach_types[ "Ambush" ] = anim.approach_types[ "Path" ];
anim.approach_types[ "Scripted" ] = anim.approach_types[ "Path" ];
anim.approach_types[ "Custom" ] = anim.approach_types[ "Path" ];
anim.approach_types[ "Exposed" ] = anim.approach_types[ "Path" ];
anim.isCombatPathNode[ "Guard" ] = true;
anim.isCombatPathNode[ "Ambush" ] = true;
anim.isCombatPathNode[ "Exposed" ] = true;
// used by level script to orient AI in certain ways at a node
anim.isCombatScriptNode[ "Guard" ] = true;
anim.isCombatScriptNode[ "Exposed" ] = true;
// CORNER TRANSITIONS ANIMS
// indicies indicate the keyboard numpad directions (8 is forward)
// 7 8 9
// 4 6 <- 5 is invalid
// 1 2 3
/*************************************************
* Entrance Animations
*************************************************/
anim.coverTrans[ "right" ][ 1 ] = %tp_moon_coverR_run_2_stand_BL;
anim.coverTrans[ "right" ][ 2 ] = %tp_moon_coverR_run_2_stand_B;
anim.coverTrans[ "right" ][ 3 ] = %tp_moon_coverR_run_2_stand_BR;
anim.coverTrans[ "right" ][ 4 ] = %tp_moon_coverR_run_2_stand_L;
anim.coverTrans[ "right" ][ 6 ] = %tp_moon_coverR_run_2_stand_R;
//im.coverTrans[ "right" ][ 7 ] = can't approach from this direction;
anim.coverTrans[ "right" ][ 8 ] = %tp_moon_coverR_run_2_stand_F;
anim.coverTrans[ "right" ][ 9 ] = %tp_moon_coverR_run_2_stand_FR;
anim.coverTrans[ "right_crouch" ][ 1 ] = %tp_moon_coverR_run_2_crouch_BL;
anim.coverTrans[ "right_crouch" ][ 2 ] = %tp_moon_coverR_run_2_crouch_B;
anim.coverTrans[ "right_crouch" ][ 3 ] = %tp_moon_coverR_run_2_crouch_BR;
anim.coverTrans[ "right_crouch" ][ 4 ] = %tp_moon_coverR_run_2_crouch_L;
anim.coverTrans[ "right_crouch" ][ 6 ] = %tp_moon_coverR_run_2_crouch_R;
//im.coverTrans[ "right_crouch" ][ 7 ] = can't approach from this direction;
anim.coverTrans[ "right_crouch" ][ 8 ] = %tp_moon_coverR_run_2_crouch_F;
anim.coverTrans[ "right_crouch" ][ 9 ] = %tp_moon_coverR_run_2_crouch_FR;
anim.coverTrans[ "right_cqb" ][ 1 ] = %tp_moon_coverR_run_2_stand_BL;
anim.coverTrans[ "right_cqb" ][ 2 ] = %tp_moon_coverR_run_2_stand_B;
anim.coverTrans[ "right_cqb" ][ 3 ] = %tp_moon_coverR_run_2_stand_BR;
anim.coverTrans[ "right_cqb" ][ 4 ] = %tp_moon_coverR_run_2_stand_L;
anim.coverTrans[ "right_cqb" ][ 6 ] = %tp_moon_coverR_run_2_stand_R;
//im.coverTrans[ "right_cqb" ][ 7 ] = can't approach from this direction;
anim.coverTrans[ "right_cqb" ][ 8 ] = %tp_moon_coverR_run_2_stand_F;
anim.coverTrans[ "right_cqb" ][ 9 ] = %tp_moon_coverR_run_2_stand_FR;
anim.coverTrans[ "right_crouch_cqb" ][ 1 ] = %tp_moon_cqb_coverR_run_2_crouch_BL;
anim.coverTrans[ "right_crouch_cqb" ][ 2 ] = %tp_moon_cqb_coverR_run_2_crouch_B;
anim.coverTrans[ "right_crouch_cqb" ][ 3 ] = %tp_moon_cqb_coverR_run_2_crouch_BR;
anim.coverTrans[ "right_crouch_cqb" ][ 4 ] = %tp_moon_cqb_coverR_run_2_crouch_L;
anim.coverTrans[ "right_crouch_cqb" ][ 6 ] = %tp_moon_cqb_coverR_run_2_crouch_R;
//im.coverTrans[ "right_crouch_cqb" ][ 7 ] = can't approach from this direction;
anim.coverTrans[ "right_crouch_cqb" ][ 8 ] = %tp_moon_cqb_coverR_run_2_crouch_F;
anim.coverTrans[ "right_crouch_cqb" ][ 9 ] = %tp_moon_cqb_coverR_run_2_crouch_FR;
anim.coverTrans[ "left" ][ 1 ] = %tp_moon_coverL_run_2_stand_BL;
anim.coverTrans[ "left" ][ 2 ] = %tp_moon_coverL_run_2_stand_B;
anim.coverTrans[ "left" ][ 3 ] = %tp_moon_coverL_run_2_stand_BR;
anim.coverTrans[ "left" ][ 4 ] = %tp_moon_coverL_run_2_stand_L;
anim.coverTrans[ "left" ][ 6 ] = %tp_moon_coverL_run_2_stand_R;
anim.coverTrans[ "left" ][ 7 ] = %tp_moon_coverL_run_2_stand_FL;
anim.coverTrans[ "left" ][ 8 ] = %tp_moon_coverL_run_2_stand_F;
//im.coverTrans[ "left" ][ 9 ] = can't approach from this direction;
anim.coverTrans[ "left_crouch" ][ 1 ] = %tp_moon_coverL_run_2_crouch_BL;
anim.coverTrans[ "left_crouch" ][ 2 ] = %tp_moon_coverL_run_2_crouch_B;
anim.coverTrans[ "left_crouch" ][ 3 ] = %tp_moon_coverL_run_2_crouch_BR;
anim.coverTrans[ "left_crouch" ][ 4 ] = %tp_moon_coverL_run_2_crouch_L;
anim.coverTrans[ "left_crouch" ][ 6 ] = %tp_moon_coverL_run_2_crouch_R;
anim.coverTrans[ "left_crouch" ][ 7 ] = %tp_moon_coverL_run_2_crouch_FL;
anim.coverTrans[ "left_crouch" ][ 8 ] = %tp_moon_coverL_run_2_crouch_F;
//im.coverTrans[ "left_crouch" ][ 9 ] = can't approach from this direction;
anim.coverTrans[ "left_cqb" ][ 1 ] = %tp_moon_coverL_run_2_stand_BL;
anim.coverTrans[ "left_cqb" ][ 2 ] = %tp_moon_coverL_run_2_stand_B;
anim.coverTrans[ "left_cqb" ][ 3 ] = %tp_moon_coverL_run_2_stand_BR;
anim.coverTrans[ "left_cqb" ][ 4 ] = %tp_moon_coverL_run_2_stand_L;
anim.coverTrans[ "left_cqb" ][ 6 ] = %tp_moon_coverL_run_2_stand_R;
anim.coverTrans[ "left_cqb" ][ 7 ] = %tp_moon_coverL_run_2_stand_FL;
anim.coverTrans[ "left_cqb" ][ 8 ] = %tp_moon_coverL_run_2_stand_F;
//im.coverTrans[ "left_cqb" ][ 9 ] = can't approach from this direction;
anim.coverTrans[ "left_crouch_cqb" ][ 1 ] = %tp_moon_cqb_coverL_run_2_crouch_BL;
anim.coverTrans[ "left_crouch_cqb" ][ 2 ] = %tp_moon_cqb_coverL_run_2_crouch_B;
anim.coverTrans[ "left_crouch_cqb" ][ 3 ] = %tp_moon_cqb_coverL_run_2_crouch_BR;
anim.coverTrans[ "left_crouch_cqb" ][ 4 ] = %tp_moon_cqb_coverL_run_2_crouch_L;
anim.coverTrans[ "left_crouch_cqb" ][ 6 ] = %tp_moon_cqb_coverL_run_2_crouch_R;
anim.coverTrans[ "left_crouch_cqb" ][ 7 ] = %tp_moon_cqb_coverL_run_2_crouch_FL;
anim.coverTrans[ "left_crouch_cqb" ][ 8 ] = %tp_moon_cqb_coverL_run_2_crouch_F;
//im.coverTrans[ "left_crouch_cqb" ][ 9 ] = can't approach from this direction;
anim.coverTrans[ "crouch" ][ 1 ] = %tp_moon_coverF_run_2_crouch_BL;
anim.coverTrans[ "crouch" ][ 2 ] = %tp_moon_coverF_run_2_crouch_B;
anim.coverTrans[ "crouch" ][ 3 ] = %tp_moon_coverF_run_2_crouch_BR;
anim.coverTrans[ "crouch" ][ 4 ] = %tp_moon_coverF_run_2_crouch_L;
anim.coverTrans[ "crouch" ][ 6 ] = %tp_moon_coverF_run_2_crouch_R;
//im.coverTrans[ "crouch" ][ 7 ] = can't approach from this direction;
//im.coverTrans[ "crouch" ][ 8 ] = can't approach from this direction;
//im.coverTrans[ "crouch" ][ 9 ] = can't approach from this direction;
anim.coverTrans[ "stand" ][ 1 ] = %tp_moon_coverF_run_2_stand_BL;
anim.coverTrans[ "stand" ][ 2 ] = %tp_moon_coverF_run_2_stand_B;
anim.coverTrans[ "stand" ][ 3 ] = %tp_moon_coverF_run_2_stand_BR;
anim.coverTrans[ "stand" ][ 4 ] = %tp_moon_coverF_run_2_stand_L;
anim.coverTrans[ "stand" ][ 6 ] = %tp_moon_coverF_run_2_stand_R;
//im.coverTrans[ "stand" ][ 7 ] = can't approach from this direction;
//im.coverTrans[ "stand" ][ 8 ] = can't approach from this direction;
//im.coverTrans[ "stand" ][ 9 ] = can't approach from this direction;
anim.coverTrans[ "stand_saw" ][ 1 ] = %saw_gunner_runin_ML;
anim.coverTrans[ "stand_saw" ][ 2 ] = %saw_gunner_runin_M;
anim.coverTrans[ "stand_saw" ][ 3 ] = %saw_gunner_runin_MR;
anim.coverTrans[ "stand_saw" ][ 4 ] = %saw_gunner_runin_L;
anim.coverTrans[ "stand_saw" ][ 6 ] = %saw_gunner_runin_R;
anim.coverTrans[ "crouch_saw" ][ 1 ] = %saw_gunner_lowwall_runin_ML;
anim.coverTrans[ "crouch_saw" ][ 2 ] = %saw_gunner_lowwall_runin_M;
anim.coverTrans[ "crouch_saw" ][ 3 ] = %saw_gunner_lowwall_runin_MR;
anim.coverTrans[ "crouch_saw" ][ 4 ] = %saw_gunner_lowwall_runin_L;
anim.coverTrans[ "crouch_saw" ][ 6 ] = %saw_gunner_lowwall_runin_R;
anim.coverTrans[ "prone_saw" ][ 1 ] = %saw_gunner_prone_runin_ML;
anim.coverTrans[ "prone_saw" ][ 2 ] = %saw_gunner_prone_runin_M;
anim.coverTrans[ "prone_saw" ][ 3 ] = %saw_gunner_prone_runin_MR;
// we need 45 degree angle approaches for exposed...
anim.coverTrans[ "exposed" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverTrans[ "exposed" ][ 1 ] = %tp_moon_exposed_run_2_stand_BL;
anim.coverTrans[ "exposed" ][ 2 ] = %tp_moon_exposed_run_2_stand_B;
anim.coverTrans[ "exposed" ][ 3 ] = %tp_moon_exposed_run_2_stand_BR;
anim.coverTrans[ "exposed" ][ 4 ] = %tp_moon_exposed_run_2_stand_L;
anim.coverTrans[ "exposed" ][ 6 ] = %tp_moon_exposed_run_2_stand_R;
anim.coverTrans[ "exposed" ][ 7 ] = %tp_moon_exposed_run_2_stand_FL;
anim.coverTrans[ "exposed" ][ 8 ] = %tp_moon_exposed_run_2_stand_F;
anim.coverTrans[ "exposed" ][ 9 ] = %tp_moon_exposed_run_2_stand_FR;
anim.coverTrans[ "exposed_crouch" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverTrans[ "exposed_crouch" ][ 1 ] = %tp_moon_exposed_run_2_crouch_BL;
anim.coverTrans[ "exposed_crouch" ][ 2 ] = %tp_moon_exposed_run_2_crouch_B;
anim.coverTrans[ "exposed_crouch" ][ 3 ] = %tp_moon_exposed_run_2_crouch_BR;
anim.coverTrans[ "exposed_crouch" ][ 4 ] = %tp_moon_exposed_run_2_crouch_L;
anim.coverTrans[ "exposed_crouch" ][ 6 ] = %tp_moon_exposed_run_2_crouch_R;
anim.coverTrans[ "exposed_crouch" ][ 7 ] = %tp_moon_exposed_run_2_crouch_FL;
anim.coverTrans[ "exposed_crouch" ][ 8 ] = %tp_moon_exposed_run_2_crouch_F;
anim.coverTrans[ "exposed_crouch" ][ 9 ] = %tp_moon_exposed_run_2_crouch_FR;
anim.coverTrans[ "exposed_cqb" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverTrans[ "exposed_cqb" ][ 1 ] = %tp_moon_cqb_exposed_run_2_stand_BL;
anim.coverTrans[ "exposed_cqb" ][ 2 ] = %tp_moon_cqb_exposed_run_2_stand_B;
anim.coverTrans[ "exposed_cqb" ][ 3 ] = %tp_moon_cqb_exposed_run_2_stand_BR;
anim.coverTrans[ "exposed_cqb" ][ 4 ] = %tp_moon_cqb_exposed_run_2_stand_L;
anim.coverTrans[ "exposed_cqb" ][ 6 ] = %tp_moon_cqb_exposed_run_2_stand_R;
anim.coverTrans[ "exposed_cqb" ][ 7 ] = %tp_moon_cqb_exposed_run_2_stand_FL;
anim.coverTrans[ "exposed_cqb" ][ 8 ] = %tp_moon_cqb_exposed_run_2_stand_F;
anim.coverTrans[ "exposed_cqb" ][ 9 ] = %tp_moon_cqb_exposed_run_2_stand_FR;
anim.coverTrans[ "exposed_crouch_cqb" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverTrans[ "exposed_crouch_cqb" ][ 1 ] = %tp_moon_exposed_run_2_crouch_BL;
anim.coverTrans[ "exposed_crouch_cqb" ][ 2 ] = %tp_moon_exposed_run_2_crouch_B;
anim.coverTrans[ "exposed_crouch_cqb" ][ 3 ] = %tp_moon_exposed_run_2_crouch_BR;
anim.coverTrans[ "exposed_crouch_cqb" ][ 4 ] = %tp_moon_exposed_run_2_crouch_L;
anim.coverTrans[ "exposed_crouch_cqb" ][ 6 ] = %tp_moon_exposed_run_2_crouch_R;
anim.coverTrans[ "exposed_crouch_cqb" ][ 7 ] = %tp_moon_exposed_run_2_crouch_FL;
anim.coverTrans[ "exposed_crouch_cqb" ][ 8 ] = %tp_moon_exposed_run_2_crouch_F;
anim.coverTrans[ "exposed_crouch_cqb" ][ 9 ] = %tp_moon_exposed_run_2_crouch_FR;
anim.coverTrans[ "heat" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverTrans[ "heat" ][ 1 ] = %heat_approach_1;
anim.coverTrans[ "heat" ][ 2 ] = %heat_approach_2;
anim.coverTrans[ "heat" ][ 3 ] = %heat_approach_3;
anim.coverTrans[ "heat" ][ 4 ] = %heat_approach_4;
anim.coverTrans[ "heat" ][ 6 ] = %heat_approach_6;
//anim.coverTrans[ "heat" ][ 7 ] = %heat_approach_8;
anim.coverTrans[ "heat" ][ 8 ] = %heat_approach_8;
//anim.coverTrans[ "heat" ][ 9 ] = %heat_approach_8;
anim.coverTrans[ "heat_left" ] = [];
anim.coverTrans[ "heat_right" ] = [];
/*************************************************
* Step in position Animations
*************************************************/
anim.coverStepInAnim = [];
anim.coverStepInAnim[ "right" ] = %corner_standR_trans_B_2_alert;
anim.coverStepInAnim[ "right_crouch" ] = %CornerCrR_trans_B_2_alert;
anim.coverStepInAnim[ "left" ] = %corner_standL_trans_B_2_alert_v2;
anim.coverStepInAnim[ "left_crouch" ] = %CornerCrL_trans_B_2_alert;
anim.coverStepInAnim[ "crouch" ] = %covercrouch_aim_2_hide;
anim.coverStepInAnim[ "stand" ] = %coverstand_aim_2_hide;
anim.coverStepInOffsets = [];
anim.coverStepInAngles = [];
for( i = 0; i < lastCoverTrans; i++ )
{
trans = transTypes[i];
anim.coverStepInOffsets[ trans ] = getMoveDelta( anim.coverStepInAnim[ trans ], 0, 1 );
anim.coverStepInAngles[ trans ] = getAngleDelta( anim.coverStepInAnim[ trans ], 0, 1 );
}
anim.coverStepInAngles[ "right" ] += 90;
anim.coverStepInAngles[ "right_crouch" ] += 90;
anim.coverStepInAngles[ "left" ] -= 90;
anim.coverStepInAngles[ "left_crouch" ] -= 90;
/*************************************************
* Traverse Animations
*************************************************/
anim.coverTrans[ "wall_over_96" ][ 1 ] = %traverse90_IN_ML;
anim.coverTrans[ "wall_over_96" ][ 2 ] = %traverse90_IN_M;
anim.coverTrans[ "wall_over_96" ][ 3 ] = %traverse90_IN_MR;
anim.traverseInfo[ "wall_over_96" ][ "height" ] = 96;
anim.coverTrans[ "wall_over_40" ][ 1 ] = %traverse_window_M_2_run;
anim.coverTrans[ "wall_over_40" ][ 2 ] = %traverse_window_M_2_run;
anim.coverTrans[ "wall_over_40" ][ 3 ] = %traverse_window_M_2_run;
/*
anim.coverTrans["wall_over_40"][1] = %traverse40_IN_ML;
anim.coverTrans["wall_over_40"][2] = %traverse40_IN_M;
anim.coverTrans["wall_over_40"][3] = %traverse40_IN_MR;
*/
/*************************************************
* Exit Animations
*************************************************/
anim.coverExit[ "right" ][ 1 ] = %tp_moon_coverR_stand_2_run_BL;
anim.coverExit[ "right" ][ 2 ] = %tp_moon_coverR_stand_2_run_B;
anim.coverExit[ "right" ][ 3 ] = %tp_moon_coverR_stand_2_run_BR;
anim.coverExit[ "right" ][ 4 ] = %tp_moon_coverR_stand_2_run_L;
anim.coverExit[ "right" ][ 6 ] = %tp_moon_coverR_stand_2_run_R;
//im.coverExit[ "right" ][ 7 ] = can't approach from this direction;
anim.coverExit[ "right" ][ 8 ] = %tp_moon_coverR_stand_2_run_F;
anim.coverExit[ "right" ][ 9 ] = %tp_moon_coverR_stand_2_run_FR;
anim.coverExit[ "right_crouch" ][ 1 ] = %tp_moon_coverR_crouch_2_run_BL;
anim.coverExit[ "right_crouch" ][ 2 ] = %tp_moon_coverR_crouch_2_run_B;
anim.coverExit[ "right_crouch" ][ 3 ] = %tp_moon_coverR_crouch_2_run_BR;
anim.coverExit[ "right_crouch" ][ 4 ] = %tp_moon_coverR_crouch_2_run_L;
anim.coverExit[ "right_crouch" ][ 6 ] = %tp_moon_coverR_crouch_2_run_R;
//im.coverExit[ "right_crouch" ][ 7 ] = can't approach from this direction;
anim.coverExit[ "right_crouch" ][ 8 ] = %tp_moon_coverR_crouch_2_run_F;
anim.coverExit[ "right_crouch" ][ 9 ] = %tp_moon_coverR_crouch_2_run_FR;
anim.coverExit[ "right_cqb" ][ 1 ] = %tp_moon_coverR_stand_2_run_BL;
anim.coverExit[ "right_cqb" ][ 2 ] = %tp_moon_coverR_stand_2_run_B;
anim.coverExit[ "right_cqb" ][ 3 ] = %tp_moon_coverR_stand_2_run_BR;
anim.coverExit[ "right_cqb" ][ 4 ] = %tp_moon_coverR_stand_2_run_L;
anim.coverExit[ "right_cqb" ][ 6 ] = %tp_moon_coverR_stand_2_run_R;
//im.coverExit[ "right_cqb" ][ 7 ] = can't approach from this direction;
anim.coverExit[ "right_cqb" ][ 8 ] = %tp_moon_coverR_stand_2_run_F;
anim.coverExit[ "right_cqb" ][ 9 ] = %tp_moon_coverR_stand_2_run_FR;
anim.coverExit[ "right_crouch_cqb" ][ 1 ] = %tp_moon_cqb_coverR_crouch_2_run_BL;
anim.coverExit[ "right_crouch_cqb" ][ 2 ] = %tp_moon_cqb_coverR_crouch_2_run_B;
anim.coverExit[ "right_crouch_cqb" ][ 3 ] = %tp_moon_cqb_coverR_crouch_2_run_BR;
anim.coverExit[ "right_crouch_cqb" ][ 4 ] = %tp_moon_cqb_coverR_crouch_2_run_L;
anim.coverExit[ "right_crouch_cqb" ][ 6 ] = %tp_moon_cqb_coverR_crouch_2_run_R;
//im.coverExit[ "right_crouch_cqb" ][ 7 ] = can't approach from this direction;
anim.coverExit[ "right_crouch_cqb" ][ 8 ] = %tp_moon_cqb_coverR_crouch_2_run_F;
anim.coverExit[ "right_crouch_cqb" ][ 9 ] = %tp_moon_cqb_coverR_crouch_2_run_FR;
anim.coverExit[ "left" ][ 1 ] = %tp_moon_coverL_stand_2_run_BL;
anim.coverExit[ "left" ][ 2 ] = %tp_moon_coverL_stand_2_run_B;
anim.coverExit[ "left" ][ 3 ] = %tp_moon_coverL_stand_2_run_BR;
anim.coverExit[ "left" ][ 4 ] = %tp_moon_coverL_stand_2_run_L;
anim.coverExit[ "left" ][ 6 ] = %tp_moon_coverL_stand_2_run_R;
anim.coverExit[ "left" ][ 7 ] = %tp_moon_coverL_stand_2_run_FL;
anim.coverExit[ "left" ][ 8 ] = %tp_moon_coverL_stand_2_run_F;
//im.coverExit[ "left" ][ 9 ] = can't approach from this direction;
anim.coverExit[ "left_crouch" ][ 1 ] = %tp_moon_coverL_crouch_2_run_BL;
anim.coverExit[ "left_crouch" ][ 2 ] = %tp_moon_coverL_crouch_2_run_B;
anim.coverExit[ "left_crouch" ][ 3 ] = %tp_moon_coverL_crouch_2_run_BR;
anim.coverExit[ "left_crouch" ][ 4 ] = %tp_moon_coverL_crouch_2_run_L;
anim.coverExit[ "left_crouch" ][ 6 ] = %tp_moon_coverL_crouch_2_run_R;
anim.coverExit[ "left_crouch" ][ 7 ] = %tp_moon_coverL_crouch_2_run_FL;
anim.coverExit[ "left_crouch" ][ 8 ] = %tp_moon_coverL_crouch_2_run_F;
//im.coverExit[ "left_crouch" ][ 9 ] = can't approach from this direction;
anim.coverExit[ "left_cqb" ][ 1 ] = %tp_moon_coverL_stand_2_run_BL;
anim.coverExit[ "left_cqb" ][ 2 ] = %tp_moon_coverL_stand_2_run_B;
anim.coverExit[ "left_cqb" ][ 3 ] = %tp_moon_coverL_stand_2_run_BR;
anim.coverExit[ "left_cqb" ][ 4 ] = %tp_moon_coverL_stand_2_run_L;
anim.coverExit[ "left_cqb" ][ 6 ] = %tp_moon_coverL_stand_2_run_R;
anim.coverExit[ "left_cqb" ][ 7 ] = %tp_moon_coverL_stand_2_run_FL;
anim.coverExit[ "left_cqb" ][ 8 ] = %tp_moon_coverL_stand_2_run_F;
//im.coverExit[ "left_cqb" ][ 9 ] = can't approach from this direction;
anim.coverExit[ "left_crouch_cqb" ][ 1 ] = %tp_moon_cqb_coverL_crouch_2_run_BL;
anim.coverExit[ "left_crouch_cqb" ][ 2 ] = %tp_moon_cqb_coverL_crouch_2_run_B;
anim.coverExit[ "left_crouch_cqb" ][ 3 ] = %tp_moon_cqb_coverL_crouch_2_run_BR;
anim.coverExit[ "left_crouch_cqb" ][ 4 ] = %tp_moon_cqb_coverL_crouch_2_run_L;
anim.coverExit[ "left_crouch_cqb" ][ 6 ] = %tp_moon_cqb_coverL_crouch_2_run_R;
anim.coverExit[ "left_crouch_cqb" ][ 7 ] = %tp_moon_cqb_coverL_crouch_2_run_FL;
anim.coverExit[ "left_crouch_cqb" ][ 8 ] = %tp_moon_cqb_coverL_crouch_2_run_F;
//im.coverExit[ "left_crouch_cqb" ][ 9 ] = can't approach from this direction;
anim.coverExit[ "crouch" ][ 1 ] = %tp_moon_coverF_crouch_2_run_BL;
anim.coverExit[ "crouch" ][ 2 ] = %tp_moon_coverF_crouch_2_run_B;
anim.coverExit[ "crouch" ][ 3 ] = %tp_moon_coverF_crouch_2_run_BR;
anim.coverExit[ "crouch" ][ 4 ] = %tp_moon_coverF_crouch_2_run_L;
anim.coverExit[ "crouch" ][ 6 ] = %tp_moon_coverF_crouch_2_run_R;
//im.coverExit[ "crouch" ][ 7 ] = can't approach from this direction;
//im.coverExit[ "crouch" ][ 8 ] = can't approach from this direction;
//im.coverExit[ "crouch" ][ 9 ] = can't approach from this direction;
anim.coverExit[ "stand" ][ 1 ] = %tp_moon_coverF_stand_2_run_BL;
anim.coverExit[ "stand" ][ 2 ] = %tp_moon_coverF_stand_2_run_B;
anim.coverExit[ "stand" ][ 3 ] = %tp_moon_coverF_stand_2_run_BR;
anim.coverExit[ "stand" ][ 4 ] = %tp_moon_coverF_stand_2_run_L;
anim.coverExit[ "stand" ][ 6 ] = %tp_moon_coverF_stand_2_run_R;
//im.coverExit[ "stand" ][ 7 ] = can't approach from this direction;
//im.coverExit[ "stand" ][ 8 ] = can't approach from this direction;
//im.coverExit[ "stand" ][ 9 ] = can't approach from this direction;
anim.coverExit[ "stand_saw" ][ 1 ] = %saw_gunner_runout_ML;
anim.coverExit[ "stand_saw" ][ 2 ] = %saw_gunner_runout_M;
anim.coverExit[ "stand_saw" ][ 3 ] = %saw_gunner_runout_MR;
anim.coverExit[ "stand_saw" ][ 4 ] = %saw_gunner_runout_L;
anim.coverExit[ "stand_saw" ][ 6 ] = %saw_gunner_runout_R;
// anim.coverExit["prone_saw" ][1] = %saw_gunner_prone_runout_ML;
anim.coverExit[ "prone_saw" ][ 2 ] = %saw_gunner_prone_runout_M;
// anim.coverExit["prone_saw" ][3] = %saw_gunner_prone_runout_MR;
anim.coverExit[ "prone_saw" ][ 4 ] = %saw_gunner_prone_runout_L;
anim.coverExit[ "prone_saw" ][ 6 ] = %saw_gunner_prone_runout_R;
// anim.coverExit["prone_saw" ][7] = %saw_gunner_prone_runout_F; // need this anim or a way to exclude it
anim.coverExit[ "prone_saw" ][ 8 ] = %saw_gunner_prone_runout_F;
anim.coverExit[ "crouch_saw" ][ 1 ] = %saw_gunner_lowwall_runout_ML;
anim.coverExit[ "crouch_saw" ][ 2 ] = %saw_gunner_lowwall_runout_M;
anim.coverExit[ "crouch_saw" ][ 3 ] = %saw_gunner_lowwall_runout_MR;
anim.coverExit[ "crouch_saw" ][ 4 ] = %saw_gunner_lowwall_runout_L;
anim.coverExit[ "crouch_saw" ][ 6 ] = %saw_gunner_lowwall_runout_R;
// we need 45 degree angle exits for exposed...
anim.coverExit[ "exposed" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverExit[ "exposed" ][ 1 ] = %tp_moon_exposed_stand_2_run_BL;
anim.coverExit[ "exposed" ][ 2 ] = %tp_moon_exposed_stand_2_run_B;
anim.coverExit[ "exposed" ][ 3 ] = %tp_moon_exposed_stand_2_run_BR;
anim.coverExit[ "exposed" ][ 4 ] = %tp_moon_exposed_stand_2_run_L;
anim.coverExit[ "exposed" ][ 6 ] = %tp_moon_exposed_stand_2_run_R;
anim.coverExit[ "exposed" ][ 7 ] = %tp_moon_exposed_stand_2_run_FL;
anim.coverExit[ "exposed" ][ 8 ] = %tp_moon_exposed_stand_2_run_F; // %stand_2_run_F_2;
anim.coverExit[ "exposed" ][ 9 ] = %tp_moon_exposed_stand_2_run_FR;
anim.coverExit[ "exposed_crouch" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverExit[ "exposed_crouch" ][ 1 ] = %tp_moon_exposed_crouch_2_run_BL;
anim.coverExit[ "exposed_crouch" ][ 2 ] = %tp_moon_exposed_crouch_2_run_B;
anim.coverExit[ "exposed_crouch" ][ 3 ] = %tp_moon_exposed_crouch_2_run_BR;
anim.coverExit[ "exposed_crouch" ][ 4 ] = %tp_moon_exposed_crouch_2_run_L;
anim.coverExit[ "exposed_crouch" ][ 6 ] = %tp_moon_exposed_crouch_2_run_R;
anim.coverExit[ "exposed_crouch" ][ 7 ] = %tp_moon_exposed_crouch_2_run_FL;
anim.coverExit[ "exposed_crouch" ][ 8 ] = %tp_moon_exposed_crouch_2_run_F;
anim.coverExit[ "exposed_crouch" ][ 9 ] = %tp_moon_exposed_crouch_2_run_FR;
anim.coverExit[ "exposed_cqb" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverExit[ "exposed_cqb" ][ 1 ] = %tp_moon_cqb_exposed_stand_2_run_BL;
anim.coverExit[ "exposed_cqb" ][ 2 ] = %tp_moon_cqb_exposed_stand_2_run_B;
anim.coverExit[ "exposed_cqb" ][ 3 ] = %tp_moon_cqb_exposed_stand_2_run_BR;
anim.coverExit[ "exposed_cqb" ][ 4 ] = %tp_moon_cqb_exposed_stand_2_run_L;
anim.coverExit[ "exposed_cqb" ][ 6 ] = %tp_moon_cqb_exposed_stand_2_run_R;
anim.coverExit[ "exposed_cqb" ][ 7 ] = %tp_moon_cqb_exposed_stand_2_run_FL;
anim.coverExit[ "exposed_cqb" ][ 8 ] = %tp_moon_cqb_exposed_stand_2_run_F;
anim.coverExit[ "exposed_cqb" ][ 9 ] = %tp_moon_cqb_exposed_stand_2_run_FR;
anim.coverExit[ "exposed_crouch_cqb" ] = [];// need this or it chokes on the next line due to assigning undefined...
anim.coverExit[ "exposed_crouch_cqb" ][ 1 ] = %tp_moon_exposed_crouch_2_run_BL;
anim.coverExit[ "exposed_crouch_cqb" ][ 2 ] = %tp_moon_exposed_crouch_2_run_B;
anim.coverExit[ "exposed_crouch_cqb" ][ 3 ] = %tp_moon_exposed_crouch_2_run_BR;
anim.coverExit[ "exposed_crouch_cqb" ][ 4 ] = %tp_moon_exposed_crouch_2_run_L;
anim.coverExit[ "exposed_crouch_cqb" ][ 6 ] = %tp_moon_exposed_crouch_2_run_R;
anim.coverExit[ "exposed_crouch_cqb" ][ 7 ] = %tp_moon_exposed_crouch_2_run_FL;
anim.coverExit[ "exposed_crouch_cqb" ][ 8 ] = %tp_moon_exposed_crouch_2_run_F;
anim.coverExit[ "exposed_crouch_cqb" ][ 9 ] = %tp_moon_exposed_crouch_2_run_FR;
anim.coverExit[ "heat" ] = [];
anim.coverExit[ "heat" ][ 1 ] = %heat_exit_1;
anim.coverExit[ "heat" ][ 2 ] = %heat_exit_2;
anim.coverExit[ "heat" ][ 3 ] = %heat_exit_3;
anim.coverExit[ "heat" ][ 4 ] = %heat_exit_4;
anim.coverExit[ "heat" ][ 6 ] = %heat_exit_6; //%heat_exit_6a
anim.coverExit[ "heat" ][ 7 ] = %heat_exit_7;
anim.coverExit[ "heat" ][ 8 ] = %heat_exit_8; //%heat_exit_8a
anim.coverExit[ "heat" ][ 9 ] = %heat_exit_9;
anim.coverExit[ "heat_left" ] = [];
anim.coverExit[ "heat_left" ][ 1 ] = %heat_exit_1;
anim.coverExit[ "heat_left" ][ 2 ] = %heat_exit_2;
anim.coverExit[ "heat_left" ][ 3 ] = %heat_exit_3;
anim.coverExit[ "heat_left" ][ 4 ] = %heat_exit_4;
anim.coverExit[ "heat_left" ][ 6 ] = %heat_exit_6;
anim.coverExit[ "heat_left" ][ 7 ] = %heat_exit_8L;
anim.coverExit[ "heat_left" ][ 8 ] = %heat_exit_8L;
anim.coverExit[ "heat_left" ][ 9 ] = %heat_exit_8R;
anim.coverExit[ "heat_right" ] = [];
anim.coverExit[ "heat_right" ][ 1 ] = %heat_exit_1;
anim.coverExit[ "heat_right" ][ 2 ] = %heat_exit_2;
anim.coverExit[ "heat_right" ][ 3 ] = %heat_exit_3;
anim.coverExit[ "heat_right" ][ 4 ] = %heat_exit_4;
anim.coverExit[ "heat_right" ][ 6 ] = %heat_exit_6;
anim.coverExit[ "heat_right" ][ 7 ] = %heat_exit_8L;
anim.coverExit[ "heat_right" ][ 8 ] = %heat_exit_8R;
anim.coverExit[ "heat_right" ][ 9 ] = %heat_exit_8R;
for ( i = 1; i <= 6; i++ )
{
if ( i == 5 )
continue;
for ( j = 0; j < transTypes.size; j++ )
{
trans = transTypes[ j ];
if ( isdefined( anim.coverTrans[ trans ][ i ] ) )
{
anim.coverTransDist [ trans ][ i ] = getMoveDelta( anim.coverTrans[ trans ][ i ], 0, 1 );
anim.coverTransAngles[ trans ][ i ] = getAngleDelta( anim.coverTrans[ trans ][ i ], 0, 1 );
}
if ( isdefined( anim.coverExit [ trans ] ) && isdefined( anim.coverExit [ trans ][ i ] ) )
{
// get exit dist only to code_move
if ( animHasNotetrack( anim.coverExit[ trans ][ i ], "code_move" ) )
codeMoveTime = getNotetrackTimes( anim.coverExit[ trans ][ i ], "code_move" )[ 0 ];
else
codeMoveTime = 1;
anim.coverExitDist [ trans ][ i ] = getMoveDelta( anim.coverExit [ trans ][ i ], 0, codeMoveTime );
anim.coverExitAngles [ trans ][ i ] = getAngleDelta( anim.coverExit [ trans ][ i ], 0, 1 );
}
}
}
for ( j = 0; j < transTypes.size; j++ )
{
trans = transTypes[ j ];
anim.coverTransLongestDist[ trans ] = 0;
for ( i = 1; i <= 6; i++ )
{
if ( i == 5 || !isdefined( anim.coverTrans[ trans ][ i ] ) )
continue;
lengthSq = lengthSquared( anim.coverTransDist[ trans ][ i ] );
if ( anim.coverTransLongestDist[ trans ] < lengthSq )
anim.coverTransLongestDist[ trans ] = lengthSq;
}
anim.coverTransLongestDist[ trans ] = sqrt( anim.coverTransLongestDist[ trans ] );
}
anim.exposedTransition[ "exposed" ] = true;
anim.exposedTransition[ "exposed_crouch" ] = true;
anim.exposedTransition[ "exposed_cqb" ] = true;
anim.exposedTransition[ "exposed_crouch_cqb" ] = true;
anim.exposedTransition[ "heat" ] = true;
anim.longestExposedApproachDist = 0;
foreach ( trans, transType in anim.exposedTransition )
{
for ( i = 7; i <= 9; i++ )
{
if ( isdefined( anim.coverTrans[ trans ][ i ] ) )
{
anim.coverTransDist [ trans ][ i ] = getMoveDelta( anim.coverTrans[ trans ][ i ], 0, 1 );
anim.coverTransAngles[ trans ][ i ] = getAngleDelta( anim.coverTrans[ trans ][ i ], 0, 1 );
}
if ( isdefined( anim.coverExit [ trans ][ i ] ) )
{
// get exit dist only to code_move
assert( animHasNotetrack( anim.coverExit[ trans ][ i ], "code_move" ) );
codeMoveTime = getNotetrackTimes( anim.coverExit[ trans ][ i ], "code_move" )[ 0 ];
anim.coverExitDist [ trans ][ i ] = getMoveDelta( anim.coverExit [ trans ][ i ], 0, codeMoveTime );
anim.coverExitAngles [ trans ][ i ] = getAngleDelta( anim.coverExit [ trans ][ i ], 0, 1 );
}
}
for ( i = 1; i <= 9; i++ )
{
if ( !isdefined( anim.coverTrans[ trans ][ i ] ) )
continue;
len = length( anim.coverTransDist[ trans ][ i ] );
if ( len > anim.longestExposedApproachDist )
anim.longestExposedApproachDist = len;
}
}
// the FindBestSplitTime calls below are used to find these values.
// all of this is for corner nodes.
anim.coverTransSplit[ "left" ][ 7 ] = 0.5;// delta of( 35.5356, 3.27114, 0 )
anim.coverTransSplit[ "left_crouch" ][ 7 ] = 0.448; // delta of (32.2281, 0.356673, 0)
anim.coverTransSplit[ "left_cqb" ][ 7 ] = 0.5; // delta of (33.1115, 1.05645, 0)
anim.coverTransSplit[ "left_crouch_cqb" ][ 7 ] = 0.448; // delta of (34.2986, 2.32586, 0)
anim.coverExitSplit[ "left" ][ 7 ] = 0.52;// delta of( 37.5652, 5.61999, 0 )
anim.coverExitSplit[ "left_crouch" ][ 7 ] = 0.55;// delta of( 35.9166, 3.88091, 0 )
anim.coverExitSplit[ "left_cqb" ][ 7 ] = 0.52; // delta of (32.9692, 0.881301, 0)
anim.coverExitSplit[ "left_crouch_cqb" ][ 7 ] = 0.55; // delta of (33.6642, 1.70904, 0)
anim.coverExitSplit[ "heat_left" ][ 7 ] = 0.42;
anim.coverTransSplit[ "left" ][ 8 ] = 0.38;// delta of( 32.9863, 0.925748, 0 )
anim.coverTransSplit[ "left_crouch" ][ 8 ] = 0.5;// delta of( 38.4125, 6.445, 0 )
anim.coverTransSplit[ "left_cqb" ][ 8 ] = 0.38; // delta of (33.892, 1.86121, 0)
anim.coverTransSplit[ "left_crouch_cqb" ][ 8 ] = 0.5; // delta of (35.8107, 3.70985, 0)
anim.coverExitSplit[ "left" ][ 8 ] = 0.442;// delta of( 34.298, 2.26239, 0 )
anim.coverExitSplit[ "left_crouch" ][ 8 ] = 0.6; // delta of (33.0388, 0.964628, 0)
anim.coverExitSplit[ "left_cqb" ][ 8 ] = 0.442; // delta of (35.6563, 3.64754, 0))
anim.coverExitSplit[ "left_crouch_cqb" ][ 8 ] = 0.6; // delta of (33.0797, 1.14774, 0)
anim.coverExitSplit[ "heat_left" ][ 8 ] = 0.42;
anim.coverTransSplit[ "right" ][ 8 ] = 0.561562;// delta of( 35.6571, 3.63511, 0 )
anim.coverTransSplit[ "right_crouch" ][ 8 ] = 0.521522; // delta of (34.6368, 2.67554, 0)
anim.coverTransSplit[ "right_cqb" ][ 8 ] = 0.561562; // delta of (35.6571, 3.63511, 0)
anim.coverTransSplit[ "right_crouch_cqb" ][ 8 ] = 0.521522; // delta of (34.2736, 2.32471, 0)
anim.coverExitSplit[ "right" ][ 8 ] = 0.316316;// delta of( 36.3085, 4.34586, 0 )
anim.coverExitSplit[ "right_crouch" ][ 8 ] = 0.386386; // delta of (33.1181, 1.14301, -0.0001)
anim.coverExitSplit[ "right_cqb" ][ 8 ] = 0.316316; // delta of (33.0089, 1.0005, 0)
anim.coverExitSplit[ "right_crouch_cqb" ][ 8 ] = 0.386386; // delta of (34.7739, 2.41176, 0)
anim.coverExitSplit[ "heat_right" ][ 8 ] = 0.4;
anim.coverTransSplit[ "right" ][ 9 ] = 0.41041;// delta of( 37.7732, 5.76641, 0 )
anim.coverTransSplit[ "right_crouch" ][ 9 ] = 0.518519; // delta of (36.3871, 4.39434, 0)
anim.coverTransSplit[ "right_cqb" ][ 9 ] = 0.41041;// delta of( 37.7732, 5.76641, 0 )
anim.coverTransSplit[ "right_crouch_cqb" ][ 9 ] = 0.232232518519; // delta of (35.8102, 3.81592, 0)
anim.coverExitSplit[ "right" ][ 9 ] = 0.365365; // delta of (35.251, 3.31115, 0)
anim.coverExitSplit[ "right_crouch" ][ 9 ] = 0.376376; // delta of (34.4959, 2.45688, -0.0001)
anim.coverExitSplit[ "right_cqb" ][ 9 ] = 0.365365; // delta of (35.4487, 3.42926, 0)
anim.coverExitSplit[ "right_crouch_cqb" ][ 9 ] = 0.376376; // delta of (35.4592, 1.47273, 0)
anim.coverExitSplit[ "heat_right" ][ 9 ] = 0.4;
/#
setDvarIfUninitialized( "scr_findsplittimes", "0" );
#/
splitArrivals = [];
splitArrivals[ "left" ] = 1;
splitArrivals[ "left_crouch" ] = 1;
splitArrivals[ "left_crouch_cqb" ] = 1;
splitArrivals[ "left_cqb" ] = 1;
splitExits = [];
splitExits[ "left" ] = 1;
splitExits[ "left_crouch" ] = 1;
splitExits[ "left_crouch_cqb" ] = 1;
splitExits[ "left_cqb" ] = 1;
splitExits[ "heat_left" ] = 1;
GetSplitTimes( 7, 8, false, splitArrivals, splitExits );
splitArrivals = [];
splitArrivals[ "right" ] = 1;
splitArrivals[ "right_crouch" ] = 1;
splitArrivals[ "right_cqb" ] = 1;
splitArrivals[ "right_crouch_cqb" ] = 1;
splitExits = [];
splitExits[ "right" ] = 1;
splitExits[ "right_crouch" ] = 1;
splitExits[ "right_cqb" ] = 1;
splitExits[ "right_crouch_cqb" ] = 1;
splitExits[ "heat_right" ] = 1;
GetSplitTimes( 8, 9, true, splitArrivals, splitExits );
/#
//thread checkApproachAngles( transTypes );
#/
anim.arrivalEndStance["left"] = "stand";
anim.arrivalEndStance["left_cqb"] = "stand";
anim.arrivalEndStance["right"] = "stand";
anim.arrivalEndStance["right_cqb"] = "stand";
anim.arrivalEndStance["stand"] = "stand";
anim.arrivalEndStance["stand_saw"] = "stand";
anim.arrivalEndStance["exposed"] = "stand";
anim.arrivalEndStance["exposed_cqb"] = "stand";
anim.arrivalEndStance["heat"] = "stand";
anim.arrivalEndStance["left_crouch"] = "crouch";
anim.arrivalEndStance["left_crouch_cqb"] = "crouch";
anim.arrivalEndStance["right_crouch"] = "crouch";
anim.arrivalEndStance["right_crouch_cqb"] = "crouch";
anim.arrivalEndStance["crouch_saw"] = "crouch";
anim.arrivalEndStance["crouch"] = "crouch";
anim.arrivalEndStance["exposed_crouch"] = "crouch";
anim.arrivalEndStance["exposed_crouch_cqb"] = "crouch";
anim.arrivalEndStance["prone_saw"] = "prone";
anim.requiredExitStance[ "Cover Stand" ] = "stand";
anim.requiredExitStance[ "Conceal Stand" ] = "stand";
anim.requiredExitStance[ "Cover Crouch" ] = "crouch";
anim.requiredExitStance[ "Conceal Crouch" ] = "crouch";
}
GetSplitTimes( begin, end, isRightSide, splitArrivals, splitExits )
{
for ( i = begin; i <= end; i++ )
{
foreach ( type, val in splitArrivals )
{
anim.coverTransPreDist[ type ][ i ] = getMoveDelta( anim.coverTrans[ type ][ i ], 0, getTransSplitTime( type, i ) );
anim.coverTransDist [ type ][ i ] = getMoveDelta( anim.coverTrans[ type ][ i ], 0, 1 ) - anim.coverTransPreDist[ type ][ i ];
anim.coverTransAngles [ type ][ i ] = getAngleDelta( anim.coverTrans[ type ][ i ], 0, 1 );
}
foreach ( type, val in splitExits )
{
anim.coverExitDist [ type ][ i ] = getMoveDelta( anim.coverExit [ type ][ i ], 0, getExitSplitTime( type, i ) );
anim.coverExitPostDist[ type ][ i ] = getMoveDelta( anim.coverExit [ type ][ i ], 0, 1 ) - anim.coverExitDist[ type ][ i ];
anim.coverExitAngles [ type ][ i ] = getAngleDelta( anim.coverExit [ type ][ i ], 0, 1 );
}
/#
if ( getdebugdvar( "scr_findsplittimes" ) != "0" )
{
foreach ( type, val in splitArrivals )
{
if ( isSubStr( type, "heat" ) )
continue;
FindBestSplitTime( anim.coverTrans[ type ][ i ], true, isRightSide, "anim.coverTransSplit[ \"" + type + "\" ][ " + i + " ]", type + " arrival in dir " + i );
AssertIsValidSplitDelta( DeltaRotate( anim.coverTransDist[ type ][ i ], 180 - anim.coverTransAngles[ type ][ i ] ), isRightSide, type + " arrival in dir " + i );
}
foreach ( type, val in splitExits )
{
if ( isSubStr( type, "heat" ) )
continue;
FindBestSplitTime( anim.coverExit [ type ][ i ], false, isRightSide, "anim.coverExitSplit[ \"" + type + "\" ][ " + i + " ]", type + " exit in dir " + i );
AssertIsValidSplitDelta( anim.coverExitDist[ type ][ i ], isRightSide, type + " exit in dir " + i );
}
}
#/
}
}
/#
FindBestSplitTime( exitanim, isapproach, isright, arrayname, debugname )
{
angleDelta = getAngleDelta( exitanim, 0, 1 );
fullDelta = getMoveDelta( exitanim, 0, 1 );
numiter = 1000;
bestsplit = -1;
bestvalue = -100000000;
bestdelta = ( 0, 0, 0 );
for ( i = 0; i < numiter; i++ )
{
splitTime = 1.0 * i / ( numiter - 1 );
delta = getMoveDelta( exitanim, 0, splitTime );
if ( isapproach )
delta = DeltaRotate( fullDelta - delta, 180 - angleDelta );
if ( isright )
delta = ( delta[ 0 ], 0 - delta[ 1 ], delta[ 2 ] );
val = min( delta[ 0 ] - 32, delta[ 1 ] );
if ( val > bestvalue || bestsplit < 0 )
{
bestvalue = val;
bestsplit = splitTime;
bestdelta = delta;
}
}
if ( bestdelta[ 0 ] < 32 || bestdelta[ 1 ] < 0 )
{
println( "^0 ^1" + debugname + " has no valid split time available! Best was at " + bestsplit + ", delta of " + bestdelta );
return;
}
//println("^0 ^2" + debugname + " has best split time at " + bestsplit + ", delta of " + bestdelta );
println( "^0 ^2" + arrayname + " = " + bestsplit + "; // delta of " + bestdelta );
}
DeltaRotate( delta, yaw )
{
cosine = cos( yaw );
sine = sin( yaw );
return( delta[ 0 ] * cosine - delta[ 1 ] * sine, delta[ 1 ] * cosine + delta[ 0 ] * sine, 0 );
}
AssertIsValidSplitDelta( delta, isRightSide, debugname )
{
if ( isRightSide )
delta = ( delta[ 0 ], 0 - delta[ 1 ], delta[ 2 ] );
// in a delta, x is forward and y is left
// assert the delta goes out far enough from the node
if ( delta[ 0 ] < 32 )
println( "^0 ^1" + debugname + " doesn't go out from the node far enough in the given split time (delta = " + delta + ")" );
// assert the delta doesn't go into the wall
if ( delta[ 1 ] < 0 )
println( "^0 ^1" + debugname + " goes into the wall during the given split time (delta = " + delta + ")" );
}
checkApproachAngles( transTypes )
{
idealTransAngles[ 1 ] = 45;
idealTransAngles[ 2 ] = 0;
idealTransAngles[ 3 ] = -45;
idealTransAngles[ 4 ] = 90;
idealTransAngles[ 6 ] = -90;
idealTransAngles[ 7 ] = 135;
idealTransAngles[ 8 ] = 180;
idealTransAngles[ 9 ] = -135;
wait .05;
for ( i = 1; i <= 9; i++ )
{
for ( j = 0; j < transTypes.size; j++ )
{
trans = transTypes[ j ];
idealAdd = 0;
if ( trans == "left" || trans == "left_crouch" )
idealAdd = 90;
else if ( trans == "right" || trans == "right_crouch" )
idealAdd = -90;
if ( isdefined( anim.coverTransAngles[ trans ][ i ] ) )
{
correctAngle = AngleClamp180( idealTransAngles[ i ] + idealAdd );
actualAngle = AngleClamp180( anim.coverTransAngles[ trans ][ i ] );
if ( AbsAngleClamp180( actualAngle - correctAngle ) > 7 )
{
println( "^1Cover approach animation has bad yaw delta: anim.coverTrans[\"" + trans + "\"][" + i + "]; is ^2" + actualAngle + "^1, should be closer to ^2" + correctAngle + "^1." );
}
}
}
}
for ( i = 1; i <= 9; i++ )
{
for ( j = 0; j < transTypes.size; j++ )
{
trans = transTypes[ j ];
idealAdd = 0;
if ( trans == "left" || trans == "left_crouch" )
idealAdd = 90;
else if ( trans == "right" || trans == "right_crouch" )
idealAdd = -90;
if ( isdefined( anim.coverExitAngles[ trans ][ i ] ) )
{
correctAngle = AngleClamp180( -1 * ( idealTransAngles[ i ] + idealAdd + 180 ) );
actualAngle = AngleClamp180( anim.coverExitAngles[ trans ][ i ] );
if ( AbsAngleClamp180( actualAngle - correctAngle ) > 7 )
{
println( "^1Cover exit animation has bad yaw delta: anim.coverTrans[\"" + trans + "\"][" + i + "]; is ^2" + actualAngle + "^1, should be closer to ^2" + correctAngle + "^1." );
}
}
}
}
}
#/
getExitSplitTime( approachType, dir )
{
exitAnim = anim.coverExit[ approachType ][ dir ];
if ( animHasNotetrack( exitAnim, "split_time" ) )
{
exitAlignTimes = getNotetrackTimes( exitAnim, "split_time" );
assert( exitAlignTimes.size == 1 );
if ( exitAlignTimes.size == 0 )
{
return anim.coverExitSplit[ approachType ][ dir ];
}
return exitAlignTimes[0];
}
return anim.coverExitSplit[ approachType ][ dir ];
}
getTransSplitTime( approachType, dir )
{
arrivalAnim = anim.coverTrans[ approachType ][ dir ];
if ( animHasNotetrack( arrivalAnim, "split_time" ) )
{
arrivalSplitTimes = getNotetrackTimes( arrivalAnim, "split_time" );
assert( arrivalSplitTimes.size == 1 );
if ( arrivalSplitTimes.size == 0 )
{
return anim.coverTransSplit[ approachType ][ dir ];
}
return arrivalSplitTimes[0];
}
return anim.coverTransSplit[ approachType ][ dir ];
}
init_moon_transition_points()
{
anim.run_transition_notes = [];
anim.run_transition_points = [];
anim.run_transition_notes[ anim.run_transition_notes.size ] = "move_transition_run_r_down";
anim.run_transition_points[ anim.run_transition_points.size ] = 0.2537;
anim.run_transition_notes[ anim.run_transition_notes.size ] = "move_transition_run_l_down";
anim.run_transition_points[ anim.run_transition_points.size ] = 0.5074;
anim.cqb_transition_notes = [];
anim.cqb_transition_points = [];
//entrance for starting the loop at a run with the right foot down
anim.cqb_transition_notes[ anim.cqb_transition_notes.size ] = "move_transition_run_r_down";
anim.cqb_transition_points[ anim.cqb_transition_points.size ] = 0.48;
anim.cqb_transition_notes[ anim.cqb_transition_notes.size ] = "move_transition_run_l_down";
anim.cqb_transition_points[ anim.cqb_transition_points.size ] = 0.24;
anim.cqb_transition_notes[ anim.cqb_transition_notes.size ] = "move_transition_start 2";
anim.cqb_transition_points[ anim.cqb_transition_points.size ] = 0.6;
}

1748
animscripts/melee.gsc Normal file

File diff suppressed because it is too large Load Diff

1231
animscripts/move.gsc Normal file

File diff suppressed because it is too large Load Diff

1614
animscripts/pain.gsc Normal file

File diff suppressed because it is too large Load Diff

396
animscripts/reactions.gsc Normal file
View File

@ -0,0 +1,396 @@
#include animscripts\SetPoseMovement;
#include animscripts\Utility;
#include common_scripts\Utility;
#using_animtree( "generic_human" );
main()
{
self endon( "killanimscript" );
animscripts\utility::initialize( "reactions" );
self newEnemySurprisedReaction();
}
getReactionAnim( name )
{
if ( IsDefined( self.customCoverReactions ) && IsDefined( self.customCoverReactions[ name ] ) )
{
return self.customCoverReactions[ name ];
}
else
{
return anim.reactionAnimArray[ name ];
}
}
///////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////
reactionsCheckLoop()
{
self thread bulletWhizbyCheckLoop();
}
///////////////////////////////////////////////////////////////////////////
// death reactions
///////////////////////////////////////////////////////////////////////////
/* disabled for now since the animations aren't in common csv
MoveDeathReaction()
{
// Decide what pose to use
desiredPose = self animscripts\utility::choosePose();
if ( desiredPose == "stand" )
{
deathAnim = getDeathReactionAnim();
DoDeathReactionAnim( deathAnim );
}
}
ExposedCombatDeathReaction()
{
// Decide what pose to use
desiredPose = self animscripts\utility::choosePose();
if ( desiredPose == "stand" )
{
deathAnim = getDeathReactionAnim();
DoDeathReactionAnim( deathAnim );
}
}
DoDeathReactionAnim( deathAnim )
{
self endon( "movemode" );
rate = self.moveplaybackrate;
self setFlaggedAnimKnobAll( "deathanim", deathAnim, %body, 1, 1, rate, true );
self animscripts\shared::DoNoteTracks( "deathanim" );
self.deathTeamate = false;
}
getDeathReactionAnim()
{
if ( self.deathTeamateReaction == "back" )
return %run_reaction_180;
else if ( self.deathTeamateReaction == "left" )
return %run_reaction_L_quick;
else if ( self.deathTeamateReaction == "right" )
return %run_reaction_R_quick;
}
deathCheck()
{
self endon( "killanimscript" );
self.deathTeamateReaction = "none";
self.deathTeamate = false;
minDeathDistance = 100;
maxDeathDistance = 500;
minGoalDistance = 200;
maxTurnAngle = 135;
minTurnAngle = 10;
self AddAIEventListener( "death" );
for ( ;; )
{
self waittill( "ai_event", event, originator, position );
if ( event != "death" )
continue;
deathDirection = position - self.origin;
deathDistance = Length( deathDirection );
if ( deathDistance >= minDeathDistance && deathDistance <= maxDeathDistance )
{
goalDirection = self.goalpos - self.origin;
goalDistance = Length( goalDirection );
if ( goalDistance >= minGoalDistance )
{
goalAngles = VectorToAngles( goalDirection );
deltaAngles = Abs( self.angles[1] - goalAngles[1] );
if ( deltaAngles > minTurnAngle )
{
if ( deltaAngles > maxTurnAngle )
self.deathTeamateReaction = "back";
else if ( self.angles[1] > goalAngles[1] )
self.deathTeamateReaction = "left";
else
self.deathTeamateReaction = "right";
self.deathTeamate = true;
}
}
}
}
}
*/
canReactAgain()
{
return ( !isdefined( self.lastReactTime ) || gettime() - self.lastReactTime > 2000 );
}
///////////////////////////////////////////////////////////////////////////
// bullet whizby reaction
///////////////////////////////////////////////////////////////////////////
bulletWhizbyReaction()
{
self endon( "killanimscript" );
self.lastReactTime = gettime();
self.a.movement = "stop";
enemyNear = ( isDefined( self.whizbyEnemy ) && distanceSquared( self.origin, self.whizbyEnemy.origin ) < 400 * 400 );
self animmode( "gravity" );
self orientmode( "face current" );
// react and go to prone
if ( enemyNear || cointoss() )
{
self clearanim( %root, 0.1 );
reactionAnims = getReactionAnim( "wizby_idle" );
reaction = reactionAnims[ randomint( reactionAnims.size ) ];
if ( enemyNear )
waitTime = 1 + randomfloat( 0.5 );
else
waitTime = 0.2 + randomfloat( 0.5 );
self setFlaggedAnimKnobRestart( "reactanim", reaction, 1, 0.1, 1 );
self animscripts\shared::DoNoteTracksForTime( waitTime, "reactanim" );
self clearanim( %root, 0.1 );
if ( !enemyNear && self.stairsState == "none" )
{
rate = 1 + randomfloat( 0.2 );
reactionAnims = getReactionAnim( "wizby_dive" );
diveAnim = reactionAnims[ randomint( reactionAnims.size ) ];
self setFlaggedAnimKnobRestart( "dive", diveAnim, 1, 0.1, rate );
self animscripts\shared::DoNoteTracks( "dive" );
}
}
else // crouch then handsignal or turn
{
wait randomfloat( 0.2 );
rate = 1.2 + randomfloat( 0.3 );
if ( self.a.pose == "stand" )
{
self clearanim( %root, 0.1 );
reactionAnim = getReactionAnim( "wizby_crouch" );
self setFlaggedAnimKnobRestart( "crouch", reactionAnim, 1, 0.1, rate );
self animscripts\shared::DoNoteTracks( "crouch" );
}
forward = anglesToForward( self.angles );
if ( isDefined( self.whizbyEnemy ) )
dirToEnemy = vectorNormalize( self.whizbyEnemy.origin - self.origin );
else
dirToEnemy = forward;
if ( vectordot( dirToEnemy, forward ) > 0 )
{
reactionAnims = getReactionAnim( "wizby_twitch" );
twitchAnim = reactionAnims[ randomint( reactionAnims.size ) ];
self clearanim( %root, 0.1 );
self setFlaggedAnimKnobRestart( "twitch", twitchAnim, 1, 0.1, 1 );
self animscripts\shared::DoNoteTracks( "twitch" );
//if ( cointoss() )
// self handsignal( "go" );
}
else
{
reactionAnims = getReactionAnim( "wizby_turn" );
turnAnim = reactionAnims[ randomint( reactionAnims.size ) ];
self clearanim( %root, 0.1 );
self setFlaggedAnimKnobRestart( "turn", turnAnim, 1, 0.1, 1 );
self animscripts\shared::DoNoteTracks( "turn" );
}
}
self clearanim( %root, 0.1 );
self.whizbyEnemy = undefined;
self animmode( "normal" );
self orientmode( "face default" );
}
bulletWhizbyCheckLoop()
{
self endon( "killanimscript" );
if ( isdefined( self.disableBulletWhizbyReaction ) )
return;
while ( 1 )
{
self waittill( "bulletwhizby", shooter );
if ( !isdefined( shooter.team ) || self.team == shooter.team )
continue;
if ( isdefined( self.coverNode ) || isdefined( self.ambushNode ) )
continue;
if ( self.a.pose != "stand" )
continue;
if ( !canReactAgain() )
continue;
self.whizbyEnemy = shooter;
self animcustom( ::bulletWhizbyReaction );
}
}
///////////////////////////////////////////////////////////////////////////
// surprised by new enemy reaction
///////////////////////////////////////////////////////////////////////////
clearLookAtThread()
{
self endon( "killanimscript" );
wait 0.3;
self setLookAtEntity();
}
getNewEnemyReactionAnim()
{
reactAnim = undefined;
if ( self nearClaimNodeAndAngle() && isdefined( anim.reactionAnimArray[ self.prevScript ] ) )
{
nodeForward = anglesToForward( self.node.angles );
dirToReactionTarget = vectorNormalize( self.reactionTargetPos - self.origin );
if ( vectorDot( nodeForward, dirToReactionTarget ) < -0.5 )
{
self orientmode( "face current" );
reactionAnims = getReactionAnim( self.prevScript );
reactAnim = reactionAnims[ randomint( reactionAnims.size ) ];
}
}
if ( !isdefined( reactAnim ) )
{
if ( isdefined( self.enemy ) && distanceSquared( self.enemy.origin, self.reactionTargetPos ) < 256 * 256 )
self orientmode( "face enemy" );
else
self orientmode( "face point", self.reactionTargetPos );
if ( self.a.pose == "crouch" )
{
dirToReactionTarget = vectorNormalize( self.reactionTargetPos - self.origin );
forward = anglesToForward( self.angles );
if ( vectorDot( forward, dirToReactionTarget ) < -0.5 )
{
self orientmode( "face current" );
reactionAnims = getReactionAnim( "crouch" );
return reactionAnims[ randomint( reactionAnims.size ) ];
}
}
reactionAnims = getReactionAnim( "stand" );
reactAnim = reactionAnims[ randomint( reactionAnims.size ) ];
}
return reactAnim;
}
stealthNewEnemyReactAnim()
{
self clearanim( %root, 0.2 );
if ( randomint( 4 ) < 3 )
{
self orientmode( "face enemy" );
self setFlaggedAnimKnobRestart( "reactanim", getReactionAnim( "stealth" ), 1, 0.2, 1 );
time = getAnimLength( getReactionAnim( "stealth" ) );
self animscripts\shared::DoNoteTracksForTime( time * 0.8, "reactanim" );
self orientmode( "face current" );
}
else
{
self orientmode( "face enemy" );
self setFlaggedAnimKnobRestart( "reactanim", getReactionAnim( "stealth_backpedal" ), 1, 0.2, 1 );
time = getAnimLength( getReactionAnim( "stealth_backpedal" ) );
self animscripts\shared::DoNoteTracksForTime( time * 0.8, "reactanim" );
self orientmode( "face current" );
self clearanim( %root, 0.2 );
self setFlaggedAnimKnobRestart( "reactanim", getReactionAnim( "stealth_backpedal2" ), 1, 0.2, 1 );
self animscripts\shared::DoNoteTracks( "reactanim" );
}
}
newEnemyReactionAnim()
{
self endon( "death" );
self endon( "endNewEnemyReactionAnim" );
self.lastReactTime = gettime();
self.a.movement = "stop";
if ( isdefined( self._stealth ) && self.alertLevel != "combat" )
{
stealthNewEnemyReactAnim();
}
else
{
reactAnim = self getNewEnemyReactionAnim();
self clearanim( %root, 0.2 );
self setFlaggedAnimKnobRestart( "reactanim", reactAnim, 1, 0.2, 1 );
self animscripts\shared::DoNoteTracks( "reactanim" );
}
self notify( "newEnemyReactionDone" );
}
newEnemySurprisedReaction()
{
self endon( "death" );
if ( isdefined( self.disableReactionAnims ) )
return;
if ( !canReactAgain() )
return;
if ( self.a.pose == "prone" || isdefined( self.a.onback ) )
return;
self animmode( "gravity" );
if ( isdefined( self.enemy ) )
newEnemyReactionAnim();
}

View File

@ -0,0 +1,801 @@
#include maps\_utility;
#include animscripts\utility;
#include animscripts\Combat_utility;
#include animscripts\melee;
#include common_scripts\utility;
RIOTSHIELD_FACE_ENEMY_DIST = 1500;
RIOTSHIELD_FORCE_WALK_DIST = 500;
#using_animtree( "generic_human" );
init_riotshield_AI_anims()
{
anim.notetracks[ "detach shield" ] = ::noteTrackDetachShield;
animscripts\init_move_transitions::init_move_transition_arrays();
anim.coverTrans[ "riotshield" ] = [];
anim.coverTrans[ "riotshield" ][ 1 ] = %riotshield_run_approach_1;
anim.coverTrans[ "riotshield" ][ 2 ] = %riotshield_run_approach_2;
anim.coverTrans[ "riotshield" ][ 3 ] = %riotshield_run_approach_3;
anim.coverTrans[ "riotshield" ][ 4 ] = %riotshield_run_approach_4;
anim.coverTrans[ "riotshield" ][ 6 ] = %riotshield_run_approach_6;
anim.coverTrans[ "riotshield" ][ 7 ] = undefined;
anim.coverTrans[ "riotshield" ][ 8 ] = %riotshield_walk2crouch_8;
anim.coverTrans[ "riotshield" ][ 9 ] = undefined;
anim.coverTrans[ "riotshield_crouch" ] = [];
anim.coverTrans[ "riotshield_crouch" ][ 1 ] = %riotshield_walk_approach_1;
anim.coverTrans[ "riotshield_crouch" ][ 2 ] = %riotshield_walk_approach_2;
anim.coverTrans[ "riotshield_crouch" ][ 3 ] = %riotshield_walk_approach_3;
anim.coverTrans[ "riotshield_crouch" ][ 4 ] = %riotshield_walk_approach_4;
anim.coverTrans[ "riotshield_crouch" ][ 6 ] = %riotshield_walk_approach_6;
anim.coverTrans[ "riotshield_crouch" ][ 7 ] = undefined;
anim.coverTrans[ "riotshield_crouch" ][ 8 ] = %riotshield_walk2crouch_8;
anim.coverTrans[ "riotshield_crouch" ][ 9 ] = undefined;
riotshieldTransTypes = [];
riotshieldTransTypes[0] = "riotshield";
riotshieldTransTypes[1] = "riotshield_crouch";
for ( j = 0; j < riotshieldTransTypes.size; j++ )
{
trans = riotshieldTransTypes[ j ];
for ( i = 1; i <= 9; i++ )
{
if ( i == 5 )
continue;
if ( isdefined( anim.coverTrans[ trans ][ i ] ) )
{
anim.coverTransDist [ trans ][ i ] = getMoveDelta( anim.coverTrans[ trans ][ i ], 0, 1 );
}
}
}
anim.coverTransAngles[ "riotshield_crouch" ][ 1 ] = 45;
anim.coverTransAngles[ "riotshield_crouch" ][ 2 ] = 0;
anim.coverTransAngles[ "riotshield_crouch" ][ 3 ] = -45;
anim.coverTransAngles[ "riotshield_crouch" ][ 4 ] = 90;
anim.coverTransAngles[ "riotshield_crouch" ][ 6 ] = -90;
anim.coverTransAngles[ "riotshield_crouch" ][ 8 ] = 180;
anim.coverTransAngles[ "riotshield" ][ 1 ] = 45;
anim.coverTransAngles[ "riotshield" ][ 2 ] = 0;
anim.coverTransAngles[ "riotshield" ][ 3 ] = -45;
anim.coverTransAngles[ "riotshield" ][ 4 ] = 90;
anim.coverTransAngles[ "riotshield" ][ 6 ] = -90;
anim.coverTransAngles[ "riotshield" ][ 8 ] = 180;
anim.arrivalEndStance[ "riotshield" ] = "crouch";
anim.arrivalEndStance[ "riotshield_crouch" ] = "crouch";
animscripts\init_common::addGrenadeThrowAnimOffset( %riotshield_crouch_grenade_toss, (-3.20014, 1.7098, 55.6886) );
}
noteTrackDetachShield( note, flagName )
{
self animscripts\shared::DropAIWeapon( self.secondaryWeapon );
self.secondaryWeapon = "none";
if ( isAlive( self ) )
riotshield_turn_into_regular_ai();
}
riotshield_approach_type()
{
if ( self.a.pose == "crouch" )
return "riotshield_crouch";
return "riotshield";
}
riotshield_approach_conditions( node )
{
// to allow approach while facing enemy and crouch walking
return true;
}
init_riotshield_AI()
{
//shieldModel = getWeaponModel( self.secondaryWeapon );
//self attach( shieldModel, "tag_weapon_left" );
animscripts\shared::placeWeaponOn( self.secondaryWeapon, "left", false );
self.subclass = "riotshield"; // incase guy didn't spawn as a "riotshield" ai
self.approachTypeFunc = ::riotshield_approach_type;
self.approachConditionCheckFunc = ::riotshield_approach_conditions;
self.faceEnemyArrival = true;
self.disableCoverArrivalsOnly = true;
self.pathRandomPercent = 0;
self.interval = 0;
self.disableDoorBehavior = true;
self.no_pistol_switch = true;
self.dontShootWhileMoving = true;
self.disableBulletWhizbyReaction = true;
self.disableFriendlyFireReaction = true;
self.neverSprintForVariation = true;
self.combatMode = "no_cover";
self.fixednode = false;
self.maxFaceEnemyDist = RIOTSHIELD_FACE_ENEMY_DIST;
self.noMeleeChargeDelay = true;
self.meleeChargeDistSq = squared( 256 );
self.meleePlayerWhileMoving = true;
self.useMuzzleSideOffset = true;
// fall over after getting hit this many times on the shield all within 0.3 seconds of each other
if ( level._gameSkill < 1 )
self.shieldBulletBlockLimit = randomintrange( 4, 8 );
else
self.shieldBulletBlockLimit = randomintrange( 8, 12 );
self.shieldBulletBlockCount = 0;
self.shieldBulletBlockTime = 0;
self.walkDist = RIOTSHIELD_FORCE_WALK_DIST;
self.walkDistFacingMotion = RIOTSHIELD_FORCE_WALK_DIST;
self.grenadeAwareness = 1;
self.frontShieldAngleCos = 0.5;
self.noGrenadeReturnThrow = true;
self.a.grenadeThrowPose = "crouch";
self.minExposedGrenadeDist = 400;
self.ignoresuppression = true;
self.specialMelee_Standard = ::riotshield_melee_standard;
self.specialMeleeChooseAction = ::riotshield_melee_AIvsAI;
self disable_turnAnims();
self disable_surprise();
self disable_cqbwalk();
init_riotshield_animsets();
if ( level._gameSkill < 1 )
self.bullet_resistance = 30;
else
self.bullet_resistance = 40;
self add_damage_function( maps\_spawner::bullet_resistance );
self add_damage_function( animscripts\pain::additive_pain );
}
riotshield_charge()
{
if ( !Melee_Standard_UpdateAndValidateTarget() )
return false;
// get from animation
delta = getMoveDelta( %riotshield_bashA_attack, 0, 1 );
rangeSq = lengthSquared( delta );
if ( distanceSquared( self.origin, self.melee.target.origin ) < rangeSq )
return true;
self animscripts\melee::Melee_PlayChargeSound();
sampleTime = 0.1;
firstTry = true;
while ( 1 )
{
assert( isdefined( self.melee.target ) );
// now that we moved a bit, see if our target moved before we check for valid melee
// it's possible something happened in the meantime that makes meleeing impossible.
if ( !Melee_Standard_UpdateAndValidateTarget() )
return false;
if ( firstTry )
{
self.a.pose = "stand";
self SetFlaggedAnimKnobAll( "chargeanim", %riotshield_sprint, %body, 1, .2, 1 );
firstTry = false;
}
self orientMode( "face point", self.melee.target.origin );
self animscripts\shared::DoNoteTracksForTime( sampleTime, "chargeanim" );
enemyDistanceSq = distanceSquared( self.origin, self.melee.target.origin );
// if we're done raising our gun, and starting a melee now will hit the guy, our preparation is finished
if ( enemyDistanceSq < rangeSq )
break;
// don't keep charging if we've been doing this for too long.
if ( gettime() >= self.melee.giveUpTime )
return false;
}
return true;
}
riotshield_melee_standard()
{
self animMode( "zonly_physics" );
animscripts\melee::Melee_Standard_ResetGiveUpTime();
while ( true )
{
if ( !riotshield_charge() )
{
// if we couldn't get in place to melee, don't try to charge for a little while and abort
self.nextMeleeChargeTime = getTime() + 1500;
self.nextMeleeChargeTarget = self.melee.target;
break;
}
assert( (self.a.pose == "stand") || (self.a.pose == "crouch") );
self animscripts\battleChatter_ai::evaluateMeleeEvent();
self orientMode( "face point", self.melee.target.origin );
self setflaggedanimknoballrestart( "meleeanim", %riotshield_bash_vs_player, %body, 1, .2, 1 );
self.melee.inProgress = true;
// If the attack loop returns false, we need to stop this melee
if( !animscripts\melee::Melee_Standard_PlayAttackLoop() )
{
// Since getting here means that we've done a melee but our attack is no longer valid, delay before we can do a standard attack again.
animscripts\melee::Melee_Standard_DelayStandardCharge( self.melee.target );
break;
}
self animMode( "none" );
}
self animMode( "none" );
}
riotshield_melee_AIvsAI()
{
assert( isDefined( self ) );
assert( isDefined( self.melee.target ) );
target = self.melee.target;
animscripts\melee::Melee_Decide_Winner();
// Choose which sequence to play based on angles
angleToEnemy = vectortoangles( target.origin - self.origin );
angleDiff = AngleClamp180( target.angles[ 1 ] - angleToEnemy[ 1 ] );
if ( abs( angleDiff ) > 100 ) // facing each other
{
if ( self.melee.winner )
{
if ( self.subclass == "riotshield" )
{
self.melee.animName = %riotshield_bashA_attack;
target.melee.animName = %riotshield_bashA_defend;
target.melee.surviveAnimName = %riotshield_bashA_defend_survive;
}
else
{
assert( target.subclass == "riotshield" );
self.melee.animName = %riotshield_bashB_defend;
target.melee.animName = %riotshield_bashB_attack;
}
}
else
{
if ( self.subclass == "riotshield" )
{
self.melee.animName = %riotshield_bashB_attack;
target.melee.animName = %riotshield_bashB_defend;
}
else
{
assert( target.subclass == "riotshield" );
self.melee.animName = %riotshield_bashA_defend;
target.melee.animName = %riotshield_bashA_attack;
}
}
}
else
{
return false;
}
self.melee.startPos = getStartOrigin( target.origin, target.angles, self.melee.animName );
self.melee.startAngles = ( target.angles[0], AngleClamp180( target.angles[1] + 180 ), target.angles[2] );
self.lockOrientation = false;
target.lockOrientation = false;
// Make sure we can move to the selected point ( no re-try for now )
return Melee_UpdateAndValidateStartPos();
}
riotshield_startMoveTransition()
{
if ( isdefined( self.disableExits ) )
return;
self orientmode( "face angle", self.angles[1] );
self animmode( "zonly_physics", false );
if ( self.a.pose == "crouch" )
{
if ( isdefined( self.sprint ) || isdefined( self.fastwalk ) )
transAnim = %riotshield_crouch2stand;
else
transAnim = %riotshield_crouch2walk;
rate = randomfloatrange( 0.9, 1.1 );
self setFlaggedAnimKnobAllRestart( "startmove", transAnim, %body, 1, .1, rate );
self animscripts\shared::DoNoteTracks( "startmove" );
self clearanim( %riotshield_crouch2walk, 0.5 );
}
if ( isdefined( self.sprint ) || isdefined( self.fastwalk ) )
{
self allowedStances( "stand", "crouch" );
self.a.pose = "stand";
}
self orientmode( "face default" );
self animMode( "normal", false );
self thread riotshield_bullet_hit_shield();
}
riotshield_endMoveTransition()
{
if ( self.prevScript == "move" && self.a.pose == "crouch" )
{
self clearAnim( %root, .2 );
rate = randomfloatrange( 0.9, 1.1 );
self animmode( "zonly_physics" );
self setFlaggedAnimKnobAllRestart( "endmove", %riotshield_walk2crouch_8, %body, 1, .2, rate );
self animscripts\shared::DoNoteTracks( "endmove" );
self animMode( "normal" );
}
self allowedStances( "crouch" );
}
riotshield_startCombat()
{
//assertex( self.combatmode == "no_cover", "riotshield AI combat mode should be 'no_cover'" );
riotshield_endMoveTransition();
self.pushable = false;
self thread riotshield_bullet_hit_shield();
}
riotshield_bullet_hit_shield()
{
self endon( "killanimscript" );
while (1)
{
self waittill( "bullet_hitshield" );
time = gettime();
if ( time - self.shieldBulletBlockTime > 500 )
self.shieldBulletBlockCount = 0;
else
self.shieldBulletBlockCount++;
self.shieldBulletBlockTime = time;
if ( self.shieldBulletBlockCount > self.shieldBulletBlockLimit )
self doDamage( 1, ( 0, 0, 0 ) ); // do minimal damage to fall down
if ( cointoss() )
reactAnim = %riotshield_reactA;
else
reactAnim = %riotshield_reactB;
self notify( "new_hit_react" );
self setFlaggedAnimRestart( "hitreact", reactAnim, 1, 0.1, 1 );
self thread riotshield_bullet_hit_shield_clear();
}
}
riotshield_bullet_hit_shield_clear()
{
self endon( "killanimscript" );
self endon( "new_hit_react" );
self waittillmatch( "hitreact", "end" );
self clearanim( %riotshield_react, 0.1 );
}
riotshield_grenadeCower()
{
if ( self.a.pose == "stand" )
{
self clearanim( %root, .2 );
self setFlaggedAnimKnobAllRestart( "trans", %riotshield_walk2crouch_8, %body, 1, .2, 1.2 );
self animscripts\shared::DoNoteTracks( "trans" );
}
if ( isdefined( self.grenade ) )
{
faceGrenade = true;
dirToGrenade = self.grenade.origin - self.origin;
if ( isdefined( self.enemy ) )
{
dirToEnemy = self.enemy.origin - self.origin;
if ( vectorDot( dirToGrenade, dirToEnemy ) < 0 )
faceGrenade = false;
}
if ( faceGrenade )
{
relYaw = AngleClamp180( self.angles[ 1 ] - vectorToYaw( dirToGrenade ) );
if ( !isdefined( self.turnThreshold ) )
self.turnThreshold = 55;
while ( abs( relYaw ) > self.turnThreshold )
{
if ( !isdefined( self.a.array ) )
animscripts\combat::setup_anim_array();
if ( !self animscripts\combat::TurnToFaceRelativeYaw( relYaw ) )
break;
relYaw = AngleClamp180( self.angles[ 1 ] - vectorToYaw( dirToGrenade ) );
}
}
}
self setAnimKnobAll( %riotshield_crouch_aim_5, %body, 1, 0.2, 1 );
self setFlaggedAnimKnobAllRestart( "grenadecower", %riotshield_crouch_idle_add, %add_idle, 1, 0.2, self.animplaybackrate );
self animscripts\shared::DoNoteTracks( "grenadecower" );
}
riotshield_flashbang()
{
self notify( "flashed" );
if ( !isdefined( self.a.onback ) )
{
rate = randomfloatrange( 0.9, 1.1 );
self.frontShieldAngleCos = 1;
flashArray = [];
flashArray[0] = %riotshield_crouch_grenade_flash1;
flashArray[1] = %riotshield_crouch_grenade_flash2;
flashArray[2] = %riotshield_crouch_grenade_flash3;
flashArray[3] = %riotshield_crouch_grenade_flash4;
flashAnim = flashArray[ randomint( flashArray.size ) ];
self setFlaggedAnimKnobAllRestart( "flashanim", flashAnim, %body, 1, .1, rate );
self.minPainDamage = 1000;
}
self animscripts\shared::DoNoteTracks( "flashanim" );
self.minPainDamage = 0;
self.frontShieldAngleCos = 0.5;
}
riotshield_pain()
{
// all the pain animations are in crouch
self.a.pose = "crouch";
if ( usingSideArm() )
forceUseWeapon( self.primaryweapon, "primary" );
if ( !isdefined( self.a.onback ) )
{
rate = randomfloatrange( 0.8, 1.15 );
self.frontShieldAngleCos = 1;
if ( ( self.damageYaw < -120 || self.damageYaw > 120 ) && isExplosiveDamageMOD( self.damageMOD ) )
{
painArray = [];
painArray[0] = %riotshield_crouch_grenade_blowback;
painArray[1] = %riotshield_crouch_grenade_blowbackL;
painArray[2] = %riotshield_crouch_grenade_blowbackR;
painAnim = painArray[ randomint( painArray.size ) ];
self setFlaggedAnimKnobAllRestart( "painanim", painAnim, %body, 1, .2, rate );
self.minPainDamage = 1000;
}
else
{
self setFlaggedAnimKnobAllRestart( "painanim", %riotshield_crouch_pain, %body, 1, .2, rate );
}
}
self animscripts\shared::DoNoteTracks( "painanim" );
self.minPainDamage = 0;
self.frontShieldAngleCos = 0.5;
}
riotshield_death()
{
if ( isdefined( self.a.onback ) && self.a.pose == "crouch" )
{
deathArray = [];
deathArray[0] = %dying_back_death_v2;
deathArray[1] = %dying_back_death_v3;
deathArray[2] = %dying_back_death_v4;
deathAnim = deathArray[ randomint( deathArray.size ) ];
self animscripts\death::playDeathAnim( deathAnim );
return true;
}
if ( self.prevScript == "pain" || self.prevScript == "flashed" )
doShieldDeath = randomInt( 2 ) == 0;
else
doShieldDeath = true;
if ( doShieldDeath )
{
if ( cointoss() )
deathAnim = %riotshield_crouch_death;
else
deathAnim = %riotshield_crouch_death_fallback;
self animscripts\death::playDeathAnim( deathAnim );
return true;
}
self.a.pose = "crouch";
return false;
}
init_riotshield_animsets()
{
// move animations
animset = [];
animset[ "sprint" ] = %riotshield_sprint;
animset[ "prone" ] = %prone_crawl;
animset[ "straight" ] = %riotshield_run_F;
animset[ "straight_variation" ] = %riotshield_run_F;
animset[ "move_f" ] = %riotshield_run_F;
animset[ "move_l" ] = %riotshield_run_L;
animset[ "move_r" ] = %riotshield_run_R;
animset[ "move_b" ] = %riotshield_run_B;
animset[ "crouch" ] = %riotshield_crouchwalk_F;
animset[ "crouch_l" ] = %riotshield_crouchwalk_L;
animset[ "crouch_r" ] = %riotshield_crouchwalk_R;
animset[ "crouch_b" ] = %riotshield_crouchwalk_B;
animset[ "stairs_up" ] = %traverse_stair_run_01;
animset[ "stairs_down" ] = %traverse_stair_run_down;
self.customMoveAnimSet[ "run" ] = animset;
self.customMoveAnimSet[ "walk" ] = animset;
self.customMoveAnimSet[ "cqb" ] = animset;
self.customIdleAnimSet = [];
self.customIdleAnimSet[ "crouch" ] = %riotshield_crouch_aim_5;
self.customIdleAnimSet[ "crouch_add" ] = %riotshield_crouch_idle_add;
self.customIdleAnimSet[ "stand" ] = %riotshield_crouch_aim_5;
self.customIdleAnimSet[ "stand_add" ] = %riotshield_crouch_idle_add;
self.a.pose = "crouch";
self allowedStances( "crouch" );
// combat animations
animset = anim.animsets.defaultStand;
animset[ "add_aim_up" ] = %riotshield_crouch_aim_8;
animset[ "add_aim_down" ] = %riotshield_crouch_aim_2;
animset[ "add_aim_left" ] = %riotshield_crouch_aim_4;
animset[ "add_aim_right" ] = %riotshield_crouch_aim_6;
animset[ "straight_level" ] = %riotshield_crouch_aim_5;
animset[ "fire" ] = %riotshield_crouch_fire_auto;
animset[ "single" ] = array( %riotshield_crouch_fire_single );
// remove this burst, semi nonsense soon
animset[ "burst2" ] = %riotshield_crouch_fire_burst;
animset[ "burst3" ] = %riotshield_crouch_fire_burst;
animset[ "burst4" ] = %riotshield_crouch_fire_burst;
animset[ "burst5" ] = %riotshield_crouch_fire_burst;
animset[ "burst6" ] = %riotshield_crouch_fire_burst;
animset[ "semi2" ] = %riotshield_crouch_fire_burst;
animset[ "semi3" ] = %riotshield_crouch_fire_burst;
animset[ "semi4" ] = %riotshield_crouch_fire_burst;
animset[ "semi5" ] = %riotshield_crouch_fire_burst;
animset[ "exposed_idle" ] = array( %riotshield_crouch_idle_add, %riotshield_crouch_twitch );
animset[ "exposed_grenade" ] = array( %riotshield_crouch_grenade_toss );
animset[ "reload" ] = array( %riotshield_crouch_reload );
animset[ "reload_crouchhide" ] = array( %riotshield_crouch_reload );
animset[ "turn_left_45" ] = %riotshield_crouch_Lturn;
animset[ "turn_left_90" ] = %riotshield_crouch_Lturn;
animset[ "turn_left_135" ] = %riotshield_crouch_Lturn;
animset[ "turn_left_180" ] = %riotshield_crouch_Lturn;
animset[ "turn_right_45" ] = %riotshield_crouch_Rturn;
animset[ "turn_right_90" ] = %riotshield_crouch_Rturn;
animset[ "turn_right_135" ] = %riotshield_crouch_Rturn;
animset[ "turn_right_180" ] = %riotshield_crouch_Rturn;
animset[ "stand_2_crouch" ] = %riotshield_walk2crouch_8;
self animscripts\init_common::set_animset_complete_custom_stand( animset );
self animscripts\init_common::set_animset_complete_custom_crouch( animset );
self.choosePoseFunc = ::riotshield_choose_pose;
self.painFunction = ::riotshield_pain;
self.specialDeathFunc = ::riotshield_death;
self.specialFlashedFunc = ::riotshield_flashbang;
self.grenadeCowerFunction = ::riotshield_grenadeCower;
self.customMoveTransition = ::riotshield_startMoveTransition;
self.permanentCustomMoveTransition = true;
set_exception( "exposed", ::riotshield_startCombat );
//set_exception( "stop_immediate", ::riotshield_endMoveTransition );
}
riotshield_choose_pose( preferredPose )
{
if ( isdefined( self.grenade ) )
return "stand";
return self animscripts\utility::choosePose( preferredPose );
}
riotshield_sprint_on()
{
self.maxFaceEnemyDist = 128;
self.sprint = true;
self orientmode( "face default" );
self.lockorientation = false;
self.walkDist = 32;
self.walkDistFacingMotion = 32;
}
riotshield_fastwalk_on()
{
self.maxFaceEnemyDist = 128;
self.fastwalk = true;
self.walkDist = 32;
self.walkDistFacingMotion = 32;
}
riotshield_sprint_off()
{
self.maxFaceEnemyDist = RIOTSHIELD_FACE_ENEMY_DIST;
self.walkDist = RIOTSHIELD_FORCE_WALK_DIST;
self.walkDistFacingMotion = RIOTSHIELD_FORCE_WALK_DIST;
self.sprint = undefined;
self allowedStances( "crouch" );
}
riotshield_fastwalk_off()
{
self.maxFaceEnemyDist = RIOTSHIELD_FACE_ENEMY_DIST;
self.walkDist = RIOTSHIELD_FORCE_WALK_DIST;
self.walkDistFacingMotion = RIOTSHIELD_FORCE_WALK_DIST;
self.fastwalk = undefined;
self allowedStances( "crouch" );
}
null_func()
{
}
riotshield_init_flee()
{
// hack to restart move script
if ( self.script == "move" )
self animcustom( ::null_func );
self.customMoveTransition = ::riotshield_flee_and_drop_shield;
}
riotshield_flee_and_drop_shield()
{
// restore this incase flee gets interrupted
self.customMoveTransition = ::riotshield_startMoveTransition;
self animmode( "zonly_physics", false );
self orientmode( "face current" );
if ( !isdefined( self.dropShieldInPlace ) && isdefined( self.enemy ) && vectordot( self.lookaheadDir, anglesToForward( self.angles ) ) < 0 )
fleeAnim = %riotshield_crouch2walk_2flee;
else
fleeAnim = %riotshield_crouch2stand_shield_drop;
rate = randomFloatRange( 0.85, 1.1 );
self SetFlaggedAnimKnobAll( "fleeanim", fleeAnim, %root, 1, .1, rate );
self animscripts\shared::DoNoteTracks( "fleeanim" ); // return on code_move
self.maxFaceEnemyDist = 32;
self.lockOrientation = false;
self orientmode( "face default" );
self animmode( "normal", false );
self animscripts\shared::DoNoteTracks( "fleeanim" );
self clearanim( fleeAnim, 0.2 );
self.maxFaceEnemyDist = 128;
}
riotshield_turn_into_regular_ai()
{
self.subclass = "regular";
self.combatMode = "cover";
self.approachTypeFunc = undefined;
self.approachConditionCheckFunc = undefined;
self.faceEnemyArrival = undefined;
self.disableCoverArrivalsOnly = undefined;
self.pathRandomPercent = 0;
self.interval = 80;
self.disableDoorBehavior = undefined;
self.no_pistol_switch = undefined;
self.dontShootWhileMoving = undefined;
self.disableBulletWhizbyReaction = undefined;
self.disableFriendlyFireReaction = undefined;
self.neverSprintForVariation = undefined;
self.maxFaceEnemyDist = 128;
self.noMeleeChargeDelay = undefined;
self.meleeChargeDistSq = undefined;
self.meleePlayerWhileMoving = undefined;
self.useMuzzleSideOffset = undefined;
self.pathEnemyFightDist = 128;
self.pathenemylookahead = 128;
self.walkDist = 256;
self.walkDistFacingMotion = 64;
self.lockorientation = false;
self.frontShieldAngleCos = 1;
self.noGrenadeReturnThrow = false;
self.ignoresuppression = false;
self.sprint = undefined;
self allowedStances( "stand", "crouch", "prone" );
self.specialMelee_Standard = undefined;
self.specialMeleeChooseAction = undefined;
self enable_turnAnims();
self.bullet_resistance = undefined;
self remove_damage_function( maps\_spawner::bullet_resistance );
self remove_damage_function( animscripts\pain::additive_pain );
self animscripts\init_common::clear_custom_animset();
self.choosePoseFunc = animscripts\utility::choosePose;
self.painFunction = undefined;
self.specialDeathFunc = undefined;
self.specialFlashedFunc = undefined;
self.grenadeCowerFunction = undefined;
self.customMoveTransition = undefined;
self.permanentCustomMoveTransition = undefined;
clear_exception( "exposed" );
clear_exception( "stop_immediate" );
}

1177
animscripts/run.gsc Normal file

File diff suppressed because it is too large Load Diff

326
animscripts/saw/common.gsc Normal file
View File

@ -0,0 +1,326 @@
main( turret )
{
self endon( "killanimscript" );// code
assert( isdefined( turret ) );
animscripts\utility::initialize( "saw" );
// when we ran our postscriptfunc we may have decided to stop using our turret,
// in which case it's gone now
if ( !isdefined( turret ) )
return;
self.a.special = "saw";
pauseUntilTime = getTime();
turretState = "start";
self animscripts\shared::placeWeaponOn( self.weapon, "none" );
turret show();
if ( isDefined( turret.aiOwner ) )
{
assert( turret.aiOwner == self );
self.a.postScriptFunc = ::postScriptFunc;
self.a.usingTurret = turret;
turret notify( "being_used" );
self thread stopUsingTurretWhenNodeLost();
}
else
{
self.a.postScriptFunc = ::preplacedPostScriptFunc;
}
turret.doFiring = false;
self thread fireController( turret );
self setTurretAnim( self.primaryTurretAnim );
self setAnimKnobRestart( self.primaryTurretAnim, 1, 0.2, 1 );
self setAnimKnobLimitedRestart( self.additiveTurretIdle );
self setAnimKnobLimitedRestart( self.additiveTurretFire );
turret setAnimKnobLimitedRestart( turret.additiveTurretIdle );
turret setAnimKnobLimitedRestart( turret.additiveTurretFire );
turret endon( "death" );
for ( ;; )
{
// tagBK< NOTE > System allows for dynamic updates of fire rate. Ported from above.
if ( isDefined( turret.script_delay_min ))
{
turret_delay = turret.script_delay_min;
}
else
{
turret_delay = maps\_mgturret::burst_fire_settings( "delay" );
}
if ( isDefined( turret.script_delay_max ))
{
turret_delay_range = turret.script_delay_max - turret_delay;
}
else
{
turret_delay_range = maps\_mgturret::burst_fire_settings( "delay_range" );
}
if ( isDefined( turret.script_burst_min ))
{
turret_burst = turret.script_burst_min;
}
else
{
turret_burst = maps\_mgturret::burst_fire_settings( "burst" );
}
if ( isDefined( turret.script_burst_max ))
{
turret_burst_range = turret.script_burst_max - turret_burst;
}
else
{
turret_burst_range = maps\_mgturret::burst_fire_settings( "burst_range" );
}
// Recalculate wait time.
if ( turret_burst_range <= 0 )
{
waittime = turret_delay;
burst = false;
}
else
{
waittime = randomFloatRange( turret_burst, turret_burst + turret_burst_range );
burst = true;
}
// Primary update.
if ( turret.doFiring )
{
thread DoShoot( turret );
if ( burst == false )
{
turret notify( "turretstatechange" );
}
self waitTimeOrUntilTurretStateChange( waittime, turret );
turret notify( "turretstatechange" );
if ( turret.doFiring )
{
thread DoAim( turret );
wait( waittime );
}
}
else
{
thread DoAim( turret );
turret waittill( "turretstatechange" );
}
}
}
waitTimeOrUntilTurretStateChange( time, turret )
{
turret endon( "turretstatechange" );
wait time;
}
fireController( turret )
{
self endon( "killanimscript" );
fovdot = cos( 15 );
for ( ;; )
{
while ( isDefined( self.enemy ) )
{
enemypos = self.enemy.origin;
//if ( isSentient( enemypos ) )
// enemypos += (0,0,32);
turretAimPos = turret getTagAngles( "tag_aim" );
if ( within_fov( turret.origin, turretAimPos, enemypos, fovdot ) || distanceSquared( turret.origin, enemyPos ) < 200 * 200 )
{
if ( !turret.doFiring )
{
turret.doFiring = true;
turret notify( "turretstatechange" );
}
}
else if ( turret.doFiring )
{
turret.doFiring = false;
turret notify( "turretstatechange" );
}
wait( 0.05 );
}
if ( turret.doFiring )
{
turret.doFiring = false;
turret notify( "turretstatechange" );
}
wait( 0.05 );
}
}
turretTimer( duration, turret )
{
if ( duration <= 0 )
return;
self endon( "killanimscript" );// code
turret endon( "turretstatechange" );// code
wait( duration );
turret notify( "turretstatechange" );
}
stopUsingTurretWhenNodeLost()
{
self endon( "killanimscript" );
// sometimes someone else will come and steal our node. when that happens,
// we should leave so we don't try to use the same MG at once.
while ( 1 )
{
if ( !isdefined( self.node ) || distancesquared( self.origin, self.node.origin ) > 64 * 64 )
self stopUseTurret();
wait .25;
}
}
postScriptFunc( animscript )
{
if ( animscript == "pain" )
{
if ( isdefined( self.node ) && distancesquared( self.origin, self.node.origin ) < 64 * 64 )
{
self.a.usingTurret hide();
self animscripts\shared::placeWeaponOn( self.weapon, "right" );
self.a.postScriptFunc = ::postPainFunc;
return;
}
else
{
self stopUseTurret();
}
}
assert( self.a.usingTurret.aiOwner == self );
if ( animscript == "saw" )
{
turret = self getTurret();
assert( isDefined( turret ) && turret == self.a.usingTurret );
return;
}
self.a.usingTurret delete();
self.a.usingTurret = undefined;
self animscripts\shared::placeWeaponOn( self.weapon, "right" );
}
postPainFunc( animscript )
{
assert( isDefined( self.a.usingTurret ) );
assert( self.a.usingTurret.aiOwner == self );
if ( !isdefined( self.node ) || distancesquared( self.origin, self.node.origin ) > 64 * 64 )
{
self stopUseTurret();
self.a.usingTurret delete();
self.a.usingTurret = undefined;
// we may have gone into long death, in which case our weapon is gone
if ( isdefined( self.weapon ) && self.weapon != "none" )
{
self animscripts\shared::placeWeaponOn( self.weapon, "right" );
}
}
else if ( animscript != "saw" )
{
self.a.usingTurret delete();
}
}
preplacedPostScriptFunc( animscript )
{
self animscripts\shared::placeWeaponOn( self.weapon, "right" );
}
within_fov( start_origin, start_angles, end_origin, fov )
{
normal = vectorNormalize( end_origin - start_origin );
forward = anglestoforward( start_angles );
dot = vectorDot( forward, normal );
return dot >= fov;
}
// ==================================
#using_animtree( "generic_human" );
DoShoot( turret )
{
self setAnim( %additive_saw_idle, 0, .1 );
self setAnim( %additive_saw_fire, 1, .1 );
turret turretDoShootAnims();
TurretDoShoot( turret );
}
DoAim( turret )
{
self setAnim( %additive_saw_idle, 1, .1 );
self setAnim( %additive_saw_fire, 0, .1 );
turret turretDoAimAnims();
}
//=====================================
#using_animtree( "mg42" );
TurretDoShoot( turret )
{
self endon( "killanimscript" );
turret endon( "turretstatechange" );// code or script
for ( ;; )
{
turret ShootTurret();
wait 0.1;
}
}
turretDoShootAnims()
{
self setAnim( %additive_saw_idle, 0, .1 );
self setAnim( %additive_saw_fire, 1, .1 );
}
turretDoAimAnims()
{
self setAnim( %additive_saw_idle, 1, .1 );
self setAnim( %additive_saw_fire, 0, .1 );
}

View File

@ -0,0 +1,36 @@
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "crouch";
animscripts\utility::UpdateAnimPose();
// It'd be nice if I had an animation to get to stand without moving...
self.a.movement = "stop";
turret = self getTurret();
turret thread turretInit( self );
self.primaryTurretAnim = %crouchSAWgunner_aim;
self.additiveTurretIdle = %saw_gunner_lowwall_idle;
self.additiveTurretFire = %saw_gunner_lowwall_firing;
thread animscripts\saw\common::main( turret );
}
//=====================================
#using_animtree( "mg42" );
turretInit( owner )
{
self UseAnimTree( #animtree );
self.additiveTurretIdle = %saw_gunner_lowwall_idle_mg;
self.additiveTurretFire = %saw_gunner_lowwall_firing_mg;
self endon( "death" );
owner waittill( "killanimscript" );// code
self stopUseAnimTree();
}

37
animscripts/saw/prone.gsc Normal file
View File

@ -0,0 +1,37 @@
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "prone";
animscripts\utility::UpdateAnimPose();
// It'd be nice if I had an animation to get to stand without moving...
self.a.movement = "stop";
turret = self getTurret();
turret thread turretInit( self );
self.primaryTurretAnim = %proneSAWgunner_aim;
self.additiveTurretIdle = %saw_gunner_prone_idle;
self.additiveTurretFire = %saw_gunner_prone_firing;
thread animscripts\saw\common::main( turret );
}
//=====================================
#using_animtree( "mg42" );
turretInit( owner )
{
self UseAnimTree( #animtree );
self.additiveTurretIdle = %saw_gunner_prone_idle_mg;
self.additiveTurretFire = %saw_gunner_prone_firing_mg;
self endon( "death" );
owner waittill( "killanimscript" );// code
self stopUseAnimTree();
}

37
animscripts/saw/stand.gsc Normal file
View File

@ -0,0 +1,37 @@
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "stand";
animscripts\utility::UpdateAnimPose();
// It'd be nice if I had an animation to get to stand without moving...
self.a.movement = "stop";
turret = self getTurret();
turret thread turretInit( self );
self.primaryTurretAnim = %standSAWgunner_aim;
self.additiveTurretIdle = %saw_gunner_idle;
self.additiveTurretFire = %saw_gunner_firing_add;
thread animscripts\saw\common::main( turret );
}
//=====================================
#using_animtree( "mg42" );
turretInit( owner )
{
self UseAnimTree( #animtree );
self.additiveTurretIdle = %saw_gunner_idle_mg;
self.additiveTurretFire = %saw_gunner_firing_mg_add;
self endon( "death" );
owner waittill( "killanimscript" );// code
self stopUseAnimTree();
}

70
animscripts/scripted.gsc Normal file
View File

@ -0,0 +1,70 @@
// Note that this script is called from the level script command animscripted, only for AI. If animscripted
// is done on a script model, this script is not called - startscriptedanim is called directly.
#using_animtree( "generic_human" );
main()
{
//thread [[anim.println]]("Entering animscripts\\scripted. anim: ",self.codeScripted["anim"],", notify: ",self.codeScripted["notifyName"],", dialogue: ",self.scripted_dialogue,", facial: ",self.facial_animation, "root: ", self.codeScripted["root"]);#/
self endon( "death" );
// wait (0);
self notify( "killanimscript" );
self notify( "clearSuppressionAttack" );
self.a.suppressingEnemy = false;
self.codeScripted[ "root" ] = %body; // TEMP!
self endon( "end_sequence" );
// Causes potential variable overflow in Stalingrad
// self thread DebugPrintEndSequence();
self startscriptedanim( self.codeScripted[ "notifyName" ], self.codeScripted[ "origin" ], self.codeScripted[ "angles" ], self.codeScripted[ "anim" ], self.codeScripted[ "blend_time" ], self.codeScripted[ "animMode" ], self.codeScripted[ "root" ] );
self.codeScripted = undefined;
// if (isdefined (self.facial_animation))
// {
// self SetFlaggedAnimRestart("scripted_anim_facedone", self.facial_animation, 1, .1, 1);
// self.facial_animation = undefined;
// }
if ( isdefined( self.scripted_dialogue ) || isdefined( self.facial_animation ) )
{
self animscripts\face::SaySpecificDialogue( self.facial_animation, self.scripted_dialogue, 0.9, "scripted_anim_facedone" );
self.facial_animation = undefined;
self.scripted_dialogue = undefined;
}
if ( isdefined( self.deathstring_passed ) )
self.deathstring = self.deathstring_passed;
self waittill( "killanimscript" );
}
#using_animtree( "generic_human" );
init( notifyName, origin, angles, theAnim, blend_time, animMode, root )
{
self.codeScripted[ "notifyName" ] = notifyName;
self.codeScripted[ "origin" ] = origin;
self.codeScripted[ "angles" ] = angles;
self.codeScripted[ "anim" ] = theAnim;
self.codeScripted[ "blend_time" ] = blend_time;
if ( isDefined( animMode ) )
self.codeScripted[ "animMode" ] = animMode;
else
self.codeScripted[ "animMode" ] = "normal";
if ( isDefined( root ) )
self.codeScripted[ "root" ] = root;
else
self.codeScripted[ "root" ] = %body;
}
// Causes potential variable overflow in Stalingrad
/*
DebugPrintEndSequence()
{
self endon ("death");
self waittill ("end_sequence");
/#thread [[anim.println]]("scripted.gsc: \"end_sequence\" was notified. Time: ",GetTime(),".");#/
}
*/

View File

@ -0,0 +1,193 @@
#include animscripts\SetPoseMovement;
#include animscripts\combat_utility;
#using_animtree( "generic_human" );
hackangle()
{
self endon( "killanimscript" );
for ( ;; )
{
enemyAngle = animscripts\utility::GetYawToEnemy();
self OrientMode( "face angle", enemyAngle );
wait .05;
}
}
main()
{
println( "anim1" );
self endon( "killanimscript" );
self endon( "outoftruck" );
animscripts\utility::initialize( "l33t truckride combat" );
thread hackangle();
self OrientMode( "face enemy" );
if ( randomint( 100 ) > 50 )
nextaction = ( "stand" );
else
nextaction = ( "crouch" );
for ( ;; )
{
// Nothing below will work if our gun is completely empty.
Reload( 0 );
// if ( canShootstand && canStand &&
// ( !canShootCrouch || !canCrouch || ( dist < anim.standRangeSq )) )
if ( nextaction == ( "stand" ) )
{
timer = gettime() + randomint( 2000 ) + 2000;
while ( timer > gettime() )
{
// self animscripts\aim::aim();
success = LocalShootVolley( 0 );
// if (!success)
// self interruptPoint(); // We couldn't shoot for some reason, so now would be a good time to run for cover.
nextaction = ( "crouch" );
}
}
else if ( nextaction == ( "crouch" ) )
{
timer = gettime() + randomint( 2000 ) + 2000;
while ( timer > gettime() )
{
/#thread [[ anim.println ]]( "ExposedCombat - Crouched combat" );#/
// self animscripts\aim::aim();
success = ShootVolley();
if ( !success )
continue;
nextaction = ( "stand" );
}
}
}
}
LocalShootVolley( completeLastShot, forceShoot, posOverrideEntity )
{
if ( !isDefined( forceShoot ) )
{
forceShoot = "dontForceShoot";
}
self animscripts\shared::placeWeaponOn( self.primaryweapon, "none" );
if ( self.a.pose == "stand" )
{
anim_autofire = %stand_shoot_auto;
anim_semiautofire = %stand_shoot;
anim_boltfire = %stand_shoot;
}
else// assume crouch
{
anim_autofire = %crouch_shoot_auto;
anim_semiautofire = %crouch_shoot;
anim_boltfire = %crouch_shoot;
}
if ( animscripts\weaponList::usingAutomaticWeapon() )
{
self animscripts\face::SetIdleFace( anim.autofireface );
self setflaggedanimknob( "animdone", anim_autofire, 1, .15, 0 );
wait 0.20;
animRate = animscripts\weaponList::autoShootAnimRate();
self setFlaggedAnimKnobRestart( "shootdone", anim_autofire, 1, .05, animRate );
numShots = randomint( 8 ) + 6;
enemyAngle = animscripts\utility::AbsYawToEnemy();
/#thread [[ anim.locspam ]]( "c16a" );#/
for ( i = 0;( i < numShots && self.bulletsInClip > 0 && enemyAngle < 20 ); i++ )
{
self waittillmatch( "shootdone", "fire" );
if ( isDefined( posOverrideEntity ) )
{
if ( isSentient( posOverrideEntity ) )
{
pos = posOverrideEntity GetEye();
}
else
{
pos = posOverrideEntity.origin;
}
self shoot( 1, pos );
}
else
self shoot();
self decrementBulletsInClip();
enemyAngle = animscripts\utility::AbsYawToEnemy();
}
if ( completeLastShot )
wait animscripts\weaponList::waitAfterShot();
self notify( "stopautofireFace" );
}
else if ( animscripts\weaponList::usingSemiAutoWeapon() )
{
self animscripts\face::SetIdleFace( anim.aimface );
self setanimknob( anim_semiautofire, 1, .15, 0 );
wait 0.2;
rand = randomint( 2 ) + 2;
for ( i = 0;( i < rand && self.bulletsInClip > 0 ); i++ )
{
self setFlaggedAnimKnobRestart( "shootdone", anim_semiautofire, 1, 0, 1 );
if ( isDefined( posOverrideEntity ) )
self shoot( 1, posOverrideEntity . origin );
else
self shoot();
self decrementBulletsInClip();
/#thread [[ anim.locspam ]]( "c17.1b" );#/
shootTime = animscripts\weaponList::shootAnimTime();
quickTime = animscripts\weaponList::waitAfterShot();
wait quickTime;
if ( ( ( completeLastShot ) || ( i < rand - 1 ) ) && shootTime > quickTime )
wait shootTime - quickTime;
}
}
else// Bolt action
{
Rechamber(); // In theory you will almost never need to rechamber here, because you will have done
// it somewhere smarter, like in cover.
self animscripts\face::SetIdleFace( anim.aimface );
// Slowly blend in the first frame of the shoot instead of playing the transition.
self setanimknob( anim_boltfire, 1, .15, 0 );
wait 0.2;
self setFlaggedAnimKnobRestart( "shootdone", anim_boltfire, 1, 0, 1 );
if ( isDefined( posOverrideEntity ) )
self shoot( 1, posOverrideEntity . origin );
else
self shoot();
self.a.needsToRechamber = 1;
self decrementBulletsInClip();
shootTime = animscripts\weaponList::shootAnimTime();
quickTime = animscripts\weaponList::waitAfterShot();
wait quickTime;
}
return 1;
}

File diff suppressed because it is too large Load Diff

2152
animscripts/shared.gsc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,715 @@
#include common_scripts\utility;
#include animscripts\combat_utility;
#include animscripts\utility;
#include animscripts\shared;
// Ideally, this will be the only thread *anywhere* that decides what/where to shoot at
// and how to shoot at it.
// This thread keeps three variables updated, and notifies "shoot_behavior_change" when any of them have changed.
// They are:
// shootEnt - an entity. aim/shoot at this if it's defined.
// shootPos - a vector. aim/shoot towards this if shootEnt isn't defined. if not defined, stop shooting entirely and return to cover if possible.
// Whenever shootEnt is defined, shootPos will be defined as its getShootAtPos().
// shootStyle - how to shoot.
// "full" (unload on the target),
// "burst" (occasional groups of shots),
// "semi" (occasianal single shots),
// "single" (occasional single shots),
// "none" (don't shoot, just aim).
// This thread will also notify "return_to_cover" and set self.shouldReturnToCover = true if it's a good idea to do so.
// Notify "stop_deciding_how_to_shoot" to end this thread if no longer trying to shoot.
decideWhatAndHowToShoot( objective )
{
self endon( "killanimscript" );
self notify( "stop_deciding_how_to_shoot" );// just in case...
self endon( "stop_deciding_how_to_shoot" );
self endon( "death" );
assert( isdefined( objective ) );// just use "normal" if you don't know what to use
maps\_gameskill::resetMissTime();
self.shootObjective = objective;
// self.shootObjective is always "normal", "suppress", or "ambush"
self.shootEnt = undefined;
self.shootPos = undefined;
self.shootStyle = "none";
self.fastBurst = false;
self.shouldReturnToCover = undefined;
if ( !isdefined( self.changingCoverPos ) )
self.changingCoverPos = false;
atCover = isDefined( self.coverNode ) && self.coverNode.type != "Cover Prone" && self.coverNode.type != "Conceal Prone";
if ( atCover )
{
// it's not safe to do some things until the next frame,
// such as canSuppressEnemy(), which may change the state of
// self.goodShootPos, which will screw up cover_behavior::main
// when this is called but then stopped immediately.
wait .05;
}
prevShootEnt = self.shootEnt;
prevShootPos = self.shootPos;
prevShootStyle = self.shootStyle;
if ( !isdefined( self.has_no_ir ) )
{
self.a.laserOn = true;
self animscripts\shared::updateLaserStatus();
}
if ( self isSniper() )
self resetSniperAim();
// only watch for incoming fire if it will be beneficial for us to return to cover when shot at.
if ( atCover && ( !self.a.atConcealmentNode || !self canSeeEnemy() ) )
thread watchForIncomingFire();
thread runOnShootBehaviorEnd();
self.ambushEndTime = undefined;
prof_begin( "decideWhatAndHowToShoot" );
while ( 1 )
{
if ( isdefined( self.shootPosOverride ) )
{
if ( !isdefined( self.enemy ) )
{
self.shootPos = self.shootPosOverride;
self.shootPosOverride = undefined;
WaitABit();
}
else
{
self.shootPosOverride = undefined;
}
}
assert( self.shootObjective == "normal" || self.shootObjective == "suppress" || self.shootObjective == "ambush" );
assert( !isdefined( self.shootEnt ) || isdefined( self.shootPos ) );// shootPos must be shootEnt's shootAtPos if shootEnt is defined, for convenience elsewhere
result = undefined;
if ( self.weapon == "none" )
noGunShoot();
else if ( usingStreamgun() )
result = streamgunShoot();
else if ( usingRocketLauncher() )
result = rpgShoot();
else if ( usingSidearm() )
result = pistolShoot();
else if ( usingMinigun() )
result = rifleShoot();//minigunShoot();
else
result = rifleShoot();
if ( isDefined( self.a.specialShootBehavior ) )
[[self.a.specialShootBehavior]]();
if ( checkChanged( prevShootEnt, self.shootEnt ) || ( !isdefined( self.shootEnt ) && checkChanged( prevShootPos, self.shootPos ) ) || checkChanged( prevShootStyle, self.shootStyle ) )
self notify( "shoot_behavior_change" );
prevShootEnt = self.shootEnt;
prevShootPos = self.shootPos;
prevShootStyle = self.shootStyle;
// (trying to prevent many AI from doing lots of work on the same frame)
if ( !isdefined( result ) )
WaitABit();
}
prof_end( "decideWhatAndHowToShoot" );
}
WaitABit()
{
self endon( "enemy" );
self endon( "done_changing_cover_pos" );
self endon( "weapon_position_change" );
self endon( "enemy_visible" );
if ( isdefined( self.shootEnt ) )
{
self.shootEnt endon( "death" );
self endon( "do_slow_things" );
// (want to keep self.shootPos up to date)
wait .05;
while ( isdefined( self.shootEnt ) )
{
self.shootPos = self.shootEnt getShootAtPos();
wait .05;
}
}
else
{
self waittill( "do_slow_things" );
}
}
noGunShoot()
{
/#
println( "^1Warning: AI at " + self.origin + ", entnum " + self getEntNum() + ", export " + self.export + " trying to shoot but has no gun" );
#/
self.shootEnt = undefined;
self.shootPos = undefined;
self.shootStyle = "none";
self.shootObjective = "normal";
}
shouldSuppress()
{
return !self isSniper() && !isShotgun( self.weapon );
}
shouldShootEnemyEnt()
{
assert( isDefined ( self ) );
if ( !self canSeeEnemy() )
return false;
// When not in cover, check if we can shoot at our current enemy as well
if ( !isDefined( self.coverNode ) && !self canShootEnemy() )
return false;
return true;
}
rifleShootObjectiveNormal()
{
if ( !shouldShootEnemyEnt() )
{
// enemy disappeared!
if ( self isSniper() )
self resetSniperAim();
if ( self.doingAmbush )
{
self.shootObjective = "ambush";
return "retry";
}
if ( !isdefined( self.enemy ) )
{
haveNothingToShoot();
}
else
{
markEnemyPosInvisible();
if ( ( self.provideCoveringFire || randomint( 5 ) > 0 ) && shouldSuppress() )
self.shootObjective = "suppress";
else
self.shootObjective = "ambush";
return "retry";
}
}
else
{
setShootEntToEnemy();
self setShootStyleForVisibleEnemy();
}
}
rifleShootObjectiveSuppress( enemySuppressable )
{
if ( !enemySuppressable )
{
haveNothingToShoot();
}
else
{
self.shootEnt = undefined;
self.shootPos = getEnemySightPos();
self setShootStyleForSuppression();
}
}
rifleShootObjectiveAmbush( enemySuppressable )
{
assert( self.shootObjective == "ambush" );
self.shootStyle = "none";
self.shootEnt = undefined;
if ( !enemySuppressable )
{
getAmbushShootPos();
if ( shouldStopAmbushing() )
{
self.ambushEndTime = undefined;
self notify( "return_to_cover" );
self.shouldReturnToCover = true;
}
}
else
{
self.shootPos = getEnemySightPos();
if ( self shouldStopAmbushing() )
{
self.ambushEndTime = undefined;
if ( shouldSuppress() )
self.shootObjective = "suppress";
if ( randomint( 3 ) == 0 )
{
self notify( "return_to_cover" );
self.shouldReturnToCover = true;
}
return "retry";
}
}
}
getAmbushShootPos()
{
if ( isdefined( self.enemy ) && self cansee( self.enemy ) )
{
setShootEntToEnemy();
return;
}
likelyEnemyDir = self getAnglesToLikelyEnemyPath();
if ( !isdefined( likelyEnemyDir ) )
{
if ( isDefined( self.coverNode ) )
likelyEnemyDir = self.coverNode.angles;
else if ( isdefined( self.ambushNode ) )
likelyEnemyDir = self.ambushNode.angles;
else if ( isdefined( self.enemy ) )
likelyEnemyDir = vectorToAngles( self lastKnownPos( self.enemy ) - self.origin );
else
likelyEnemyDir = self.angles;
}
dist = 1024;
if ( isdefined( self.enemy ) )
dist = distance( self.origin, self.enemy.origin );
newShootPos = self getEye() + anglesToForward( likelyEnemyDir ) * dist;
if ( !isdefined( self.shootPos ) || distanceSquared( newShootPos, self.shootPos ) > 5 * 5 )// avoid frequent "shoot_behavior_change" notifies
self.shootPos = newShootPos;
}
rifleShoot()
{
if ( self.shootObjective == "normal" )
{
rifleShootObjectiveNormal();
}
else
{
if ( shouldShootEnemyEnt() )// later, maybe we can be more realistic than just shooting at the enemy the instant he becomes visible
{
self.shootObjective = "normal";
self.ambushEndTime = undefined;
return "retry";
}
markEnemyPosInvisible();
if ( self isSniper() )
self resetSniperAim();
enemySuppressable = canSuppressEnemy();
if ( self.shootObjective == "suppress" || ( self.team == "allies" && !isdefined( self.enemy ) && !enemySuppressable ) )
rifleShootObjectiveSuppress( enemySuppressable );
else
rifleShootObjectiveAmbush( enemySuppressable );
}
}
streamgunShoot()
{
if ( shouldShootEnemyEnt() )
{
setShootEntToEnemy();
setShootStyle( "continuous", false );
}
}
shouldStopAmbushing()
{
if ( !isdefined( self.ambushEndTime ) )
{
if ( self isBadGuy() )
self.ambushEndTime = gettime() + randomintrange( 10000, 60000 );
else
self.ambushEndTime = gettime() + randomintrange( 4000, 10000 );
}
return self.ambushEndTime < gettime();
}
rpgShoot()
{
if ( !shouldShootEnemyEnt() )
{
markEnemyPosInvisible();
haveNothingToShoot();
return;
}
setShootEntToEnemy();
self.shootStyle = "single";
distSqToShootPos = lengthsquared( self.origin - self.shootPos );
// too close for RPG
if ( distSqToShootPos < squared( 512 ) )
{
self notify( "return_to_cover" );
self.shouldReturnToCover = true;
return;
}
}
pistolShoot()
{
if ( self.shootObjective == "normal" )
{
if ( !shouldShootEnemyEnt() )
{
// enemy disappeared!
if ( !isdefined( self.enemy ) )
{
haveNothingToShoot();
return;
}
else
{
markEnemyPosInvisible();
self.shootObjective = "ambush";
return "retry";
}
}
else
{
setShootEntToEnemy();
self.shootStyle = "single";
}
}
else
{
if ( shouldShootEnemyEnt() )// later, maybe we can be more realistic than just shooting at the enemy the instant he becomes visible
{
self.shootObjective = "normal";
self.ambushEndTime = undefined;
return "retry";
}
markEnemyPosInvisible();
self.shootEnt = undefined;
self.shootStyle = "none";
self.shootPos = getEnemySightPos();
// stop ambushing after a while
if ( !isdefined( self.ambushEndTime ) )
self.ambushEndTime = gettime() + randomintrange( 4000, 8000 );
if ( self.ambushEndTime < gettime() )
{
self.shootObjective = "normal";
self.ambushEndTime = undefined;
return "retry";
}
}
}
markEnemyPosInvisible()
{
if ( isdefined( self.enemy ) && !self.changingCoverPos && self.script != "combat" )
{
// make sure they're not just hiding
if ( isAI( self.enemy ) && isdefined( self.enemy.script ) && ( self.enemy.script == "cover_stand" || self.enemy.script == "cover_crouch" ) )
{
if ( isdefined( self.enemy.a.coverMode ) && self.enemy.a.coverMode == "hide" )
return;
}
self.couldntSeeEnemyPos = self.enemy.origin;
}
}
watchForIncomingFire()
{
self endon( "killanimscript" );
self endon( "stop_deciding_how_to_shoot" );
while ( 1 )
{
self waittill( "suppression" );
if ( self.suppressionMeter > self.suppressionThreshold )
{
if ( self readyToReturnToCover() )
{
self notify( "return_to_cover" );
self.shouldReturnToCover = true;
}
}
}
}
readyToReturnToCover()
{
if ( self.changingCoverPos )
return false;
assert( isdefined( self.coverPosEstablishedTime ) );
if ( !isdefined( self.enemy ) || !self canSee( self.enemy ) )
return true;
if ( gettime() < self.coverPosEstablishedTime + 800 )
{
// don't return to cover until we had time to fire a couple shots;
// better to look daring than indecisive
return false;
}
if ( isPlayer( self.enemy ) && self.enemy.health < self.enemy.maxHealth * .5 )
{
// give ourselves some time to take them down
if ( gettime() < self.coverPosEstablishedTime + 3000 )
return false;
}
return true;
}
runOnShootBehaviorEnd()
{
self endon( "death" );
self waittill_any( "killanimscript", "stop_deciding_how_to_shoot"/*, "return_to_cover"*/ );
self.a.laserOn = false;
self animscripts\shared::updateLaserStatus();
}
checkChanged( prevval, newval )
{
if ( isdefined( prevval ) != isdefined( newval ) )
return true;
if ( !isdefined( newval ) )
{
assert( !isdefined( prevval ) );
return false;
}
return prevval != newval;
}
setShootEntToEnemy()
{
self.shootEnt = self.enemy;
self.shootPos = self.shootEnt getShootAtPos();
}
haveNothingToShoot()
{
self.shootEnt = undefined;
self.shootPos = undefined;
self.shootStyle = "none";
if ( self.doingAmbush )
self.shootObjective = "ambush";
if ( !self.changingCoverPos )
{
self notify( "return_to_cover" );
self.shouldReturnToCover = true;
}
}
shouldBeAJerk()
{
return level._gameskill == 3 && isPlayer( self.enemy );// && self shouldDoSemiForVariety();
}
fullAutoRangeSq = 250 * 250;
burstRangeSq = 900 * 900;
singleShotRangeSq = 1600 * 1600;
setShootStyleForVisibleEnemy()
{
assert( isdefined( self.shootPos ) );
assert( isdefined( self.shootEnt ) );
if ( isdefined( self.shootEnt.enemy ) && isdefined( self.shootEnt.enemy.syncedMeleeTarget ) )
return setShootStyle( "single", false );
if ( self isSniper() )
return setShootStyle( "single", false );
if ( isStreamgun( self.weapon ) )
{
return setShootStyle( "continuous", false );
}
if ( isShotgun( self.weapon ) )
{
if ( weapon_pump_action_shotgun() )
return setShootStyle( "single", false );
else
return setShootStyle( "semi", false );
}
if ( weaponBurstCount( self.weapon ) > 0 )
return setShootStyle( "burst", false );
distanceSq = distanceSquared( self getShootAtPos(), self.shootPos );
isMG = weaponClass( self.weapon ) == "mg";
if ( self.provideCoveringFire && isMG )
return setShootStyle( "full", false );
if ( distanceSq < fullAutoRangeSq )
{
if ( isdefined( self.shootEnt ) && isdefined( self.shootEnt.magic_bullet_shield ) )
return setShootStyle( "single", false );
else
return setShootStyle( "full", false );
}
else if ( distanceSq < burstRangeSq || shouldBeAJerk() )
{
if ( weaponIsSemiAuto( self.weapon ) || shouldDoSemiForVariety() )
return setShootStyle( "semi", true );
else
return setShootStyle( "burst", true );
}
else if ( self.provideCoveringFire || isMG || distanceSq < singleShotRangeSq )
{
if ( shouldDoSemiForVariety() )
return setShootStyle( "semi", false );
else
return setShootStyle( "burst", false );
}
return setShootStyle( "single", false );
}
setShootStyleForSuppression()
{
assert( isdefined( self.shootPos ) );
distanceSq = distanceSquared( self getShootAtPos(), self.shootPos );
assert( !self isSniper() );// snipers shouldn't be suppressing!
assert( !isShotgun( self.weapon ) );// shotgun users shouldn't be suppressing!
assert( !isStreamgun( self.weapon ) ); // streamguns shouldn't be suppressing!
if ( weaponIsSemiAuto( self.weapon ) )
{
if ( distanceSq < singleShotRangeSq )
return setShootStyle( "semi", false );
return setShootStyle( "single", false );
}
if ( weaponClass( self.weapon ) == "mg" )
return setShootStyle( "full", false );
if ( self.provideCoveringFire || distanceSq < singleShotRangeSq )
{
if ( shouldDoSemiForVariety() )
return setShootStyle( "semi", false );
else
return setShootStyle( "burst", false );
}
return setShootStyle( "single", false );
}
setShootStyle( style, fastBurst )
{
self.shootStyle = style;
self.fastBurst = fastBurst;
}
shouldDoSemiForVariety()
{
if ( weaponClass( self.weapon ) != "rifle" )
return false;
if ( self.team != "allies" )
return false;
// true randomness isn't safe, because that will cause frequent shoot_behavior_change notifies.
// fake the randomness in a way that won't change frequently.
changeFrequency = safemod( int( self.origin[ 1 ] ), 10000 ) + 2000;
fakeTimeValue = int( self.origin[ 0 ] ) + gettime();
return fakeTimeValue %( 2 * changeFrequency ) > changeFrequency;
}
resetSniperAim()
{
assert( self isSniper() );
self.sniperShotCount = 0;
self.sniperHitCount = 0;
thread sniper_glint_behavior();
}
sniper_glint_behavior()
{
self endon( "killanimscript" );
self endon( "enemy" );
self endon( "return_to_cover" );
self notify( "new_glint_thread" );
self endon( "new_glint_thread" );
assertex( self isSniper(), "Not a sniper!" );
if ( !isdefined( level._effect[ "sniper_glint" ] ) )
{
println( "^3Warning, sniper glint is not setup for sniper with classname " + self.classname );
return;
}
if ( !isAlive( self.enemy ) )
return;
//if ( !isPlayer( self.enemy ) )
// return;
fx = getfx( "sniper_glint" );
wait 0.2;
for ( ;; )
{
if ( self.weapon == self.primaryweapon && player_sees_my_scope() )
{
if ( distanceSquared( self.origin, self.enemy.origin ) > 256 * 256 )
PlayFXOnTag( fx, self, "tag_flash" );
timer = randomfloatrange( 3, 5 );
wait( timer );
}
wait( 0.2 );
}
}

957
animscripts/snowmobile.gsc Normal file
View File

@ -0,0 +1,957 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\_anim;
#include animscripts\shared;
#include animscripts\utility;
#using_animtree( "generic_human" );
CONST_MPHCONVERSION = 17.6;
main()
{
assert( isdefined( self.ridingvehicle ) );
self.current_event = "none";
self.shoot_while_driving_thread = undefined;
self snowmobile_geton();
if ( isdefined( self.drivingvehicle ) )
main_driver();
else
main_passenger();
}
snowmobile_geton()
{
self.grenadeawareness = 0;
self.a.pose = "crouch";
self disable_surprise();
self.allowpain = false;
self.getOffVehicleFunc = ::snowmobile_getoff;
self.specialDeathFunc = animscripts\snowmobile::snowmobile_normal_death;
self.disableBulletWhizbyReaction = true;
}
snowmobile_getoff()
{
self.allowpain = true;
self.getOffVehicleFunc = undefined;
self.specialDeathFunc = undefined;
self.a.specialShootBehavior = undefined;
self.disableBulletWhizbyReaction = undefined;
}
main_driver()
{
driver_shooting = self.ridingvehicle.driver_shooting || self.ridingvehicle.riders.size == 1;
snowmobile_setanim_driver( driver_shooting );
if ( driver_shooting )
{
placeweaponon( self.primaryweapon, "left" );
self.rightaimlimit = 90;
self.leftaimlimit = -90;
self setanimaimweight( 1, 0.2 );
self thread snowmobile_trackshootentorpos_driver();
self thread snowmobile_loop_driver_shooting();
}
else
{
placeweaponon( self.primaryweapon, "none" );
self thread snowmobile_loop_driver();
}
snowmobile_handle_events( "driver" );
}
main_passenger()
{
snowmobile_setanim_passenger( self.ridingvehicle.passenger_shooting );
if ( self.ridingvehicle.passenger_shooting )
{
self.rightaimlimit = 180;
self.leftaimlimit = -180;
self.diraimlimit = 1;
self setanimaimweight( 1, 0.2 );
self thread snowmobile_trackshootentorpos_passenger();
self thread snowmobile_loop_passenger_shooting();
}
else
{
self thread snowmobile_loop_passenger();
}
snowmobile_handle_events( "passenger" );
}
snowmobile_loop_driver()
{
self endon( "death" );
self endon( "killanimscript" );
current_anim = "left2right";
anim_length = [];
anim_length[ "left2right" ] = getanimlength( animarray( "left2right" ) );
anim_length[ "right2left" ] = getanimlength( animarray( "right2left" ) );
self setanimknoball( %sm_turn, %body, 1, 0 );
self setanim( animarray( "drive" ), 1, 0 );
self setanimknob( animarray( current_anim ), 1, 0 );
self setanimtime( animarray( current_anim ), 0.5 );
for ( ;; )
{
if ( self.ridingvehicle.steering_enable )
{
steering = 0.5*(1 + maps\_vehicle::update_steering( self.ridingvehicle ));
anim_time = self getanimtime( animarray( current_anim ) );
if ( current_anim == "right2left" )
anim_time = 1 - anim_time;
rate = 20*abs( anim_time - steering );
if ( anim_time < steering )
{
current_anim = "left2right";
rate *= anim_length[ "left2right" ];
}
else
{
current_anim = "right2left";
rate *= anim_length[ "right2left" ];
anim_time = 1 - anim_time;
}
}
else
{
current_anim = "left2right";
rate = 0;
anim_time = 0.5;
}
self setanimknoblimited( animarray( current_anim ), 1, 0.1, rate );
self setanimtime( animarray( current_anim ), anim_time );
wait( 0.05 );
}
}
snowmobile_loop_passenger()
{
self endon( "death" );
self endon( "killanimscript" );
self setanimknoball( animarray( "hide" ), %body, 1, 0 );
self setanimknob( animarray( "drive" ), 1, 0 );
for (;;)
{
steering = maps\_vehicle::update_steering( self.ridingvehicle );
self setanimlimited( %sm_lean, abs( steering ), 0.05 );
if ( steering >= 0 ) {
self setanimknoblimited( animarray( "lean_right" ), 1, 0.05 );
} else {
self setanimknoblimited( animarray( "lean_left" ), 1, 0.05 );
}
wait 0.05;
}
}
snowmobile_loop_driver_shooting()
{
self endon( "death" );
self endon( "killanimscript" );
leanblendtime = .05;
reloadFinishedTime = 0;
self setanimknoball( %sm_aiming, %body, 1, 0 );
self setanimknob( animarray( "idle" ), 1, 0 );
for ( ;; )
{
if ( self.current_event != "none" )
{
self waittill( "snowmobile_event_finished" );
continue;
}
steering = maps\_vehicle::update_steering( self.ridingvehicle );
center_steering = 1 - abs( steering );
left_steering = max( 0, 0 - steering );
right_steering = max( 0, steering );
self setanimlimited( animarray( "straight_level_center" ), center_steering, leanblendtime );
self setanimlimited( animarray( "straight_level_left" ), left_steering, leanblendtime );
self setanimlimited( animarray( "straight_level_right" ), right_steering, leanblendtime );
if ( self.bulletsinclip <= 0 )
{
self animscripts\weaponList::RefillClip();
reloadFinishedTime = gettime() + 3000;
}
if ( reloadFinishedTime <= gettime() )
snowmobile_start_shooting();
self setanimknoblimited( animarray( "add_aim_left_center" ), center_steering, leanblendtime );
self setanimlimited( animarray( "add_aim_left_left" ), left_steering, leanblendtime );
self setanimlimited( animarray( "add_aim_left_right" ), right_steering, leanblendtime );
self setanimknoblimited( animarray( "add_aim_right_center" ), center_steering, leanblendtime );
self setanimlimited( animarray( "add_aim_right_left" ), left_steering, leanblendtime );
self setanimlimited( animarray( "add_aim_right_right" ), right_steering, leanblendtime );
self thread snowmobile_stop_shooting();
wait( 0.05 );
}
}
snowmobile_loop_passenger_shooting()
{
self endon( "death" );
self endon( "killanimscript" );
leanblendtime = .05;
self setanimknoball( %sm_aiming, %body, 1, 0 );
self setanimknob( animarray( "idle" ), 1, 0 );
for ( ;; )
{
if ( self.current_event != "none" )
{
self waittill( "snowmobile_event_finished" );
continue;
}
if ( snowmobile_reload() )
continue;
steering = maps\_vehicle::update_steering( self.ridingvehicle );
center_steering = 1 - abs( steering );
left_steering = max( 0, 0 - steering );
right_steering = max( 0, steering );
self setanimlimited( animarray( "straight_level_center" ), center_steering, leanblendtime );
self setanimlimited( animarray( "straight_level_left" ), left_steering, leanblendtime );
self setanimlimited( animarray( "straight_level_right" ), right_steering, leanblendtime );
snowmobile_start_shooting();
self setanimlimited( animarray( "aim_left_center" ), center_steering, leanblendtime );
self setanimlimited( animarray( "aim_left_left" ), left_steering, leanblendtime );
self setanimlimited( animarray( "aim_left_right" ), right_steering, leanblendtime );
self setanimlimited( animarray( "aim_right_center" ), center_steering, leanblendtime );
self setanimlimited( animarray( "aim_right_left" ), left_steering, leanblendtime );
self setanimlimited( animarray( "aim_right_right" ), right_steering, leanblendtime );
self setanimlimited( animarray( "add_aim_backleft_center" ), center_steering, leanblendtime );
self setanimlimited( animarray( "add_aim_backleft_left" ), left_steering, leanblendtime );
self setanimlimited( animarray( "add_aim_backleft_right" ), right_steering, leanblendtime );
self setanimlimited( animarray( "add_aim_backright_center" ), center_steering, leanblendtime );
self setanimlimited( animarray( "add_aim_backright_left" ), left_steering, leanblendtime );
self setanimlimited( animarray( "add_aim_backright_right" ), right_steering, leanblendtime );
if ( isplayer( self.enemy ) )
self updateplayersightaccuracy();
wait( 0.05 );
self thread snowmobile_stop_shooting(); // stop shooting on the next frame unless snowmobile_start_shooting is called again
}
}
snowmobile_do_event( animation )
{
self endon( "death" );
self.ridingvehicle.steering_enable = false;
self setflaggedanimknoblimitedrestart( "snowmobile_event", animation, 1, 0.17 );
donotetracks( "snowmobile_event", ::snowmobile_waitfor_start_lean );
self setanimknoblimited( animarray( "event_restore" ), 1, 0.1 );
self.ridingvehicle.steering_enable = true;
self.current_event = "none";
self notify( "snowmobile_event_finished" );
}
snowmobile_handle_events( rider )
{
self endon( "death" );
self endon( "killanimscript" );
snowmobile = self.ridingvehicle;
for ( ;; )
{
if ( snowmobile.event[ "jump" ][ rider ] )
{
snowmobile.event[ "jump" ][ rider ] = false;
self notify( "snowmobile_event_occurred" );
self.current_event = "jump";
snowmobile.steering_enable = false;
self setflaggedanimknoblimitedrestart( "jump", animarray( "event_jump" ), 1, 0.17 );
}
if ( snowmobile.event[ "bump" ][ rider ] )
{
snowmobile.event[ "bump" ][ rider ] = false;
self notify( "snowmobile_event_occurred" );
if ( self.current_event != "bump_big" )
self thread snowmobile_do_event( animarray( "event_bump" ) );
}
if ( snowmobile.event[ "bump_big" ][ rider ] )
{
snowmobile.event[ "bump_big" ][ rider ] = false;
self notify( "snowmobile_event_occurred" );
self.current_event = "bump_big";
self thread snowmobile_do_event( animarray( "event_bump_big" ) );
}
if ( snowmobile.event[ "sway_left" ][ rider ] )
{
snowmobile.event[ "sway_left" ][ rider ] = false;
self notify( "snowmobile_event_occurred" );
if ( self.current_event != "bump_big" )
self thread snowmobile_do_event( animarray( "event_sway" )[ "left" ] );
}
if ( snowmobile.event[ "sway_right" ][ rider ] )
{
snowmobile.event[ "sway_right" ][ rider ] = false;
self notify( "snowmobile_event_occurred" );
if ( self.current_event != "bump_big" )
self thread snowmobile_do_event( animarray( "event_sway" )[ "right" ] );
}
wait( 0.05 );
}
}
snowmobile_start_shooting()
{
self notify( "want_shoot_while_driving" );
self setAnim( %sm_add_fire, 1, 0.2 );
if ( isdefined( self.shoot_while_driving_thread ) )
return;
self.shoot_while_driving_thread = true;
self thread snowmobile_decide_shoot();
self thread snowmobile_shoot();
}
snowmobile_stop_shooting()
{
self endon( "killanimscript" );
self endon( "want_shoot_while_driving" );
wait .05;
self notify( "end_shoot_while_driving" );
self.shoot_while_driving_thread = undefined;
self clearAnim( %sm_add_fire, 0.2 );
}
snowmobile_decide_shoot()
{
self endon( "killanimscript" );
self endon( "end_shoot_while_driving" );
self.a.specialShootBehavior = ::snowmobileShootBehavior;
snowmobile_decide_shoot_internal();
self.shoot_while_driving_thread = undefined; // start shooting again the next time we want it
}
snowmobile_decide_shoot_internal()
{
// events stop the shooting animations, so stop shooting when they happen
self endon( "snowmobile_event_occurred" );
self animscripts\shoot_behavior::decideWhatAndHowToShoot( "normal" );
}
snowmobileShootBehavior()
{
if ( !isdefined( self.enemy ) )
{
self.shootent = undefined;
self.shootpos = undefined;
self.shootstyle = "none";
return;
}
self.shootent = self.enemy;
self.shootpos = self.enemy getShootAtPos();
distSq = distanceSquared( self.origin, self.enemy.origin );
if ( distSq < 1000*1000 )
self.shootstyle = "full";
else if ( distSq < 2000*2000 )
self.shootstyle = "burst";
else
self.shootstyle = "single";
if ( isdefined( self.enemy.vehicle ) )
{
shoot_ahead_speed_multiplier = 0.5;
//shoot_ahead_random_spread = 50;
vehicle = self.shootent.vehicle;
snowmobile = self.ridingvehicle;
delta = snowmobile.origin - vehicle.origin;
forward = anglestoforward( vehicle.angles );
right = anglestoright( vehicle.angles );
dot = vectordot( delta, forward );
if ( dot < 0 )
{
speed = vehicle vehicle_getspeed() * shoot_ahead_speed_multiplier;
speed *= CONST_MPHCONVERSION;
if ( speed > 50 )
{
sideness = vectordot( delta, right );
sideness /= 3;
if ( sideness > 128 )
sideness = 128;
else if ( sideness < -128 )
sideness = -128;
// flip it so guys farther to the side shoot in front of you
if ( sideness > 0 )
sideness = 128 - sideness;
else
sideness = -128 - sideness;
self.shootent = undefined;
self.shootpos = vehicle.origin + speed * forward + sideness * right;
return;
}
}
}
}
snowmobile_shoot()
{
self endon( "killanimscript" );
self endon( "end_shoot_while_driving" );
self notify( "doing_shootWhileDriving" );
self endon( "doing_shootWhileDriving" );
for ( ;; )
{
if ( !self.bulletsInClip )
{
wait 0.5;
continue;
}
self animscripts\combat_utility::shootUntilShootBehaviorChange();
// self clearAnim( %exposed_modern, 0.2 );
}
}
snowmobile_reload()
{
if ( !self.ridingvehicle.steering_enable )
return false;
if ( !self animscripts\combat_utility::needtoreload( 0 ) )
return false;
if ( !usingRifleLikeWeapon() )
return false;
snowmobile_reload_internal();
// notify "abort_reload" in case the reload didn't finish. works with handledropclip() in shared.gsc
self notify( "abort_reload" );
return true;
}
snowmobile_reload_internal()
{
self endon( "snowmobile_event_occurred" );
self.stop_aiming_for_reload = true;
self waittill( "start_blending_reload" );
self setanim( %sm_aiming, 0, 0.25 );
self setflaggedanimrestart( "gun_down", animarray( "gun_down" ), 1, 0.25 );
DoNoteTracks( "gun_down" );
self clearAnim( animarray( "gun_down" ), 0 );
self setflaggedanimknoballrestart( "reload_anim", animarray( "reload" ), %body, 1, 0.25 );
DoNoteTracks( "reload_anim" );
self clearAnim( %sm_reload, 0.2 );
self setflaggedanimrestart( "gun_up", animarray( "gun_up" ), 1, 0.25 );
self.gun_up_for_reload = true;
DoNoteTracks( "gun_up", ::snowmobile_waitfor_start_aim );
self.stop_aiming_for_reload = undefined;
self clearAnim( %sm_reload, 0.1 );
self setanim( %sm_aiming, 1, 0.1 );
if ( isdefined( self.gun_up_for_reload ) )
{
self.gun_up_for_reload = undefined;
DoNoteTracks( "gun_up", ::snowmobile_waitfor_end );
self clearAnim( animarray( "gun_up" ), 0 );
}
}
snowmobile_waitfor_start_aim( note )
{
if ( note == "start_aim" )
return true;
}
snowmobile_waitfor_end( note )
{
if ( note == "end" )
return true;
}
snowmobile_waitfor_start_lean( note )
{
if ( note == "start_lean" )
return true;
}
snowmobile_trackshootentorpos_driver()
{
self endon( "killanimscript" );
self endon( "stop tracking" );
/#
assert( !isdefined( self.trackLoopThread ) );
self.trackLoopThread = thisthread;
self.trackLoopThreadType = "snowmobile_trackshootentorpos_driver";
#/
aimblendtime = .05;
maxyawdeltachange = 8;// max change in yaw in 1 frame
prevyawdelta = 0;
yawdelta = 0;
firstframe = true;
for ( ;; )
{
incranimaimweight();
selfshootatpos = ( self.origin[ 0 ], self.origin[ 1 ], self geteye()[ 2 ] );
shootpos = self.shootpos;
if ( isdefined( self.shootent ) )
shootpos = self.shootent getshootatpos();
if ( !isdefined( shootpos ) )
{
assert( !isdefined( self.shootent ) );
yawdelta = 0;
likelyenemydir = self getanglestolikelyenemypath();
if ( isdefined( likelyenemydir ) )
{
yawdelta = angleclamp180( self.angles[ 1 ] - likelyenemydir[ 1 ] );
}
}
else
{
vectortoshootpos = shootpos - selfshootatpos;
anglestoshootpos = vectortoangles( vectortoshootpos );
yawdelta = self.angles[ 1 ] - anglestoshootpos[ 1 ];
yawdelta = angleclamp180( yawdelta );
}
assert( self.rightaimlimit >= 0 );
assert( self.leftaimlimit <= 0 );
if ( yawdelta > self.rightaimlimit || yawdelta < self.leftaimlimit )
yawdelta = 0;
if ( firstframe )
{
firstframe = false;
}
else
{
yawdeltachange = yawdelta - prevyawdelta;
if ( abs( yawdeltachange ) > maxyawdeltachange )
yawdelta = prevyawdelta + maxyawdeltachange * sign( yawdeltachange );
}
prevyawdelta = yawdelta;
weight4 = min( max( 0 - yawdelta, 0 ), 90 ) / 90 * self.a.aimweight;
weight6 = min( max( yawdelta, 0 ), 90 ) / 90 * self.a.aimweight;
self setanimlimited( %sm_aim_4, weight4, aimblendtime );
self setanimlimited( %sm_aim_6, weight6, aimblendtime );
wait( 0.05 );
}
}
snowmobile_trackshootentorpos_passenger()
{
self endon( "killanimscript" );
self endon( "stop tracking" );
/#
assert( !isdefined( self.trackLoopThread ) );
self.trackLoopThread = thisthread;
self.trackLoopThreadType = "snowmobile_trackshootentorpos_passenger";
#/
aimblendtime = .05;
maxyawdeltachange_default = 5;// max change in yaw in 1 frame
maxyawdeltachange_fast = 20;
maxyawdeltachange_reload = 15;
yawdelta_overshoot_begin = 40;
yawdelta_overshoot_end = 30;
prevyawdelta = 0;
yawdelta = 0;
firstframe = true;
for ( ;; )
{
incranimaimweight();
selfshootatpos = ( self.origin[ 0 ], self.origin[ 1 ], self geteye()[ 2 ] );
shootpos = self.shootpos;
if ( isdefined( self.shootent ) )
shootpos = self.shootent getshootatpos();
if ( !isdefined( shootpos ) )
{
assert( !isdefined( self.shootent ) );
yawdelta = 0;
likelyenemydir = self getanglestolikelyenemypath();
if ( isdefined( likelyenemydir ) )
{
yawdelta = angleclamp180( self.angles[ 1 ] - likelyenemydir[ 1 ] );
}
}
else
{
vectortoshootpos = shootpos - selfshootatpos;
anglestoshootpos = vectortoangles( vectortoshootpos );
yawdelta = self.angles[ 1 ] - anglestoshootpos[ 1 ];
yawdelta = angleclamp180( yawdelta );
//line( selfshootatpos, shootpos );
}
assert( self.diraimlimit == 1 || self.diraimlimit == -1 );
if ( isdefined( self.stop_aiming_for_reload ) || ( yawdelta > 0 && ( yawdelta - self.rightaimlimit ) * self.diraimlimit > 0 ) || ( yawdelta < 0 && ( yawdelta - self.leftaimlimit ) * self.diraimlimit < 0 ) )
yawdelta = 0;
if ( firstframe )
{
firstframe = false;
}
else
{
if ( prevyawdelta < -180 + yawdelta_overshoot_begin && yawdelta > 180 - yawdelta_overshoot_end )
yawdelta = -179;
if ( prevyawdelta > 180 - yawdelta_overshoot_begin && yawdelta < -180 + yawdelta_overshoot_end )
yawdelta = 179;
yawdeltachange = yawdelta - prevyawdelta;
maxyawdeltachange = (maxyawdeltachange_fast - maxyawdeltachange_default) * abs( yawdeltachange ) / 180 + maxyawdeltachange_default;
if ( isdefined( self.stop_aiming_for_reload ) )
{
maxyawdeltachange = maxyawdeltachange_reload;
if ( abs( prevyawdelta ) < 45 )
self notify( "start_blending_reload" );
}
if ( abs( yawdeltachange ) > maxyawdeltachange )
yawdelta = prevyawdelta + maxyawdeltachange * sign( yawdeltachange );
}
prevyawdelta = yawdelta;
weight1 = max( -90 - yawdelta, 0 ) / 90 * self.a.aimweight;
weight4 = min( max( 0 - yawdelta, 0 ), 90 ) / 90 * self.a.aimweight;
weight5 = max( 90 - abs( yawdelta ), 0 ) / 90 * self.a.aimweight;
weight6 = min( max( yawdelta, 0 ), 90 ) / 90 * self.a.aimweight;
weight3 = max( -90 + yawdelta, 0 ) / 90 * self.a.aimweight;
self setanimlimited( %sm_aim_1, weight1, aimblendtime );
self setanimlimited( %sm_aim_4_delta, weight4, aimblendtime );
self setanimlimited( %sm_aim_5_delta, weight5, aimblendtime );
self setanimlimited( %sm_aim_6_delta, weight6, aimblendtime );
self setanimlimited( %sm_aim_3, weight3, aimblendtime );
wait( 0.05 );
}
}
snowmobile_get_death_anim( deathAnims, deathAnimDirs, goalDir )
{
bestDeathAnim = undefined;
secondBestDeathAnim = undefined;
bestDeathAnimDiff = 0;
for ( i = 0; i < deathAnims.size; i++ )
{
diff = AbsAngleClamp180( goalDir - deathAnimDirs[i] );
if ( !isdefined( bestDeathAnim ) || diff < bestDeathAnimDiff )
{
secondBestDeathAnim = bestDeathAnim;
bestDeathAnim = deathAnims[i];
bestDeathAnimDiff = diff;
}
else if ( !isdefined( secondBestDeathAnim ) )
{
secondBestDeathAnim = deathAnims[i];
}
}
assert( isdefined( bestDeathAnim ) );
assert( isdefined( secondBestDeathAnim ) );
deathAnim = bestDeathAnim;
if ( isDefined( anim.prevSnowmobileDeath ) && deathAnim == anim.prevSnowmobileDeath && gettime() - anim.prevSnowmobileDeathTime < 500 )
deathAnim = secondBestDeathAnim;
anim.prevSnowmobileDeath = deathAnim;
anim.prevSnowmobileDeathTime = gettime();
return deathAnim;
}
snowmobile_death_launchslide()
{
snowmobile = self.ridingvehicle;
assert( isdefined( snowmobile ) );
velocity = snowmobile.prevFrameVelocity;
velocity = ( velocity[0], velocity[1], randomfloatrange( 200, 400 ) ) * .75;
//println( length( velocity ) );
if ( lengthSquared( velocity ) > 1000 * 1000 )
velocity = vectornormalize( velocity ) * 1000;
model = spawn( "script_origin", self.origin );
model moveSlide( ( 0, 0, 40 ), 15, velocity );
self linkto( model );
model thread deleteShortly();
}
snowmobile_normal_death()
{
//self snowmobile_death_launchslide();
deathAnims = [];
deathAnims[0] = level._scr_anim[ "snowmobile" ][ "small" ][ "death" ][ "back" ];
deathAnims[1] = level._scr_anim[ "snowmobile" ][ "small" ][ "death" ][ "right" ];
deathAnims[2] = level._scr_anim[ "snowmobile" ][ "small" ][ "death" ][ "left" ];
deathAnimDirs = [];
deathAnimDirs[0] = -180;
deathAnimDirs[1] = -90;
deathAnimDirs[2] = 90;
deathAnim = snowmobile_get_death_anim( deathAnims, deathAnimDirs, self.damageyaw );
animscripts\death::playDeathAnim( deathAnim );
return true;
}
snowmobile_collide_death()
{
snowmobile = self.ridingvehicle;
if ( !isdefined( snowmobile ) )
return snowmobile_normal_death();
velocity = snowmobile.prevFrameVelocity;
self snowmobile_death_launchslide();
angles = vectortoangles( velocity );
delta = AngleClamp180( angles[1] - self.angles[1] );
deathAnims = [];
deathAnims[0] = level._scr_anim[ "snowmobile" ][ "big" ][ "death" ][ "back" ];
deathAnims[1] = level._scr_anim[ "snowmobile" ][ "big" ][ "death" ][ "left" ];
deathAnims[2] = level._scr_anim[ "snowmobile" ][ "big" ][ "death" ][ "front" ];
deathAnims[3] = level._scr_anim[ "snowmobile" ][ "big" ][ "death" ][ "right" ];
deathAnimDirs = [];
deathAnimDirs[0] = -180;
deathAnimDirs[1] = -90;
deathAnimDirs[2] = 0;
deathAnimDirs[3] = 90;
deathAnim = snowmobile_get_death_anim( deathAnims, deathAnimDirs, delta );
animscripts\death::playDeathAnim( deathAnim );
return true;
}
deleteShortly()
{
prevorg = self.origin;
for ( i = 0; i < 60; i++ )
{
wait .05;
line(self.origin,prevorg);
prevorg = self.origin;
}
wait 3;
if ( isdefined( self ) )
self delete();
}
snowmobile_setanim_common( seat )
{
self.a.array[ "idle" ] = level._scr_anim[ "snowmobile" ][ seat ][ "idle" ];
self.a.array[ "drive" ] = level._scr_anim[ "snowmobile" ][ seat ][ "drive" ];
self.a.array[ "fire" ] = level._scr_anim[ "snowmobile" ][ seat ][ "fire" ];
self.a.array[ "single" ] = array( level._scr_anim[ "snowmobile" ][ seat ][ "single" ] );
self.a.array[ "burst2" ] = level._scr_anim[ "snowmobile" ][ seat ][ "fire" ];
self.a.array[ "burst3" ] = level._scr_anim[ "snowmobile" ][ seat ][ "fire" ];
self.a.array[ "burst4" ] = level._scr_anim[ "snowmobile" ][ seat ][ "fire" ];
self.a.array[ "burst5" ] = level._scr_anim[ "snowmobile" ][ seat ][ "fire" ];
self.a.array[ "burst6" ] = level._scr_anim[ "snowmobile" ][ seat ][ "fire" ];
self.a.array[ "semi2" ] = level._scr_anim[ "snowmobile" ][ seat ][ "fire" ];
self.a.array[ "semi3" ] = level._scr_anim[ "snowmobile" ][ seat ][ "fire" ];
self.a.array[ "semi4" ] = level._scr_anim[ "snowmobile" ][ seat ][ "fire" ];
self.a.array[ "semi5" ] = level._scr_anim[ "snowmobile" ][ seat ][ "fire" ];
}
snowmobile_setanim_driver( shooting )
{
self.a.array = [];
snowmobile_setanim_common( "driver" );
self.a.array[ "left2right" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "left2right" ];
self.a.array[ "right2left" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "right2left" ];
self.a.array[ "straight_level_left" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "straight_level" ][ "left" ];
self.a.array[ "straight_level_center" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "straight_level" ][ "center" ];
self.a.array[ "straight_level_right" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "straight_level" ][ "right" ];
self.a.array[ "add_aim_left_left" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "add_aim_left" ][ "left" ];
self.a.array[ "add_aim_left_center" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "add_aim_left" ][ "center" ];
self.a.array[ "add_aim_left_right" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "add_aim_left" ][ "right" ];
self.a.array[ "add_aim_right_left" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "add_aim_right" ][ "left" ];
self.a.array[ "add_aim_right_center" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "add_aim_right" ][ "center" ];
self.a.array[ "add_aim_right_right" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "add_aim_right" ][ "right" ];
if ( shooting )
{
self.a.array["event_jump"] = level._scr_anim[ "snowmobile" ][ "driver" ][ "shoot_jump" ];
self.a.array["event_bump"] = level._scr_anim[ "snowmobile" ][ "driver" ][ "shoot_bump" ];
self.a.array["event_bump_big"] = level._scr_anim[ "snowmobile" ][ "driver" ][ "shoot_bump_big" ];
self.a.array["event_sway"] = [];
self.a.array["event_sway"][ "left" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "shoot_sway_left" ];
self.a.array["event_sway"][ "right" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "shoot_sway_right" ];
self.a.array["event_restore"] = %sm_aiming;
}
else
{
self.a.array["event_jump"] = level._scr_anim[ "snowmobile" ][ "driver" ][ "drive_jump" ];
self.a.array["event_bump"] = level._scr_anim[ "snowmobile" ][ "driver" ][ "drive_bump" ];
self.a.array["event_bump_big"] = level._scr_anim[ "snowmobile" ][ "driver" ][ "drive_bump_big" ];
self.a.array["event_sway"] = [];
self.a.array["event_sway"][ "left" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "drive_sway_left" ];
self.a.array["event_sway"][ "right" ] = level._scr_anim[ "snowmobile" ][ "driver" ][ "drive_sway_right" ];
self.a.array["event_restore"] = %sm_turn;
}
}
snowmobile_setanim_passenger( shooting )
{
self.a.array = [];
snowmobile_setanim_common( "passenger" );
self.a.array[ "hide" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "hide" ];
self.a.array[ "lean_left" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "add_lean" ][ "left" ];
self.a.array[ "lean_right" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "add_lean" ][ "right" ];
self.a.array[ "reload" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "reload" ];
self.a.array[ "gun_up" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "gun_up" ];
self.a.array[ "gun_down" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "gun_down" ];
self.a.array[ "aim_left_left" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "aim_left" ][ "left" ];
self.a.array[ "aim_left_center" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "aim_left" ][ "center" ];
self.a.array[ "aim_left_right" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "aim_left" ][ "right" ];
self.a.array[ "aim_right_left" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "aim_right" ][ "left" ];
self.a.array[ "aim_right_center" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "aim_right" ][ "center" ];
self.a.array[ "aim_right_right" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "aim_right" ][ "right" ];
self.a.array[ "add_aim_backleft_left" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "add_aim_backleft" ][ "left" ];
self.a.array[ "add_aim_backleft_center" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "add_aim_backleft" ][ "center" ];
self.a.array[ "add_aim_backleft_right" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "add_aim_backleft" ][ "right" ];
self.a.array[ "add_aim_backright_left" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "add_aim_backright" ][ "left" ];
self.a.array[ "add_aim_backright_center" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "add_aim_backright" ][ "center" ];
self.a.array[ "add_aim_backright_right" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "add_aim_backright" ][ "right" ];
self.a.array[ "straight_level_left" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "straight_level" ][ "left" ];
self.a.array[ "straight_level_center" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "straight_level" ][ "center" ];
self.a.array[ "straight_level_right" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "straight_level" ][ "right" ];
if ( shooting )
{
self.a.array["event_jump"] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "drive_jump" ];
self.a.array["event_bump"] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "drive_bump" ];
self.a.array["event_bump_big"] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "drive_bump_big" ];
self.a.array["event_sway"] = [];
self.a.array["event_sway"][ "left" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "drive_sway_left" ];
self.a.array["event_sway"][ "right" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "drive_sway_right" ];
self.a.array["event_restore"] = %sm_aiming;
}
else
{
self.a.array["event_jump"] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "hide_jump" ];
self.a.array["event_bump"] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "hide_bump" ];
self.a.array["event_bump_big"] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "hide_bump_big" ];
self.a.array["event_sway"] = [];
self.a.array["event_sway"][ "left" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "hide_sway_left" ];
self.a.array["event_sway"][ "right" ] = level._scr_anim[ "snowmobile" ][ "passenger" ][ "hide_sway_right" ];
self.a.array["event_restore"] = %sm_turn;
}
}

View File

@ -0,0 +1,823 @@
// squadmanager.gsc
/****************************************************************************
initialization
*****************************************************************************/
// initializes the squad management system
init_squadManager()
{
if ( isdefined( anim.squadInitialized ) && anim.squadInitialized )
return;
anim.squadCreateFuncs = [];
anim.squadCreateStrings = [];
anim.squads = [];
anim.squadIndex = [];
anim.squadRand = 0;
anim.squadInitialized = true;
}
/****************************************************************************
functionality
*****************************************************************************/
createSquad( squadName, squadCreator )
{
assertex( !isdefined( anim.squads[ squadName ] ), "createSquad attempted to create a squad with the same name as an existing squad" );
//prof_begin( "createSquad" );
anim.squads[ squadName ] = spawnstruct();
squad = anim.squads[ squadName ];
squad.squadName = squadName;
// SRS 10/17/08: added squad.team so we can still support custom-named squads,
// not just "axis" and "allies"
squad.team = getSquadTeam( squadCreator );
squad.sightTime = 0;
squad.origin = undefined;
squad.forward = undefined;
squad.enemy = undefined;
squad.isInCombat = false;
squad.memberCount = 0;
squad.members = [];
squad.officers = [];
squad.officerCount = 0;
squad.squadList = [];
squad.memberAddFuncs = [];
squad.memberAddStrings = [];
squad.memberRemoveFuncs = [];
squad.memberRemoveStrings = [];
squad.squadUpdateFuncs = [];
squad.squadUpdateStrings = [];
squad.squadID = anim.squadIndex.size;
squad initState( "combat", 0.75 );
squad initState( "cover", 0.75 );
squad initState( "move", 0.75 );
squad initState( "stop", 0.75 );
squad initState( "death", 0.75 );
squad initState( "suppressed", 0.75 );
squad initState( "attacking", 0.5 );
// add this squad to the global index
anim.squadIndex[ anim.squadIndex.size ] = squad;
squad updateSquadList();
// notifies for other scripts
level notify( "squad created " + squadName );
anim notify( "squad created " + squadName );
for ( i = 0; i < anim.squadCreateFuncs.size; i++ )
{
squadCreateFunc = anim.squadCreateFuncs[ i ];
squad thread [[ squadCreateFunc ]]();
}
// battlechatter init
// squad animscripts\battlechatter::init_squadBattleChatter();
// tell all other squads to add us to their lists
for ( i = 0; i < anim.squadIndex.size; i++ )
anim.squadIndex[ i ] updateSquadList();
squad thread updateWaiter();
squad thread squadTracker();
squad thread officerWaiter();
squad thread updateMemberStates();
//prof_end( "createSquad" );
return( squad );
}
deleteSquad( squadName )
{
assertex( isdefined( anim.squads[ squadName ] ), "deleteSquad attempted to delete a squad that does not exist" );
if ( squadName == "axis" || squadName == "team3" || squadName == "allies" )
return;
squadID = anim.squads[ squadName ].squadID;
squad = anim.squads[ squadName ];
squad notify( "squad_deleting" );
// for (i = 0; i < squad.members.size; i++)
while ( squad.members.size )
squad.members[ 0 ] addToSquad( squad.members[ 0 ].team );
anim.squadIndex[ squadID ] = anim.squadIndex[ anim.squadIndex.size - 1 ];
anim.squadIndex[ squadID ].squadID = squadID;
anim.squadIndex[ anim.squadIndex.size - 1 ] = undefined;
anim.squads[ squadName ] = undefined;
level notify( "squad deleted " + squadName );
anim notify( "squad deleted " + squadName );
for ( i = 0; i < anim.squadIndex.size; i++ )
anim.squadIndex[ i ] updateSquadList();
}
generateSquadName()
{
squadName = "auto" + anim.squadRand;
anim.squadRand++ ;
return( squadName );
}
addPlayerToSquad( squadName )
{
if ( !isdefined( squadName ) )
{
if ( isdefined( self.script_squadname ) )
squadName = self.script_squadname;
else
squadName = self.team;
}
if ( !isdefined( anim.squads[ squadName ] ) )
{
anim createSquad( squadName, self );
}
squad = anim.squads[ squadName ];
self.squad = squad;
// self.squad updateOrigin();
}
// adds the ai that calls the function to the specified squad
// if not squad is specified, the ai is added to one of the defaults
squadChange()
{
self endon( "death" );
wait( 10.0 );// ???
if ( !isdefined( self.script_squadname ) )
squadName = ( self.team + self.script_flanker );
else
squadName = ( self.script_squadname + self.script_flanker );
self addToSquad( squadName );
}
getSquadTeam( squadCreator )
{
squadTeam = "allies"; // player, allies
if( squadCreator.team == "axis" || squadCreator.team == "neutral" || squadCreator.team == "team3" )
{
squadteam = squadCreator.team;
}
return squadTeam;
}
addToSquad( squadName )
{
assertex( IsSentient( self ), "addToSquad attempted to add a non-sentient member to a squad" );
//prof_begin( "addToSquad" );
if ( !isdefined( squadName ) )
{
if ( isdefined( self.script_flanker ) )
self thread squadChange();
if ( isdefined( self.script_squadname ) )
squadName = self.script_squadname;
else
squadName = self.team;
}
if ( !isdefined( anim.squads[ squadName ] ) )
anim createSquad( squadName, self );
squad = anim.squads[ squadName ];
if ( isdefined( self.squad ) )
{
if ( self.squad == squad )
return;
else
self removeFromSquad();
}
// move to init.gsc
self.lastEnemySightTime = 0;
self.combatTime = 0;
// end move
self.squad = squad;
self.memberID = squad.members.size;
squad.members[ self.memberID ] = self;
squad.memberCount = squad.members.size;
// this is handled in wait for loadout function
if ( isdefined( level._loadoutComplete ) )
{
if ( self.team == "allies" && self animscripts\battlechatter::isOfficer() )
{
self addOfficerToSquad();
}
}
// self.squad updateOrigin();
for ( i = 0; i < self.squad.memberAddFuncs.size; i++ )
{
memberAddFunc = self.squad.memberAddFuncs[ i ];
self thread [[ memberAddFunc ]]( self.squad.squadName );
}
//prof_end( "addToSquad" );
self thread memberCombatWaiter();
self thread memberDeathWaiter();
}
removeFromSquad()
{
//prof_begin( "removeFromSquad" );
ASSERTEX( IsDefined( self.squad ), "removeFromSquad attempted to remove a member who was not part of a squad (self.squad == undefined)" );
squad = self.squad;
memberID = -1;
if ( IsDefined( self ) )
{
memberID = self.memberID;
}
else
{
for ( i = 0; i < squad.members.size; i++ )
{
if ( squad.members[ i ] == self )
memberID = i;
}
}
ASSERTEX( memberID > - 1, "removeFromSquad could not find memberID" );
if ( memberID != squad.members.size - 1 )
{
other = squad.members[ squad.members.size - 1 ];
squad.members[ memberID ] = other;
if ( isdefined( other ) )
other.memberID = memberID;
}
squad.members[ squad.members.size - 1 ] = undefined;
squad.memberCount = squad.members.size;
if ( IsDefined( self.officerID ) )
{
self removeOfficerFromSquad();
}
for ( i = 0; i < self.squad.memberRemoveFuncs.size; i++ )
{
memberRemoveFunc = self.squad.memberRemoveFuncs[ i ];
self thread [[ memberRemoveFunc ]]( squad.squadName );
}
assert( squad.members.size == squad.memberCount );
if ( squad.memberCount == 0 )
{
deleteSquad( squad.squadName );
}
if ( isdefined( self ) )
{
self.squad = undefined;
self.memberID = undefined;
}
self notify( "removed from squad" );
//prof_end( "removeFromSquad" );
}
addOfficerToSquad()
{
squad = self.squad;
if ( isdefined( self.officerID ) )
return;
assertex( !isdefined( self.officerID ), "addOfficerToSquad attempted to add a member that is already in an officers" );
self.officerID = squad.officers.size;
squad.officers[ self.officerID ] = self;
squad.officerCount = squad.officers.size;
}
removeOfficerFromSquad()
{
//prof_begin( "removeOfficerFromSquad" );
squad = self.squad;
officerID = -1;
if ( isdefined( self ) )
{
officerID = self.officerID;
}
else
{
for ( i = 0; i < squad.officers.size; i++ )
{
if ( squad.officers[ i ] == self )
officerID = i;
}
}
assertex( officerID > - 1, "removeOfficerFromSquad could not find officerID" );
if ( officerID != squad.officers.size - 1 )
{
other = squad.officers[ squad.officers.size - 1 ];
squad.officers[ officerID ] = other;
if ( isdefined( other ) )
other.officerID = officerID;
}
squad.officers[ squad.officers.size - 1 ] = undefined;
squad.officerCount = squad.officers.size;
assert( squad.officers.size == squad.officerCount );
if ( isdefined( self ) )
self.officerID = undefined;
//prof_end( "removeOfficerFromSquad" );
}
/****************************************************************************
trackers/waiters
*****************************************************************************/
officerWaiter()
{
if ( !isdefined( level._loadoutComplete ) )
{
anim waittill( "loadout complete" );
}
for ( i = 0; i < self.members.size; i++ )
{
if ( self.members[ i ] animscripts\battlechatter::isOfficer() )
{
self.members[ i ] addOfficerToSquad();
}
}
}
updateWaiter()
{
while ( 1 )
{
anim waittill( "squadupdate", action );
//prof_begin( "updateWaiter" );
switch( action )
{
case "squadlist":
self updateSquadList();
break;
case "combat":
self updateCombat();
break;
case "origin":
self updateOrigin();
break;
case "forward":
self updateHeading();
break;
}
//prof_end( "updateWaiter" );
}
}
squadTracker()
{
anim endon( "squad deleted " + self.squadName );
// even with the long wait time, this is a crappy way to track things
// ideally the updateFunctions would only be called when another function needs to know the status of something
// rather than polling like it's doing now.
while ( 1 )
{
// combat can be removed
self updateAll();
wait( 0.1 );
}
}
memberDeathWaiter()
{
// self notify ("squad change");
self endon( "removed from squad" );
self waittill( "death", attacker );
if ( isdefined( self ) )
{
self.attacker = attacker;
}
self removeFromSquad();
}
memberCombatWaiter()
{
// self notify ("squad change");
self endon( "removed from squad" );
while ( 1 )
{
self waittill( "enemy" );
if ( !isdefined( self.enemy ) )
self.squad notify( "squadupdate", "combat" );
else
self.squad.isInCombat = true;
wait( 0.05 );
}
}
/****************************************************************************
utility
*****************************************************************************/
updateHeading()
{
if ( isdefined( self.enemy ) )
{
self.forward = vectornormalize( self.enemy.origin - self.origin );
return;
}
newHeading = ( 0, 0, 0 );
numInfluences = 0;
for ( i = 0; i < self.members.size; i++ )
{
if ( !isalive( self.members[ i ] ) )
continue;
// logic here to prune out separated members... otherwise origin could be too vague
newHeading += anglestoforward( self.members[ i ].angles );
numInfluences++ ;
}
if ( numInfluences )
self.forward = ( newHeading[ 0 ] / numInfluences, newHeading[ 1 ] / numInfluences, newHeading[ 2 ] / numInfluences );
else
self.forward = newHeading;
}
updateOrigin()
{
//prof_begin( "updateOrigin" );
newOrigin = ( 0, 0, 0 );
numInfluences = 0;
for ( i = 0; i < self.members.size; i++ )
{
// logic here to prune out separated members... otherwise origin could be too vague
// assertex (isdefined (self.members[i]), "updateOrigin run while a squad member was undefined");
if ( !isalive( self.members[ i ] ) )
continue;
newOrigin += self.members[ i ].origin;
numInfluences++ ;
}
if ( numInfluences )
self.origin = ( newOrigin[ 0 ] / numInfluences, newOrigin[ 1 ] / numInfluences, newOrigin[ 2 ] / numInfluences );
else
self.origin = newOrigin;
//prof_end( "updateOrigin" );
}
updateCombat()
{
//prof_begin( "updateCombat" );
self.isInCombat = false;
// reset squad contact status
for ( i = 0; i < anim.squadIndex.size; i++ )
self.squadList[ anim.squadIndex[ i ].squadName ].isInContact = false;
for ( i = 0; i < self.members.size; i++ )
{
if ( isdefined( self.members[ i ].enemy ) && isdefined( self.members[ i ].enemy.squad ) && self.members[ i ].combatTime > 0 )
self.squadList[ self.members[ i ].enemy.squad.squadName ].isInContact = true;
}
//prof_end( "updateCombat" );
}
updateEnemy()
{
//prof_begin( "updateEnemy" );
curEnemy = undefined;
for ( i = 0; i < self.members.size; i++ )
{
if ( isdefined( self.members[ i ].enemy ) && isdefined( self.members[ i ].enemy.squad ) )
{
if ( !isdefined( curEnemy ) )
curEnemy = self.members[ i ].enemy.squad;
else if ( self.members[ i ].enemy.squad.memberCount > curEnemy.memberCount )
curEnemy = self.members[ i ].enemy.squad;
}
}
self.enemy = curEnemy;
//prof_end( "updateEnemy" );
}
updateAll()
{
//prof_begin( "updateAll" );
newOrigin = ( 0, 0, 0 );
numInfluences = 0;
curEnemy = undefined;
isInCombat = false;
self updateCombat();
for ( i = 0; i < self.members.size; i++ )
{
if ( !isalive( self.members[ i ] ) )
continue;
// logic here to prune out separated members... otherwise origin could be too vague
newOrigin += self.members[ i ].origin;
numInfluences++ ;
if ( isdefined( self.members[ i ].enemy ) && isdefined( self.members[ i ].enemy.squad ) )
{
if ( !isdefined( curEnemy ) )
curEnemy = self.members[ i ].enemy.squad;
else if ( self.members[ i ].enemy.squad.memberCount > curEnemy.memberCount )
curEnemy = self.members[ i ].enemy.squad;
}
}
if ( numInfluences )
self.origin = ( newOrigin[ 0 ] / numInfluences, newOrigin[ 1 ] / numInfluences, newOrigin[ 2 ] / numInfluences );
else
self.origin = newOrigin;
self.isInCombat = isInCombat;
self.enemy = curEnemy;
// integreate this at some point
self updateHeading();
//prof_end( "updateAll" );
}
updateSquadList()
{
//prof_begin( "updateSquadList" );
for ( i = 0; i < anim.squadIndex.size; i++ )
{
if ( !isdefined( self.squadList[ anim.squadIndex[ i ].squadName ] ) )
{
self.squadList[ anim.squadIndex[ i ].squadName ] = spawnstruct();
self.squadList[ anim.squadIndex[ i ].squadName ].isInContact = false;
}
for ( j = 0; j < self.squadUpdateFuncs.size; j++ )
{
squadUpdateFunc = self.squadUpdateFuncs[ j ];
self thread [[ squadUpdateFunc ]]( anim.squadIndex[ i ].squadName );
}
}
//prof_end( "updateSquadList" );
}
printAboveHead( string, duration, offset, color )
{
self endon( "death" );
if ( !isdefined( offset ) )
offset = ( 0, 0, 0 );
if ( !isdefined( color ) )
color = ( 1, 0, 0 );
for ( i = 0; i < ( duration * 2 ); i++ )
{
if ( !isalive( self ) )
return;
aboveHead = self getshootatpos() + ( 0, 0, 10 ) + offset;
print3d( aboveHead, string, color, 1, 0.5 ); // origin, text, RGB, alpha, scale
wait( 0.05 );
}
}
/****************************************************************************
ai functions
*****************************************************************************/
aiUpdateAnimState( animscript )
{
//prof_begin( "aiUpdateAnimState" );
switch( animscript )
{
case "combat":
case "move":
case "stop":
case "death":
self.a.state = animscript;
break;
case "pain":
case "grenadecower":
break;
case "cover_crouch":
case "cover_left":
case "cover_prone":
case "cover_right":
case "cover_stand":
case "cover_wide_left":
case "cover_wide_right":
case "concealment_crouch":
case "concealment_prone":
case "concealment_stand":
case "stalingrad_cover_crouch":
self.a.state = "cover";
break;
case "aim":
case "l33t truckride combat":
self.a.state = "combat";
break;
}
//prof_end( "aiUpdateAnimState" );
}
/****************************************************************************
squad functions
*****************************************************************************/
updateStates()
{
self resetState( "combat" );
self resetState( "cover" );
self resetState( "move" );
self resetState( "stop" );
self resetState( "death" );
self resetState( "suppressed" );
self resetState( "attacking" );
for ( i = 0; i < self.members.size; i++ )
{
if ( !isalive( self.members[ i ] ) )
continue;
self queryMemberAnimState( self.members[ i ] );
self queryMemberState( self.members[ i ], "suppressed" );
self queryMemberState( self.members[ i ], "combat" );
self queryMemberState( self.members[ i ], "attacking" );
self queryMemberState( self.members[ i ], "cover" );
}
}
updateMemberStates()
{
anim endon( "squad deleted " + self.squadName );
timeSlice = 0.05;
while ( 1 )
{
//prof_begin( "updateMemberStates" );
for ( i = 0; i < self.members.size; i++ )
{
if ( !isalive( self.members[ i ] ) )
continue;
self.members[ i ] aiUpdateCombat( timeSlice );
self.members[ i ] aiUpdateSuppressed( timeSlice );
}
//prof_end( "updateMemberStates" );
wait( timeSlice );
}
}
aiUpdateCombat( timeSlice )
{
if ( isdefined( self.lastEnemySightPos ) )
{
if ( self.combatTime < 0 )
self.combatTime = timeSlice;
else
self.combatTime += timeSlice;
self.lastEnemySightTime = gettime();
return;
}
else if ( self issuppressed() )
{
self.combatTime += timeSlice;
return;
}
if ( self.combatTime > 0 )
self.combatTime = ( 0 - timeSlice );
else
self.combatTime -= timeSlice;
}
aiUpdateSuppressed( timeSlice )
{
if ( self.suppressed )
{
if ( self.suppressedTime < 0 )
self.suppressedTime = timeSlice;
else
self.suppressedTime += timeSlice;
return;
}
if ( self.suppressedTime > 0 )
self.suppressedTime = ( 0 - timeSlice );
else
self.suppressedTime -= timeSlice;
}
initState( state, activateRatio )
{
self.squadStates[ state ] = spawnstruct();
self.squadStates[ state ].activateRatio = activateRatio;
self.squadStates[ state ].isActive = false;
self.squadStates[ state ].numActive = 0;
}
resetState( state )
{
self.squadStates[ state ].isActive = false;
self.squadStates[ state ].numActive = 0;
}
queryMemberAnimState( member )
{
self.squadStates[ member.a.state ].numActive++ ;
if ( self.squadStates[ member.a.state ].numActive > ( self.squadStates[ member.a.state ].activateRatio * self.members.size ) )
self.squadStates[ member.a.state ].isActive = true;
}
queryMemberState( member, state )
{
//prof_begin( "queryMemberState" );
switch( state )
{
case "suppressed":
if ( member.suppressedTime > 1.0 )
self.squadStates[ state ].numActive++ ;
break;
case "combat":
if ( member.combatTime > 0.0 )
self.squadStates[ state ].numActive++ ;
break;
case "attacking":
if ( gettime() < member.a.lastShootTime + 2000 )
self.squadStates[ state ].numActive++ ;
break;
case "cover":
if ( !member animscripts\battlechatter::isExposed() )
self.squadStates[ state ].numActive++ ;
break;
}
if ( self.squadStates[ state ].numActive > ( self.squadStates[ state ].activateRatio * self.members.size ) )
self.squadStates[ state ].isActive = true;
//prof_end( "queryMemberState" );
}

281
animscripts/stop.gsc Normal file
View File

@ -0,0 +1,281 @@
// "Stop" makes the character not walk, run or fight. He can be standing, crouching or lying
// prone; he can be alert or idle.
#include animscripts\combat_utility;
#include animscripts\Utility;
#include animscripts\SetPoseMovement;
#using_animtree( "generic_human" );
main()
{
if ( isdefined( self.no_ai ) )
return;
if ( isdefined( self.locked_combat ) )
{
animscripts\locked_combat::locked_combat();
return;
}
if ( isdefined( self.onSnowMobile ) )
{
animscripts\snowmobile::main();
return;
}
self notify( "stopScript" );
self endon( "killanimscript" );
/#
if ( getdebugdvar( "anim_preview" ) != "" )
return;
#/
[[ self.exception[ "stop_immediate" ] ]]();
// We do the exception_stop script a little late so that the AI has some animation they're playing
// otherwise they'd go into basepose.
thread delayedException();
animscripts\utility::initialize( "stop" );
specialIdleLoop();
self randomizeIdleSet();
self thread setLastStoppedTime();
self thread animscripts\reactions::reactionsCheckLoop();
transitionedToIdle = isdefined( self.customIdleAnimSet );
if ( !transitionedToIdle )
{
if ( self.a.weaponPos[ "right" ] == "none" && self.a.weaponPos[ "left" ] == "none" )
transitionedToIdle = true;
else if ( AngleClamp180( self getMuzzleAngle()[ 0 ] ) > 20 )
transitionedToIdle = true;
}
for ( ;; )
{
desiredPose = getDesiredIdlePose();
if ( desiredPose == "prone" )
{
transitionedToIdle = true;
self ProneStill();
}
else
{
assertex( desiredPose == "crouch" || desiredPose == "stand", desiredPose );
if ( self.a.pose != desiredPose )
{
self clearAnim( %root, 0.3 );
transitionedToIdle = false;
}
self SetPoseMovement( desiredPose, "stop" );
if ( !transitionedToIdle )
{
self transitionToIdle( desiredPose, self.a.idleSet );
transitionedToIdle = true;
}
else
{
self playIdle( desiredPose, self.a.idleSet );
}
}
}
}
setLastStoppedTime()
{
self endon( "death" );
self waittill( "killanimscript" );
self.lastStoppedTime = gettime();
}
specialIdleLoop()
{
self endon( "stop_specialidle" );
if ( isdefined( self.specialIdleAnim ) )
{
idleAnimArray = self.specialIdleAnim;
self.specialIdleAnim = undefined;
self notify( "clearing_specialIdleAnim" );
self animmode( "gravity" );
self orientmode( "face current" );
self clearAnim( %root, .2 );
while ( 1 )
{
self setflaggedanimrestart( "special_idle", idleAnimArray[ randomint( idleAnimArray.size ) ], 1, 0.2, 1 );
self waittillmatch( "special_idle", "end" );
}
}
}
getDesiredIdlePose()
{
myNode = animscripts\utility::GetClaimedNode();
if ( isDefined( myNode ) )
{
myNodeAngle = myNode.angles[ 1 ];
myNodeType = myNode.type;
}
else
{
myNodeAngle = self.desiredAngle;
myNodeType = "node was undefined";
}
self animscripts\face::SetIdleFace( anim.alertface );
// Find out if we should be standing, crouched or prone
desiredPose = animscripts\utility::choosePose();
if ( myNodeType == "Cover Stand" || myNodeType == "Conceal Stand" )
{
// At cover_stand nodes, we don't want to crouch since it'll most likely make our gun go through the wall.
desiredPose = animscripts\utility::choosePose( "stand" );
}
else if ( myNodeType == "Cover Crouch" || myNodeType == "Conceal Crouch" )
{
// We should crouch at concealment crouch nodes.
desiredPose = animscripts\utility::choosePose( "crouch" );
}
else if ( myNodeType == "Cover Prone" || myNodeType == "Conceal Prone" )
{
// We should go prone at prone nodes.
desiredPose = animscripts\utility::choosePose( "prone" );
}
return desiredPose;
}
transitionToIdle( pose, idleSet )
{
if ( self isCQBWalking() && self.a.pose == "stand" )
pose = "stand_cqb";
if ( isdefined( anim.idleAnimTransition[ pose ] ) )
{
assert( isdefined( anim.idleAnimTransition[ pose ][ "in" ] ) );
// idles and transitions should have no tag origin movement
//self animmode( "zonly_physics", false );
idleAnim = anim.idleAnimTransition[ pose ][ "in" ];
self setFlaggedAnimKnobAllRestart( "idle_transition", idleAnim, %body, 1, .2, self.animplaybackrate );
self animscripts\shared::DoNoteTracks( "idle_transition" );
//self animmode( "normal", false );
}
}
playIdle( pose, idleSet )
{
if ( self isCQBWalking() && self.a.pose == "stand" )
pose = "stand_cqb";
idleAddAnim = undefined;
if ( isdefined( self.customIdleAnimSet ) && isdefined( self.customIdleAnimSet[ pose ] ) )
{
idleAnim = self.customIdleAnimSet[ pose ];
additive = pose + "_add";
if ( isdefined( self.customIdleAnimSet[ additive ] ) )
idleAddAnim = self.customIdleAnimSet[ additive ];
}
else
{
idleSet = idleSet % anim.idleAnimArray[ pose ].size;
idleAnim = anim_array( anim.idleAnimArray[ pose ][ idleSet ], anim.idleAnimWeights[ pose ][ idleSet ] );
}
transTime = 0.2;
if ( gettime() == self.a.scriptStartTime )
transTime = 0.5;
if ( isdefined( idleAddAnim ) )
{
self setAnimKnobAll( idleAnim, %body, 1, transTime, 1 );
self setAnim( %add_idle );
self setFlaggedAnimKnobAllRestart( "idle", idleAddAnim, %add_idle, 1, transTime, self.animplaybackrate );
}
else
{
self setFlaggedAnimKnobAllRestart( "idle", idleAnim, %body, 1, transTime, self.animplaybackrate );
}
self animscripts\shared::DoNoteTracks( "idle" );
}
ProneStill()
{
if ( self.a.pose != "prone" )
{
anim_array[ "stand_2_prone" ] = %stand_2_prone;
anim_array[ "crouch_2_prone" ] = %crouch_2_prone;
transAnim = anim_array[ self.a.pose + "_2_prone" ];
assertex( isdefined( transAnim ), self.a.pose );
assert( animHasNotetrack( transAnim, "anim_pose = \"prone\"" ) );
self setFlaggedAnimKnobAllRestart( "trans", transAnim, %body, 1, .2, 1.0 );
animscripts\shared::DoNoteTracks( "trans" );
assert( self.a.pose == "prone" );
self.a.movement = "stop";
self setProneAnimNodes( -45, 45, %prone_legs_down, %exposed_modern, %prone_legs_up );
return;// in case we need to change our pose again for whatever reason
}
self thread UpdateProneThread();
if ( randomint( 10 ) < 3 )
{
twitches = [];
twitches[ 0 ] = %prone_twitch_ammocheck;
twitches[ 1 ] = %prone_twitch_look;
twitches[ 2 ] = %prone_twitch_scan;
twitches[ 3 ] = %prone_twitch_lookfast;
twitches[ 4 ] = %prone_twitch_lookup;
//twitches[ 1 ] = %prone_twitch_ammocheck2;
//twitches[ 6 ] = %prone_twitch_scan2;
twitchAnim = twitches[ randomint( twitches.size ) ];
self setFlaggedAnimKnobAll( "prone_idle", twitchAnim, %exposed_modern, 1, 0.2 );
}
else
{
self setAnimKnobAll( %prone_aim_5, %exposed_modern, 1, 0.2 );
self setFlaggedAnimKnob( "prone_idle", %prone_idle, 1, 0.2 );// ( additive idle on top )
}
self waittillmatch( "prone_idle", "end" );
self notify( "kill UpdateProneThread" );
}
UpdateProneThread()
{
self endon( "killanimscript" );
self endon( "kill UpdateProneThread" );
for ( ;; )
{
self animscripts\cover_prone::UpdateProneWrapper( 0.1 );
wait 0.1;
}
}
delayedException()
{
self endon( "killanimscript" );
wait( 0.05 );
[[ self.exception[ "stop" ] ]]();
}

View File

@ -0,0 +1,48 @@
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "stand";
animscripts\utility::UpdateAnimPose();
// It'd be nice if I had an animation to get to stand without moving...
self.a.movement = "stop";
turret = self getTurret();
turret thread turretInit( self );
self.primaryTurretAnim = %technicalGunner_aim;
self.additiveTurretIdle = %technical_turret_driveidle;
self.additiveTurretFire = %technical_turret_firing;
self.painFunction = ::technical_pain;
self.deathAnim = %technical_turret_death;
thread animscripts\saw\common::main( turret );
}
technical_pain()
{
self setFlaggedAnimKnobAllRestart( "painanim", %technical_turret_pain, %body, 1, .1, 1 );
self animscripts\shared::DoNoteTracks( "painanim" );
}
//=====================================
#using_animtree( "mg42" );
turretInit( owner )
{
self.leftArc = 180;
self.rightArc = 180;
self UseAnimTree( #animtree );
self.additiveTurretIdle = %saw_gunner_idle_mg;
self.additiveTurretFire = %saw_gunner_firing_mg_add;
self endon( "death" );
owner waittill( "killanimscript" );// code
self stopUseAnimTree();
}

View File

@ -0,0 +1,27 @@
// crouch_jump_down_40.gsc
// Makes the character roll down off a ledge at no higher than 32 units. Designed for 40 units but should work for 44-70 or so.
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "crouch";
animscripts\utility::UpdateAnimPose();
self endon( "killanimscript" );
self.a.movement = "walk";
self traverseMode( "nogravity" );
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
//crouch_jump_down_40
self setFlaggedAnimKnoballRestart( "stepanim", %jump_across_72, %body, 1, .1, 1 );
wait .15;
// self waittillmatch("stepanim", "gravity on");
self traverseMode( "gravity" );
self animscripts\shared::DoNoteTracks( "stepanim" );
}

View File

@ -0,0 +1,25 @@
// Jump_across_72.gsc
// Makes the character do a lateral jump of 72 units.
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "stand";
animscripts\utility::UpdateAnimPose();
self endon( "killanimscript" );
self traverseMode( "nogravity" );
self traverseMode( "noclip" );
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
self setFlaggedAnimKnoballRestart( "jumpanim", %gulag_pipe_traverse, %body, 1, .1, 1 );
self waittillmatch( "jumpanim", "finish" );
self traverseMode( "gravity" );
self animscripts\shared::DoNoteTracks( "jumpanim" );
}

View File

@ -0,0 +1,27 @@
// Fence_climb.gsc
// Makes the character climb a 48 unit fence
// TEMP - copied wall dive until we get an animation
// Makes the character dive over a low wall
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "crouch";
animscripts\utility::UpdateAnimPose();
self endon( "killanimscript" );
self traverseMode( "nogravity" );
self traverseMode( "noclip" );// So he doesn't get stuck if the wall is a little too high
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
self setFlaggedAnimKnoballRestart( "diveanim", %fenceclimb, %body, 1, .1, 1 );
// self waittillmatch("diveanim", "gravity on");
self animscripts\shared::DoNoteTracks( "diveanim" );
self traverseMode( "gravity" );
}

View File

@ -0,0 +1,30 @@
// Jump_across_100.gsc
// Makes the character do a lateral jump of 100 units.
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "stand";
animscripts\utility::UpdateAnimPose();
self endon( "killanimscript" );
self traverseMode( "nogravity" );
self traverseMode( "noclip" );
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
jumpAnims = [];
jumpAnims[0] = %jump_across_100_spring;
jumpAnims[1] = %jump_across_100_lunge;
jumpAnims[2] = %jump_across_100_stumble;
jumpanim = jumpAnims[ randomint( jumpAnims.size ) ];
self setFlaggedAnimKnoballRestart( "jumpanim", jumpanim, %body, 1, .1, 1 );
self animscripts\shared::DoNoteTracks( "jumpanim" );
}

View File

@ -0,0 +1,25 @@
// Jump_across_72.gsc
// Makes the character do a lateral jump of 72 units.
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "stand";
animscripts\utility::UpdateAnimPose();
self endon( "killanimscript" );
self traverseMode( "nogravity" );
self traverseMode( "noclip" );
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
self setFlaggedAnimKnoballRestart( "jumpanim", %jump_across_72, %body, 1, .1, 1 );
self waittillmatch( "jumpanim", "gravity on" );
self traverseMode( "gravity" );
self animscripts\shared::DoNoteTracks( "jumpanim" );
}

View File

@ -0,0 +1,32 @@
// Jump_over_high_wall.gsc
// Makes the character dive over a high wall. Designed for getting bad guys into levels - it looks bad from the back.
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "crouch";
animscripts\utility::UpdateAnimPose();
self endon( "killanimscript" );
self traverseMode( "nogravity" );
self traverseMode( "noclip" );
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
self clearanim( %stand_and_crouch, 0.1 );
self setFlaggedAnimKnoballRestart( "diveanim", %jump_over_high_wall, %body, 1, .1, 1 );
self playsound( "dive_wall" );
self waittillmatch( "diveanim", "gravity on" );
self traverseMode( "nogravity" );
self waittillmatch( "diveanim", "noclip" );
self traverseMode( "noclip" );
self waittillmatch( "diveanim", "gravity on" );
self traverseMode( "gravity" );
self animscripts\shared::DoNoteTracks( "diveanim" );
}

View File

@ -0,0 +1,25 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "dog" );
main()
{
assertex( self.type == "dog", "Only dogs can do this traverse currently." );
self endon( "killanimscript" );
self traverseMode( "nogravity" );
self traverseMode( "noclip" );
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
realHeight = startnode.traverse_height - startnode.origin[ 2 ];
self thread teleportThread( realHeight - 80 );
self clearanim( %root, 0.2 );
self setflaggedanimrestart( "jump_up_80", anim.dogTraverseAnims[ "jump_up_80" ], 1, 0.2, 1 );
self animscripts\shared::DoNoteTracks( "jump_up_80" );
self.traverseComplete = true;
}

View File

@ -0,0 +1,19 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
if ( self.type == "dog" )
dog_jump_down( 7, 0.7 );
else
jumpdown_130_human();
}
jumpdown_130_human()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %traverse_jumpdown_130;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,19 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
if ( self.type == "dog" )
dog_jump_down( 3, 1.0 );
else
low_wall_human();
}
low_wall_human()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %traverse_jumpdown_40;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,19 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
if ( self.type == "dog" )
dog_jump_down( 5, 1.0 );
else
low_wall_human();
}
low_wall_human()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %traverse_jumpdown_56;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,19 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
if ( self.type == "dog" )
dog_jump_down( 7, 0.8 );
else
low_wall_human();
}
low_wall_human()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %traverse_jumpdown_96;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,44 @@
// ladder_down.gsc
// Climbs down a ladder of any height by using a looping animation.
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "crouch";
animscripts\utility::UpdateAnimPose();
self endon( "killanimscript" );
self traverseMode( "nogravity" );
self traverseMode( "noclip" );
// First, get on
endnode = self getnegotiationendnode();
assert( isdefined( endnode ) );
endPos = endnode.origin;
//("ladder_down: about to start climbing. Height to climb: " + (endPos[2] - self.origin[2]) );#/
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
self setFlaggedAnimKnoballRestart( "climbanim", %ladder_climbon, %body, 1, .1, 1 );
self animscripts\shared::DoNoteTracks( "climbanim" );
// Now do the cycle
climbAnim = %ladder_climbdown;
self setFlaggedAnimKnoballRestart( "climbanim", climbAnim, %body, 1, .1, 1 );
cycleDelta = GetMoveDelta( climbAnim, 0, 1 );
climbRate = cycleDelta[ 2 ] / getanimlength( climbAnim );
climbingTime = ( endPos[ 2 ] - self.origin[ 2 ] ) / climbRate;
self animscripts\shared::DoNoteTracksForTime( climbingTime, "climbanim" );
self traverseMode( "gravity" );
self.a.movement = "stop";
self.a.pose = "stand";
//("ladder_down: all done");#/
}

View File

@ -0,0 +1,51 @@
// ladder_up.gsc
// Climbs a ladder of any height by using a looping animation, and gets off at the top.
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "crouch";
animscripts\utility::UpdateAnimPose();
self endon( "killanimscript" );
// self traverseMode("nogravity");
self traverseMode( "noclip" );
climbAnim = %ladder_climbup;
endAnim = %ladder_climboff;
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
self setFlaggedAnimKnoballRestart( "climbanim", climbAnim, %body, 1, .1, 1 );
endAnimDelta = GetMoveDelta( endAnim, 0, 1 );
endNode = self getnegotiationendnode();
assert( isdefined( endnode ) );
endPos = endnode.origin - endAnimDelta + ( 0, 0, 1 ); // 1 unit padding
cycleDelta = GetMoveDelta( climbAnim, 0, 1 );
climbRate = cycleDelta[ 2 ] / getanimlength( climbAnim );
//("ladder_up: about to start climbing. Height to climb: " + (endAnimDelta[2] + endPos[2] - self.origin[2]) );#/
climbingTime = ( endPos[ 2 ] - self.origin[ 2 ] ) / climbRate;
if ( climbingTime > 0 )
{
self.allowpain = true;
self animscripts\shared::DoNoteTracksForTime( climbingTime, "climbanim" );
// println ("elapsed ", (gettime() - timer) * 0.001);
self setFlaggedAnimKnoballRestart( "climbanim", endAnim, %body, 1, .1, 1 );
self animscripts\shared::DoNoteTracks( "climbanim" );
}
self traverseMode( "gravity" );
self.a.movement = "run";
self.a.pose = "crouch";
//("ladder_up: all done");#/
}

View File

@ -0,0 +1,12 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_d112_f244;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,12 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_d128_f50;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,12 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_d160_f160;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,12 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_d160_f244;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,12 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_d200_f600;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,12 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_d220_f640;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,12 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_d240_f328;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,12 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_d64_f160;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,14 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_lava_jump_into_train_f104;
traverseData[ "traverseToCoverAnim" ] = %tp_moon_lava_jump_into_train_f104;
traverseData[ "coverType" ] = "Exposed";
DoTraverse( traverseData );
}

View File

@ -0,0 +1,14 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_lava_jump_into_train_f24;
traverseData[ "traverseToCoverAnim" ] = %tp_moon_lava_jump_into_train_f24;
traverseData[ "coverType" ] = "Exposed";
DoTraverse( traverseData );
}

View File

@ -0,0 +1,14 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_lava_jump_into_train_f352;
traverseData[ "traverseToCoverAnim" ] = %tp_moon_lava_jump_into_train_f352;
traverseData[ "coverType" ] = "Cover Crouch";
DoTraverse( traverseData );
}

View File

@ -0,0 +1,15 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_lava_jump_traintop_f104;
traverseData[ "traverseToCoverAnim" ] = %tp_moon_lava_jump_traintop_f104;
traverseData[ "coverType" ] = "Cover Right";
traverseData[ "forceTeleport" ] = true;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,12 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_u36_f_d188;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,12 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_u36_f_d248;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,12 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_u36_f_d284;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,12 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_u48;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,12 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
#using_animtree( "generic_human" );
main()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_storage_jump;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,40 @@
// moon_trav_wall_hop_u_40_d_40.gsc
// Makes the character climb a 40 unit fence, lunar
#include animscripts\traverse\shared;
main()
{
wall_hop_human();
}
#using_animtree( "generic_human" );
wall_hop_human()
{
if( !IsDefined( level.moon_trav_wall_hop_toggle ) )
{
level.moon_trav_wall_hop_toggle = 1;
}
if ( level.moon_trav_wall_hop_toggle == 1 )
{
level.moon_trav_wall_hop_toggle = 0;
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_u40_f_d40_a;
DoTraverse( traverseData );
}
else
{
level.moon_trav_wall_hop_toggle = 1;
traverseData = [];
traverseData[ "traverseAnim" ] = %tp_moon_trav_jump_u40_f_d40_b;
DoTraverse( traverseData );
}
}

View File

@ -0,0 +1,19 @@
#include animscripts\utility;
#include animscripts\traverse\shared;
main()
{
if ( self.type == "dog" )
dog_jump_down( 3, 1.0 );
else
retro_jump_down_human();
}
#using_animtree( "generic_human" );
retro_jump_down_human()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %nx_proto_retro_jump_down_run;
DoTraverse( traverseData );
}

View File

@ -0,0 +1,378 @@
#include animscripts\utility;
#include maps\_utility;
#using_animtree( "generic_human" );
// Deprecated. only used for old traverses that will be deleted.
advancedTraverse( traverseAnim, normalHeight )
{
// do not do code prone in this script
self.desired_anim_pose = "crouch";
animscripts\utility::UpdateAnimPose();
self endon( "killanimscript" );
self traverseMode( "nogravity" );
self traverseMode( "noclip" );// So he doesn't get stuck if the wall is a little too high
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
realHeight = startnode.traverse_height - startnode.origin[ 2 ];
self thread teleportThread( realHeight - normalHeight );
blendTime = 0.15;
self clearAnim( %body, blendTime );
self setFlaggedAnimKnoballRestart( "traverse", traverseAnim, %root, 1, blendTime, 1 );
gravityToBlendTime = 0.2;
endBlendTime = 0.2;
self thread animscripts\shared::DoNoteTracksForever( "traverse", "no clear" );
if ( !animHasNotetrack( traverseAnim, "gravity on" ) )
{
magicWhateverTime_WhereTheHeckDidWeGetThisNumberAnyway = 1.23;
wait( magicWhateverTime_WhereTheHeckDidWeGetThisNumberAnyway - gravityToBlendTime );
self traverseMode( "gravity" );
wait( gravityToBlendTime );
}
else
{
self waittillmatch( "traverse", "gravity on" );
self traverseMode( "gravity" );
if ( !animHasNotetrack( traverseAnim, "blend" ) )
wait( gravityToBlendTime );
else
self waittillmatch( "traverse", "blend" );
}
}
teleportThread( verticalOffset )
{
self endon( "killanimscript" );
self notify( "endTeleportThread" );
self endon( "endTeleportThread" );
reps = 5;
offset = ( 0, 0, verticalOffset / reps );
for ( i = 0; i < reps; i++ )
{
self forceTeleport( self.origin + offset );
wait .05;
}
}
teleportThreadEx( verticalOffset, delay, frames, animRate )
{
self endon( "killanimscript" );
self notify( "endTeleportThread" );
self endon( "endTeleportThread" );
if ( (verticalOffset == 0) || (frames <= 0) )
return;
if ( delay > 0 )
wait delay;
offset = ( 0, 0, verticalOffset / frames );
if ( isDefined( animRate ) && (animRate < 1.0) )
self setFlaggedAnimKnoball( "traverseAnim", self.traverseAnim, self.traverseAnimRoot, 1, .2, animRate );
for ( i = 0; i < frames; i++ )
{
self forceTeleport( self.origin + offset );
wait .05;
}
if ( isDefined( animRate ) && (animRate < 1.0) )
self setFlaggedAnimKnoball( "traverseAnim", self.traverseAnim, self.traverseAnimRoot, 1, .2, 1.0 );
}
DoTraverse( traverseData )
{
self endon( "killanimscript" );
self notify( "traverse_started" );
// do not do code prone in this script
self.desired_anim_pose = "stand";
animscripts\utility::UpdateAnimPose();
// orient to the Negotiation start node
startnode = self getNegotiationStartNode();
endNode = self getNegotiationEndNode();
assert( isDefined( startnode ) );
assert( isDefined( endNode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
self.traverseHeight = traverseData[ "traverseHeight" ];
self.traverseStartNode = startnode;
traverseAnim = traverseData[ "traverseAnim" ];
traverseToCoverAnim = traverseData[ "traverseToCoverAnim" ]; // traversals that end up with 180-degree spins into cover at the end
self traverseMode( "nogravity" );
self traverseMode( "noclip" );
self.traverseStartZ = self.origin[ 2 ];
if ( !animHasNotetrack( traverseAnim, "traverse_align" ) )
{
/# println( "^1Warning: animation ", traverseAnim, " has no traverse_align notetrack" ); #/
self handleTraverseAlignment();
}
toCover = false;
if ( isDefined( traverseToCoverAnim ) && isDefined( self.node ) && self.node.type == traverseData[ "coverType" ] && distanceSquared( self.node.origin, endNode.origin ) < 25 * 25 )
{
if ( AbsAngleClamp180( self.node.angles[ 1 ] - endNode.angles[ 1 ] ) > 160 )
{
toCover = true;
traverseAnim = traverseToCoverAnim;
}
}
if ( toCover )
{
if ( isdefined( traverseData[ "traverseToCoverSound" ] ) )
{
self thread play_sound_on_entity( traverseData[ "traverseToCoverSound" ] );
}
}
else
{
if ( isdefined( traverseData[ "traverseSound" ] ) )
{
self thread play_sound_on_entity( traverseData[ "traverseSound" ] );
}
}
self.traverseAnim = traverseAnim;
self.traverseAnimRoot = %body;
// tagJW<NOTE>: Use the blend_finish tag to determine blend time on the traverse animation
blend_time = 0.2;
if( self IsCQBWalking() )
{
blend_finish_time = GetNotetrackTimes( traverseAnim, "cqb_blend_finish" );
}
else
{
blend_finish_time = GetNotetrackTimes( traverseAnim, "blend_finish" );
}
if ( blend_finish_time.size > 0 )
{
blend_time = blend_finish_time[0] * GetAnimLength( traverseAnim );
}
self setFlaggedAnimKnoballRestart( "traverseAnim", traverseAnim, %body, 1, blend_time, 1 );
self.traverseDeathIndex = 0;
self.traverseDeathAnim = traverseData[ "interruptDeathAnim" ];
self animscripts\shared::DoNoteTracks( "traverseAnim", ::handleTraverseNotetracks );
self traverseMode( "gravity" );
if ( self.delayedDeath )
return;
self.a.nodeath = false;
if ( toCover && isDefined( self.node ) && distanceSquared( self.origin, self.node.origin ) < 16 * 16 )
{
self.a.movement = "stop";
if( IsDefined( traverseData[ "forceTeleport" ] ) && traverseData[ "forceTeleport" ] )
{
self ForceTeleport( self.node.origin );
}
else
{
self Teleport( self.node.origin );
}
}
else if( IsDefined( traverseData[ "traverseStopsAtEnd" ] ) )
{
self.a.movement = "stop";
}
else
{
self.a.movement = "run";
//self setAnimKnobAllRestart( animscripts\run::GetRunAnim(), %body, 1, 0.0, 1 );
self clearanim( traverseAnim, 0.2 );
self animscripts\utility::handle_move_transition_notes( traverseAnim );
}
self notify( "traverse_finished" );
self.traverseAnimRoot = undefined;
self.traverseAnim = undefined;
self.deathAnim = undefined;
}
handleTraverseNotetracks( note )
{
if ( note == "traverse_death" )
return handleTraverseDeathNotetrack();
else if ( note == "traverse_align" )
return handleTraverseAlignment();
else if ( note == "traverse_drop" )
return handleTraverseDrop();
}
handleTraverseDeathNotetrack()
{
if ( isdefined( self.traverseDeathAnim ) )
{
deathAnimArray = self.traverseDeathAnim[ self.traverseDeathIndex ];
self.deathAnim = deathAnimArray[ randomint( deathAnimArray.size ) ];
self.traverseDeathIndex++;
}
}
handleTraverseAlignment()
{
self traverseMode( "nogravity" );
self traverseMode( "noclip" );
if ( isDefined( self.traverseHeight ) && isDefined( self.traverseStartNode.traverse_height ) )
{
currentHeight = self.traverseStartNode.traverse_height - self.traverseStartZ;
self thread teleportThread( currentHeight - self.traverseHeight );
}
}
handleTraverseDrop()
{
startpos = self.origin + ( 0, 0, 32 );
trace = bullettrace( startpos, self.origin + ( 0, 0, -512 ), false, undefined );
endpos = trace[ "position" ];
dist = distance( startpos, endpos );
realDropHeight = dist - 32 - 0.5;// 0.5 makes sure we end up above the ground a bit
traverseAnimPos = self getAnimTime( self.traverseAnim );
traverseAnimDelta = getMoveDelta( self.traverseAnim, traverseAnimPos, 1.0 );
traverseAnimLength = getAnimLength( self.traverseAnim );
animDropHeight = 0 - traverseAnimDelta[ 2 ];
assertEx( animDropHeight >= 0, animDropHeight );
dropOffset = animDropHeight - realDropHeight;
/#
if ( getdvarint( "scr_traverse_debug" ) )
{
thread animscripts\utility::debugLine( startpos, endpos, ( 1, 1, 1 ), 2 * 20 );
thread animscripts\utility::drawStringTime( "drop offset: " + dropOffset, endpos, ( 1, 1, 1 ), 2 );
}
#/
if ( animDropHeight < realDropHeight )
animRate = animDropHeight / realDropHeight;
else
animRate = 1;
teleportLength = ( traverseAnimLength - traverseAnimPos ) / 3.0; // let's make the teleport take 1/3 of the animation time roughly
numFrames = ceil( teleportLength * 20 ); // 0.05 per frame. Maximum number of frames we can use
self thread teleportThreadEx( dropOffset, 0, numFrames, animRate );
self thread finishTraverseDrop( endpos[ 2 ] );
}
finishTraverseDrop( finalz )
{
self endon( "killanimscript" );
finalz += 4.0;
while ( 1 )
{
if ( self.origin[ 2 ] < finalz )
{
self traverseMode( "gravity" );
break;
}
wait .05;
}
}
doNothingFunc()
{
self animMode( "zonly_physics" );
self waittill( "killanimscript" );
}
#using_animtree( "dog" );
dog_wall_and_window_hop( traverseName, height )
{
self endon( "killanimscript" );
self traverseMode( "nogravity" );
self traverseMode( "noclip" );
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
realHeight = startnode.traverse_height - startnode.origin[ 2 ];
self thread teleportThread( realHeight - height );
self clearanim( %root, 0.2 );
self setflaggedanimrestart( "dog_traverse", anim.dogTraverseAnims[ traverseName ], 1, 0.2, 1 );
self animscripts\shared::DoNoteTracks( "dog_traverse" );
self.traverseComplete = true;
}
dog_jump_down( frames, rate )
{
self endon( "killanimscript" );
self traverseMode( "noclip" );
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
height = self getNegotiationStartNode().origin[2] - self getNegotiationEndNode().origin[2];
self.traverseAnim = anim.dogTraverseAnims[ "jump_down_40" ];
self.traverseAnimRoot = %root;
self thread teleportThreadEx( 40.0 - height, 0.1, frames, rate );
self clearanim( %root, 0.2 );
self setflaggedanimrestart( "traverseAnim", self.traverseAnim, 1, 0.2, 1 );
self animscripts\shared::DoNoteTracks( "traverseAnim" );
self clearanim( self.traverseAnim, 0 ); // start run immediately
self traverseMode( "gravity" );
self.traverseComplete = true;
self.traverseAnimRoot = undefined;
self.traverseAnim = undefined;
}
dog_jump_up( height, frames )
{
self endon( "killanimscript" );
self traverseMode( "noclip" );
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
self thread teleportThreadEx( height - 40.0, 0.2, frames );
self clearanim( %root, 0.25 );
self setflaggedanimrestart( "traverseAnim", anim.dogTraverseAnims[ "jump_up_40" ], 1, 0.2, 1 );
self animscripts\shared::DoNoteTracks( "traverseAnim" );
self clearanim( anim.dogTraverseAnims[ "jump_up_40" ], 0 ); // start run immediately
self traverseMode( "gravity" );
self.traverseComplete = true;
}

View File

@ -0,0 +1,54 @@
#include animscripts\traverse\shared;
#include animscripts\utility;
#include common_scripts\utility;
#using_animtree( "generic_human" );
main()
{
if ( self.type == "dog" )
slide_across_car_dog();
else
slide_across_car_human();
}
slide_across_car_human()
{
traverseData = [];
traverseData[ "traverseAnim" ] = %slide_across_car;
traverseData[ "traverseToCoverAnim" ] = %slide_across_car_2_cover;
traverseData[ "coverType" ] = "Cover Crouch";
traverseData[ "traverseHeight" ] = 38.0;
traverseData[ "interruptDeathAnim" ][ 0 ] = array( %slide_across_car_death );
traverseData[ "traverseSound" ] = "npc_car_slide_hood";
traverseData[ "traverseToCoverSound" ] = "npc_car_slide_cover";
DoTraverse( traverseData );
}
#using_animtree( "dog" );
slide_across_car_dog()
{
self endon( "killanimscript" );
self traverseMode( "noclip" );
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
self clearanim( %root, 0.1 );
self setflaggedanimrestart( "traverse", anim.dogTraverseAnims[ "jump_up_40" ], 1, 0.1, 1 );
self animscripts\shared::DoNoteTracks( "traverse" );
// TEMP, can't hear jump over sounds
self thread play_sound_in_space( "anml_dog_bark", self gettagorigin( "tag_eye" ) );
self clearanim( %root, 0 );
self setflaggedanimrestart( "traverse", anim.dogTraverseAnims[ "jump_down_40" ], 1, 0, 1 );
self animscripts\shared::DoNoteTracks( "traverse" );
self traverseMode( "gravity" );
self.traverseComplete = true;
}

View File

@ -0,0 +1,49 @@
// stairs_down.gsc
// Climbs down stairs of any height by using a looping animation.
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "stand";
animscripts\utility::UpdateAnimPose();
self endon( "killanimscript" );
self traverseMode( "nogravity" );
endnode = self getnegotiationendnode()
assert( isdefined( endnode ) );
endPos = endnode.origin;
horizontalDelta = ( endPos[ 0 ] - self.origin[ 0 ], endPos[ 1 ] - self.origin[ 1 ], 0 );
horizontalDistance = length( horizontalDelta );
// Do the cycle
//if ( self animscripts\utility::weaponAnims() == "none" || self animscripts\utility::weaponAnims() == "pistol" )
// climbAnim = %climbstairs_down;
//else
climbAnim = %climbstairs_down_armed;
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startNode ) );
self OrientMode( "face angle", node.angles[ 1 ] );
self setFlaggedAnimKnoball( "climbanim", climbAnim, %body, 1, .3, 1 );
cycleDelta = GetMoveDelta( climbAnim, 0, 1 );
cycleDelta = ( cycleDelta[ 0 ], cycleDelta[ 1 ], 0 );
cycleHorDist = length( cycleDelta );
cycleTime = getanimlength( climbAnim );
climbingTime = ( horizontalDistance / cycleHorDist ) * cycleTime;
//("stairs_down: about to start climbing. Horizontal dist: " +horizontalDistance+ ", dist/cycle: "+cycleHorDist+", time/cycle: "+cycleTime+", time to play: "+climbingTime);#/
self animscripts\shared::DoNoteTracksForTime( climbingTime, "climbanim" );
// self traverseMode("gravity");
self.a.movement = "walk";
self.a.pose = "stand";
//("stairs_down: all done");#/
}

View File

@ -0,0 +1,47 @@
// stairs_up.gsc
// Climbs stairs of any height by using a looping animation, and gets off at the top.
#using_animtree( "generic_human" );
main()
{
// do not do code prone in this script
self.desired_anim_pose = "crouch";
animscripts\utility::UpdateAnimPose();
self endon( "killanimscript" );
self traverseMode( "nogravity" );
//if ( self animscripts\utility::weaponAnims() == "none" || self animscripts\utility::weaponAnims() == "pistol" )
// climbAnim = %climbstairs_up;
//else
climbAnim = %climbstairs_up_armed;
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startNode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
self setFlaggedAnimKnoballRestart( "climbanim", climbAnim, %body, 1, .1, 1 );
endnode = self getnegotiationendnode();
assert( isdefined( endnode ) );
endPos = endnode.origin + ( 0, 0, 1 ); // 1 unit padding
horizontalDelta = ( endPos[ 0 ] - self.origin[ 0 ], endPos[ 1 ] - self.origin[ 1 ], 0 );
horizontalDistance = length( horizontalDelta );
cycleDelta = GetMoveDelta( climbAnim, 0, 1 );
cycleDelta = ( cycleDelta[ 0 ], cycleDelta[ 1 ], 0 );
cycleHorDist = length( cycleDelta );
cycleTime = getanimlength( climbAnim );
climbingTime = ( horizontalDistance / cycleHorDist ) * cycleTime;
//("stairs_down: about to start climbing. Horizontal dist: " +horizontalDistance+ ", dist/cycle: "+cycleHorDist+", time/cycle: "+cycleTime+", time to play: "+climbingTime);#/
self animscripts\shared::DoNoteTracksForTime( climbingTime, "climbanim" );
// self traverseMode("gravity");
self.a.movement = "walk";
self.a.pose = "stand";
//("stairs_up: all done");#/
}

View File

@ -0,0 +1,39 @@
#include animscripts\traverse\shared;
// step_down.gsc
// Makes the character step down off a ledge. Currently the ledge is assumed to be 36 units.
#using_animtree( "generic_human" );
main()
{
if ( self.type == "dog" )
dog_jump_down( 40, 3 );
else
step_down_human();
}
step_down_human()
{
// do not do code prone in this script
self.desired_anim_pose = "crouch";
animscripts\utility::UpdateAnimPose();
self endon( "killanimscript" );
self.a.movement = "walk";
self traverseMode( "nogravity" );
// self traverseMode("noclip"); // Testing to see if a clip brush will stop regular pathfinding and force the traverse script to be used.
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
self setFlaggedAnimKnoballRestart( "stepanim", %step_down_low_wall, %body, 1, .1, 1 );
self waittillmatch( "stepanim", "gravity on" );
self traverseMode( "gravity" );
self animscripts\shared::DoNoteTracks( "stepanim" );
}

View File

@ -0,0 +1,38 @@
#include animscripts\traverse\shared;
// step_up.gsc
// Makes the character step up onto a ledge. Currently the ledge is assumed to be 36 units.
#using_animtree( "generic_human" );
main()
{
if ( self.type == "dog" )
dog_jump_up( 40, 3 );
else
step_up_human();
}
step_up_human()
{
// do not do code prone in this script
self.desired_anim_pose = "crouch";
animscripts\utility::UpdateAnimPose();
self endon( "killanimscript" );
self.a.movement = "walk";
self traverseMode( "nogravity" );
// orient to the Negotiation start node
startnode = self getnegotiationstartnode();
assert( isdefined( startnode ) );
self OrientMode( "face angle", startnode.angles[ 1 ] );
self setFlaggedAnimKnoballRestart( "stepanim", %step_up_low_wall, %body, 1, .1, 1 );
self waittillmatch( "stepanim", "gravity on" );
self traverseMode( "gravity" );
self animscripts\shared::DoNoteTracks( "stepanim" );
self setAnimKnobAllRestart( animscripts\run::GetCrouchRunAnim(), %body, 1, 0.1, 1 );
}

Some files were not shown because too many files have changed in this diff Show More