Pushed raw files
This commit is contained in:
1 parent
22d0d4d39f
commit
79f967ecc9
5854 files changed
+2989978
No files matched your search
@@ -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 );
|
||||
}
|
||||
@@ -0,0 +1,773 @@
|
||||
#include animscripts\Utility;
|
||||
#include common_scripts\Utility;
|
||||
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Initialize anim sets
|
||||
//
|
||||
// anim.initAnimSet is used as a temporary buffer, because variables, including arrays, can't be passed by reference
|
||||
// Set it up in each init_animset_* function and then store it in anim.animset.*
|
||||
// This allows using helpers such as "set_animarray_stance_change" for different sets
|
||||
////////////////////////////////////////////
|
||||
|
||||
init_anim_sets()
|
||||
{
|
||||
anim.animsets = spawnstruct();
|
||||
anim.animsets.move = [];
|
||||
|
||||
// combat stand
|
||||
init_animset_default_stand();
|
||||
init_animset_cqb_stand();
|
||||
init_animset_pistol_stand();
|
||||
init_animset_rpg_stand();
|
||||
init_animset_shotgun_stand();
|
||||
init_animset_heat_stand();
|
||||
|
||||
// combat crouch
|
||||
init_animset_default_crouch();
|
||||
init_animset_rpg_crouch();
|
||||
init_animset_shotgun_crouch();
|
||||
|
||||
// combat prone
|
||||
init_animset_default_prone();
|
||||
|
||||
// move
|
||||
init_animset_run_move();
|
||||
init_animset_walk_move();
|
||||
init_animset_cqb_move();
|
||||
init_animset_heat_run_move();
|
||||
|
||||
init_moving_turn_animations();
|
||||
}
|
||||
|
||||
|
||||
init_animset_run_move()
|
||||
{
|
||||
anim.initAnimSet = [];
|
||||
anim.initAnimSet[ "sprint" ] = %sprint_loop_distant;
|
||||
anim.initAnimSet[ "sprint_short" ] = %sprint1_loop;
|
||||
anim.initAnimSet[ "prone" ] = %prone_crawl;
|
||||
|
||||
anim.initAnimSet[ "straight" ] = %run_lowready_F;
|
||||
|
||||
anim.initAnimSet[ "move_f" ] = %walk_forward;
|
||||
anim.initAnimSet[ "move_l" ] = %walk_left;
|
||||
anim.initAnimSet[ "move_r" ] = %walk_right;
|
||||
anim.initAnimSet[ "move_b" ] = %walk_backward; //this looks too fast to be natural
|
||||
|
||||
anim.initAnimSet[ "crouch" ] = %crouch_fastwalk_F;
|
||||
anim.initAnimSet[ "crouch_l" ] = %crouch_fastwalk_L;
|
||||
anim.initAnimSet[ "crouch_r" ] = %crouch_fastwalk_R;
|
||||
anim.initAnimSet[ "crouch_b" ] = %crouch_fastwalk_B;
|
||||
|
||||
anim.initAnimSet[ "stairs_up" ] = %traverse_stair_run_01;
|
||||
anim.initAnimSet[ "stairs_down" ] = %traverse_stair_run_down;
|
||||
|
||||
assert( !isdefined( anim.animsets.move[ "run" ] ) );
|
||||
anim.animsets.move[ "run" ] = anim.initAnimSet;
|
||||
}
|
||||
|
||||
|
||||
init_animset_heat_run_move()
|
||||
{
|
||||
assert( isdefined( anim.animsets.move[ "run" ] ) );
|
||||
anim.initAnimSet = anim.animsets.move[ "run" ];
|
||||
|
||||
anim.initAnimSet[ "straight" ] = %heat_run_loop;
|
||||
|
||||
assert( !isdefined( anim.animsets.move[ "heat_run" ] ) );
|
||||
anim.animsets.move[ "heat_run" ] = anim.initAnimSet;
|
||||
}
|
||||
|
||||
|
||||
init_animset_walk_move()
|
||||
{
|
||||
anim.initAnimSet = [];
|
||||
anim.initAnimSet[ "sprint" ] = %sprint_loop_distant;
|
||||
anim.initAnimSet[ "sprint_short" ] = %sprint1_loop;
|
||||
anim.initAnimSet[ "prone" ] = %prone_crawl;
|
||||
|
||||
anim.initAnimSet[ "straight" ] = %walk_CQB_F;
|
||||
|
||||
anim.initAnimSet[ "move_f" ] = %walk_CQB_F;
|
||||
anim.initAnimSet[ "move_l" ] = %walk_left;
|
||||
anim.initAnimSet[ "move_r" ] = %walk_right;
|
||||
anim.initAnimSet[ "move_b" ] = %walk_backward;
|
||||
|
||||
anim.initAnimSet[ "crouch" ] = %crouch_fastwalk_F;
|
||||
anim.initAnimSet[ "crouch_l" ] = %crouch_fastwalk_L;
|
||||
anim.initAnimSet[ "crouch_r" ] = %crouch_fastwalk_R;
|
||||
anim.initAnimSet[ "crouch_b" ] = %crouch_fastwalk_B;
|
||||
|
||||
anim.initAnimSet[ "stairs_up" ] = %traverse_stair_run;
|
||||
anim.initAnimSet[ "stairs_down" ] = %traverse_stair_run_down_01;
|
||||
|
||||
assert( !isdefined( anim.animsets.move[ "walk" ] ) );
|
||||
anim.animsets.move[ "walk" ] = anim.initAnimSet;
|
||||
}
|
||||
|
||||
|
||||
init_animset_cqb_move()
|
||||
{
|
||||
anim.initAnimSet = [];
|
||||
anim.initAnimSet[ "sprint" ] = %sprint_loop_distant;
|
||||
anim.initAnimSet[ "sprint_short" ] = %sprint1_loop;
|
||||
anim.initAnimSet[ "straight" ] = %run_CQB_F_search_v1; // %run_CQB_F_search_v2
|
||||
|
||||
anim.initAnimSet[ "move_f" ] = %walk_CQB_F;
|
||||
anim.initAnimSet[ "move_l" ] = %walk_left;
|
||||
anim.initAnimSet[ "move_r" ] = %walk_right;
|
||||
anim.initAnimSet[ "move_b" ] = %walk_backward;
|
||||
|
||||
anim.initAnimSet[ "stairs_up" ] = %traverse_stair_run;
|
||||
anim.initAnimSet[ "stairs_down" ] = %traverse_stair_run_down_01;
|
||||
|
||||
assert( !isdefined( anim.animsets.move[ "cqb" ] ) );
|
||||
anim.animsets.move[ "cqb" ] = anim.initAnimSet;
|
||||
}
|
||||
|
||||
|
||||
init_animset_pistol_stand()
|
||||
{
|
||||
anim.initAnimSet = [];
|
||||
anim.initAnimSet[ "add_aim_up" ] = %pistol_stand_aim_8_add;
|
||||
anim.initAnimSet[ "add_aim_down" ] = %pistol_stand_aim_2_add;
|
||||
anim.initAnimSet[ "add_aim_left" ] = %pistol_stand_aim_4_add;
|
||||
anim.initAnimSet[ "add_aim_right" ] = %pistol_stand_aim_6_add;
|
||||
anim.initAnimSet[ "straight_level" ] = %pistol_stand_aim_5;
|
||||
|
||||
anim.initAnimSet[ "fire" ] = %pistol_stand_fire_A;
|
||||
anim.initAnimSet[ "single" ] = array( %pistol_stand_fire_A );
|
||||
|
||||
anim.initAnimSet[ "reload" ] = array( %pistol_stand_reload_A );
|
||||
anim.initAnimSet[ "reload_crouchhide" ] = array();
|
||||
|
||||
anim.initAnimSet[ "exposed_idle" ] = array( %exposed_idle_alert_v1, %exposed_idle_alert_v2, %exposed_idle_alert_v3 );
|
||||
|
||||
set_animarray_standing_turns_pistol();
|
||||
|
||||
anim.initAnimSet[ "add_turn_aim_up" ] = %pistol_stand_aim_8_alt;
|
||||
anim.initAnimSet[ "add_turn_aim_down" ] = %pistol_stand_aim_2_alt;
|
||||
anim.initAnimSet[ "add_turn_aim_left" ] = %pistol_stand_aim_4_alt;
|
||||
anim.initAnimSet[ "add_turn_aim_right" ] = %pistol_stand_aim_6_alt;
|
||||
|
||||
assert( !isdefined( anim.animsets.pistolStand ) );
|
||||
anim.animsets.pistolStand = anim.initAnimSet;
|
||||
}
|
||||
|
||||
init_animset_rpg_stand()
|
||||
{
|
||||
anim.initAnimSet = [];
|
||||
anim.initAnimSet[ "add_aim_up" ] = %RPG_stand_aim_8;
|
||||
anim.initAnimSet[ "add_aim_down" ] = %RPG_stand_aim_2;
|
||||
anim.initAnimSet[ "add_aim_left" ] = %RPG_stand_aim_4;
|
||||
anim.initAnimSet[ "add_aim_right" ] = %RPG_stand_aim_6;
|
||||
anim.initAnimSet[ "straight_level" ] = %RPG_stand_aim_5;
|
||||
|
||||
anim.initAnimSet[ "fire" ] = %RPG_stand_fire;
|
||||
anim.initAnimSet[ "single" ] = array( %exposed_shoot_semi1 );
|
||||
|
||||
anim.initAnimSet[ "reload" ] = array( %RPG_stand_reload );
|
||||
anim.initAnimSet[ "reload_crouchhide" ] = array();
|
||||
|
||||
anim.initAnimSet[ "exposed_idle" ] = array( %RPG_stand_idle );
|
||||
|
||||
set_animarray_stance_change();
|
||||
set_animarray_standing_turns();
|
||||
set_animarray_add_turn_aims_stand();
|
||||
|
||||
assert( !isdefined( anim.animsets.rpgStand ) );
|
||||
anim.animsets.rpgStand = anim.initAnimSet;
|
||||
}
|
||||
|
||||
init_animset_shotgun_stand()
|
||||
{
|
||||
anim.initAnimSet = [];
|
||||
anim.initAnimSet[ "add_aim_up" ] = %shotgun_aim_8;
|
||||
anim.initAnimSet[ "add_aim_down" ] = %shotgun_aim_2;
|
||||
anim.initAnimSet[ "add_aim_left" ] = %shotgun_aim_4;
|
||||
anim.initAnimSet[ "add_aim_right" ] = %shotgun_aim_6;
|
||||
anim.initAnimSet[ "straight_level" ] = %shotgun_aim_5;
|
||||
|
||||
anim.initAnimSet[ "fire" ] = %exposed_shoot_auto_v3;
|
||||
anim.initAnimSet[ "single" ] = array( %shotgun_stand_fire_1A, %shotgun_stand_fire_1B );
|
||||
set_animarray_burst_and_semi_fire_stand();
|
||||
|
||||
anim.initAnimSet[ "exposed_idle" ] = array( %exposed_idle_alert_v1, %exposed_idle_alert_v2, %exposed_idle_alert_v3 );
|
||||
|
||||
anim.initAnimSet[ "reload" ] = array( %shotgun_stand_reload_A, %shotgun_stand_reload_B, %shotgun_stand_reload_C, %shotgun_stand_reload_C, %shotgun_stand_reload_C );// ( C is standing, want it more often )
|
||||
anim.initAnimSet[ "reload_crouchhide" ] = array( %shotgun_stand_reload_A, %shotgun_stand_reload_B );
|
||||
|
||||
set_animarray_stance_change();
|
||||
set_animarray_standing_turns();
|
||||
set_animarray_add_turn_aims_stand();
|
||||
|
||||
assert( !isdefined( anim.animsets.shotgunStand ) );
|
||||
anim.animsets.shotgunStand = anim.initAnimSet;
|
||||
}
|
||||
|
||||
init_animset_cqb_stand()
|
||||
{
|
||||
anim.initAnimSet = [];
|
||||
anim.initAnimSet[ "add_aim_up" ] = %CQB_stand_aim8;
|
||||
anim.initAnimSet[ "add_aim_down" ] = %CQB_stand_aim2;
|
||||
anim.initAnimSet[ "add_aim_left" ] = %CQB_stand_aim4;
|
||||
anim.initAnimSet[ "add_aim_right" ] = %CQB_stand_aim6;
|
||||
|
||||
anim.initAnimSet[ "straight_level" ] = %CQB_stand_aim5;
|
||||
|
||||
anim.initAnimSet[ "fire" ] = %exposed_shoot_auto_v3;
|
||||
anim.initAnimSet[ "single" ] = array( %exposed_shoot_semi1 );
|
||||
set_animarray_burst_and_semi_fire_stand();
|
||||
|
||||
anim.initAnimSet[ "exposed_idle" ] = array( %exposed_idle_alert_v1, %exposed_idle_alert_v2, %exposed_idle_alert_v3 );
|
||||
|
||||
anim.initAnimSet[ "reload" ] = array( %CQB_stand_reload_steady );
|
||||
anim.initAnimSet[ "reload_crouchhide" ] = array( %CQB_stand_reload_knee );
|
||||
|
||||
set_animarray_stance_change();
|
||||
set_animarray_standing_turns();
|
||||
set_animarray_add_turn_aims_stand();
|
||||
|
||||
assert( !isdefined( anim.animsets.cqbStand ) );
|
||||
anim.animsets.cqbStand = anim.initAnimSet;
|
||||
}
|
||||
|
||||
init_animset_heat_stand()
|
||||
{
|
||||
anim.initAnimSet = [];
|
||||
anim.initAnimSet[ "add_aim_up" ] = %heat_stand_aim_8;
|
||||
anim.initAnimSet[ "add_aim_down" ] = %heat_stand_aim_2;
|
||||
anim.initAnimSet[ "add_aim_left" ] = %heat_stand_aim_4;
|
||||
anim.initAnimSet[ "add_aim_right" ] = %heat_stand_aim_6;
|
||||
|
||||
anim.initAnimSet[ "straight_level" ] = %heat_stand_aim_5;
|
||||
|
||||
anim.initAnimSet[ "fire" ] = %heat_stand_fire_auto;
|
||||
anim.initAnimSet[ "single" ] = array( %heat_stand_fire_single );
|
||||
set_animarray_custom_burst_and_semi_fire_stand( %heat_stand_fire_burst );
|
||||
|
||||
anim.initAnimSet[ "exposed_idle" ] = array( %heat_stand_idle, /*%heat_stand_twitchA, %heat_stand_twitchB, %heat_stand_twitchC,*/ %heat_stand_scanA, %heat_stand_scanB );
|
||||
//heat_stand_scanA
|
||||
//heat_stand_scanB
|
||||
|
||||
anim.initAnimSet[ "reload" ] = array( %heat_exposed_reload );
|
||||
anim.initAnimSet[ "reload_crouchhide" ] = array();
|
||||
|
||||
set_animarray_stance_change();
|
||||
|
||||
anim.initAnimSet[ "turn_left_45" ] = %heat_stand_turn_L;
|
||||
anim.initAnimSet[ "turn_left_90" ] = %heat_stand_turn_L;
|
||||
anim.initAnimSet[ "turn_left_135" ] = %heat_stand_turn_180;
|
||||
anim.initAnimSet[ "turn_left_180" ] = %heat_stand_turn_180;
|
||||
anim.initAnimSet[ "turn_right_45" ] = %heat_stand_turn_R;
|
||||
anim.initAnimSet[ "turn_right_90" ] = %heat_stand_turn_R;
|
||||
anim.initAnimSet[ "turn_right_135" ] = %heat_stand_turn_180;
|
||||
anim.initAnimSet[ "turn_right_180" ] = %heat_stand_turn_180;
|
||||
|
||||
set_animarray_add_turn_aims_stand();
|
||||
|
||||
assert( !isdefined( anim.animsets.heatStand ) );
|
||||
anim.animsets.heatStand = anim.initAnimSet;
|
||||
}
|
||||
|
||||
init_animset_default_stand()
|
||||
{
|
||||
anim.initAnimSet = [];
|
||||
anim.initAnimSet[ "add_aim_up" ] = %exposed_aim_8;
|
||||
anim.initAnimSet[ "add_aim_down" ] = %exposed_aim_2;
|
||||
anim.initAnimSet[ "add_aim_left" ] = %exposed_aim_4;
|
||||
anim.initAnimSet[ "add_aim_right" ] = %exposed_aim_6;
|
||||
|
||||
anim.initAnimSet[ "straight_level" ] = %exposed_aim_5;
|
||||
|
||||
anim.initAnimSet[ "fire" ] = %exposed_shoot_auto_v3;
|
||||
anim.initAnimSet[ "single" ] = array( %exposed_shoot_semi1 );
|
||||
set_animarray_burst_and_semi_fire_stand();
|
||||
|
||||
anim.initAnimSet[ "exposed_idle" ] = array( %exposed_idle_alert_v1, %exposed_idle_alert_v2, %exposed_idle_alert_v3 );
|
||||
anim.initAnimSet[ "exposed_grenade" ] = array( %exposed_grenadeThrowB, %exposed_grenadeThrowC );
|
||||
|
||||
anim.initAnimSet[ "reload" ] = array( %exposed_reload );// %exposed_reloadb, %exposed_reloadc
|
||||
anim.initAnimSet[ "reload_crouchhide" ] = array( %exposed_reloadb );
|
||||
|
||||
set_animarray_stance_change();
|
||||
set_animarray_standing_turns();
|
||||
set_animarray_add_turn_aims_stand();
|
||||
|
||||
assert( !isdefined( anim.animsets.defaultStand ) );
|
||||
anim.animsets.defaultStand = anim.initAnimSet;
|
||||
}
|
||||
|
||||
|
||||
init_animset_default_crouch()
|
||||
{
|
||||
anim.initAnimSet = [];
|
||||
anim.initAnimSet[ "add_aim_up" ] = %exposed_crouch_aim_8;
|
||||
anim.initAnimSet[ "add_aim_down" ] = %exposed_crouch_aim_2;
|
||||
anim.initAnimSet[ "add_aim_left" ] = %exposed_crouch_aim_4;
|
||||
anim.initAnimSet[ "add_aim_right" ] = %exposed_crouch_aim_6;
|
||||
anim.initAnimSet[ "straight_level" ] = %exposed_crouch_aim_5;
|
||||
|
||||
anim.initAnimSet[ "fire" ] = %exposed_crouch_shoot_auto_v2;
|
||||
anim.initAnimSet[ "single" ] = array( %exposed_crouch_shoot_semi1 );
|
||||
set_animarray_burst_and_semi_fire_crouch();
|
||||
|
||||
anim.initAnimSet[ "reload" ] = array( %exposed_crouch_reload );
|
||||
|
||||
anim.initAnimSet[ "exposed_idle" ] = array( %exposed_crouch_idle_alert_v1, %exposed_crouch_idle_alert_v2, %exposed_crouch_idle_alert_v3 );
|
||||
|
||||
set_animarray_stance_change();
|
||||
set_animarray_crouching_turns();
|
||||
set_animarray_add_turn_aims_crouch();
|
||||
|
||||
assert( !isdefined( anim.animsets.defaultCrouch ) );
|
||||
anim.animsets.defaultCrouch = anim.initAnimSet;
|
||||
}
|
||||
|
||||
init_animset_rpg_crouch()
|
||||
{
|
||||
anim.initAnimSet = [];
|
||||
anim.initAnimSet[ "add_aim_up" ] = %RPG_crouch_aim_8;
|
||||
anim.initAnimSet[ "add_aim_down" ] = %RPG_crouch_aim_2;
|
||||
anim.initAnimSet[ "add_aim_left" ] = %RPG_crouch_aim_4;
|
||||
anim.initAnimSet[ "add_aim_right" ] = %RPG_crouch_aim_6;
|
||||
anim.initAnimSet[ "straight_level" ] = %RPG_crouch_aim_5;
|
||||
|
||||
anim.initAnimSet[ "fire" ] = %RPG_crouch_fire;
|
||||
anim.initAnimSet[ "single" ] = array( %RPG_crouch_fire );
|
||||
|
||||
anim.initAnimSet[ "reload" ] = array( %RPG_crouch_reload );
|
||||
|
||||
anim.initAnimSet[ "exposed_idle" ] = array( %RPG_crouch_idle );
|
||||
|
||||
set_animarray_stance_change();
|
||||
set_animarray_crouching_turns();
|
||||
set_animarray_add_turn_aims_crouch();
|
||||
|
||||
assert( !isdefined( anim.animsets.rpgCrouch ) );
|
||||
anim.animsets.rpgCrouch = anim.initAnimSet;
|
||||
}
|
||||
|
||||
|
||||
init_animset_shotgun_crouch()
|
||||
{
|
||||
anim.initAnimSet = [];
|
||||
anim.initAnimSet[ "add_aim_up" ] = %exposed_crouch_aim_8;
|
||||
anim.initAnimSet[ "add_aim_down" ] = %exposed_crouch_aim_2;
|
||||
anim.initAnimSet[ "add_aim_left" ] = %exposed_crouch_aim_4;
|
||||
anim.initAnimSet[ "add_aim_right" ] = %exposed_crouch_aim_6;
|
||||
anim.initAnimSet[ "straight_level" ] = %exposed_crouch_aim_5;
|
||||
|
||||
anim.initAnimSet[ "fire" ] = %exposed_crouch_shoot_auto_v2;
|
||||
anim.initAnimSet[ "single" ] = array( %shotgun_crouch_fire );
|
||||
set_animarray_burst_and_semi_fire_crouch();
|
||||
|
||||
anim.initAnimSet[ "reload" ] = array( %shotgun_crouch_reload );
|
||||
anim.initAnimSet[ "exposed_idle" ] = array( %exposed_crouch_idle_alert_v1, %exposed_crouch_idle_alert_v2, %exposed_crouch_idle_alert_v3 );
|
||||
|
||||
set_animarray_stance_change();
|
||||
set_animarray_crouching_turns();
|
||||
set_animarray_add_turn_aims_crouch();
|
||||
|
||||
assert( !isdefined( anim.animsets.shotgunCrouch ) );
|
||||
anim.animsets.shotgunCrouch = anim.initAnimSet;
|
||||
}
|
||||
|
||||
|
||||
init_animset_default_prone()
|
||||
{
|
||||
anim.initAnimSet = [];
|
||||
anim.initAnimSet[ "add_aim_up" ] = %prone_aim_8_add;
|
||||
anim.initAnimSet[ "add_aim_down" ] = %prone_aim_2_add;
|
||||
anim.initAnimSet[ "add_aim_left" ] = %prone_aim_4_add;
|
||||
anim.initAnimSet[ "add_aim_right" ] = %prone_aim_6_add;
|
||||
|
||||
anim.initAnimSet[ "straight_level" ] = %prone_aim_5;
|
||||
anim.initAnimSet[ "fire" ] = %prone_fire_1;
|
||||
|
||||
anim.initAnimSet[ "single" ] = array( %prone_fire_1 );
|
||||
anim.initAnimSet[ "reload" ] = array( %prone_reload );
|
||||
|
||||
anim.initAnimSet[ "burst2" ] = %prone_fire_burst;
|
||||
anim.initAnimSet[ "burst3" ] = %prone_fire_burst;
|
||||
anim.initAnimSet[ "burst4" ] = %prone_fire_burst;
|
||||
anim.initAnimSet[ "burst5" ] = %prone_fire_burst;
|
||||
anim.initAnimSet[ "burst6" ] = %prone_fire_burst;
|
||||
|
||||
anim.initAnimSet[ "semi2" ] = %prone_fire_burst;
|
||||
anim.initAnimSet[ "semi3" ] = %prone_fire_burst;
|
||||
anim.initAnimSet[ "semi4" ] = %prone_fire_burst;
|
||||
anim.initAnimSet[ "semi5" ] = %prone_fire_burst;
|
||||
|
||||
anim.initAnimSet[ "exposed_idle" ] = array( %exposed_crouch_idle_alert_v1, %exposed_crouch_idle_alert_v2, %exposed_crouch_idle_alert_v3 );
|
||||
|
||||
set_animarray_stance_change();
|
||||
|
||||
assert( !isdefined( anim.animsets.defaultProne ) );
|
||||
anim.animsets.defaultProne = anim.initAnimSet;
|
||||
}
|
||||
|
||||
|
||||
init_animset_complete_custom_stand( completeSet )
|
||||
{
|
||||
self.combatStandAnims = completeSet;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
init_animset_complete_custom_crouch( completeSet )
|
||||
{
|
||||
self.combatCrouchAnims = completeSet;
|
||||
}
|
||||
|
||||
init_animset_custom_crouch( fireAnim, idleAnim, reloadAnim )
|
||||
{
|
||||
assert( isdefined( anim.animsets ) && isdefined( anim.animsets.defaultCrouch ) );
|
||||
|
||||
anim.initAnimSet = anim.animsets.defaultCrouch;
|
||||
|
||||
if ( isdefined( fireAnim ) )
|
||||
{
|
||||
anim.initAnimSet[ "fire" ] = fireAnim;
|
||||
anim.initAnimSet[ "single" ] = array( fireAnim );
|
||||
set_animarray_custom_burst_and_semi_fire_crouch( fireAnim );
|
||||
}
|
||||
|
||||
if ( isdefined( idleAnim ) )
|
||||
anim.initAnimSet[ "exposed_idle" ] = array( idleAnim );
|
||||
|
||||
if ( isdefined( reloadAnim ) )
|
||||
anim.initAnimSet[ "reload" ] = array( reloadAnim );
|
||||
|
||||
self.combatCrouchAnims = anim.initAnimSet;
|
||||
}
|
||||
|
||||
|
||||
clear_custom_animset()
|
||||
{
|
||||
self.customMoveAnimSet = undefined;
|
||||
self.customIdleAnimSet = undefined;
|
||||
|
||||
self.combatStandAnims = undefined;
|
||||
self.combatCrouchAnims = undefined;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Helpers for the above init_*
|
||||
////////////////////////////////////////////
|
||||
|
||||
set_animarray_standing_turns_pistol( animArray )
|
||||
{
|
||||
anim.initAnimSet[ "turn_left_45" ] = %pistol_stand_turn45L;
|
||||
anim.initAnimSet[ "turn_left_90" ] = %pistol_stand_turn90L;
|
||||
anim.initAnimSet[ "turn_left_135" ] = %pistol_stand_turn90L;
|
||||
anim.initAnimSet[ "turn_left_180" ] = %pistol_stand_turn180L;
|
||||
anim.initAnimSet[ "turn_right_45" ] = %pistol_stand_turn45R;
|
||||
anim.initAnimSet[ "turn_right_90" ] = %pistol_stand_turn90R;
|
||||
anim.initAnimSet[ "turn_right_135" ] = %pistol_stand_turn90R;
|
||||
anim.initAnimSet[ "turn_right_180" ] = %pistol_stand_turn180L;
|
||||
}
|
||||
|
||||
set_animarray_standing_turns()
|
||||
{
|
||||
anim.initAnimSet[ "turn_left_45" ] = %exposed_tracking_turn45L;
|
||||
anim.initAnimSet[ "turn_left_90" ] = %exposed_tracking_turn90L;
|
||||
anim.initAnimSet[ "turn_left_135" ] = %exposed_tracking_turn135L;
|
||||
anim.initAnimSet[ "turn_left_180" ] = %exposed_tracking_turn180L;
|
||||
anim.initAnimSet[ "turn_right_45" ] = %exposed_tracking_turn45R;
|
||||
anim.initAnimSet[ "turn_right_90" ] = %exposed_tracking_turn90R;
|
||||
anim.initAnimSet[ "turn_right_135" ] = %exposed_tracking_turn135R;
|
||||
anim.initAnimSet[ "turn_right_180" ] = %exposed_tracking_turn180R;
|
||||
}
|
||||
|
||||
set_animarray_crouching_turns()
|
||||
{
|
||||
anim.initAnimSet[ "turn_left_45" ] = %exposed_crouch_turn_90_left;
|
||||
anim.initAnimSet[ "turn_left_90" ] = %exposed_crouch_turn_90_left;
|
||||
anim.initAnimSet[ "turn_left_135" ] = %exposed_crouch_turn_180_left;
|
||||
anim.initAnimSet[ "turn_left_180" ] = %exposed_crouch_turn_180_left;
|
||||
anim.initAnimSet[ "turn_right_45" ] = %exposed_crouch_turn_90_right;
|
||||
anim.initAnimSet[ "turn_right_90" ] = %exposed_crouch_turn_90_right;
|
||||
anim.initAnimSet[ "turn_right_135" ] = %exposed_crouch_turn_180_right;
|
||||
anim.initAnimSet[ "turn_right_180" ] = %exposed_crouch_turn_180_right;
|
||||
}
|
||||
|
||||
|
||||
set_animarray_stance_change()
|
||||
{
|
||||
anim.initAnimSet[ "crouch_2_stand" ] = %exposed_crouch_2_stand;
|
||||
anim.initAnimSet[ "crouch_2_prone" ] = %crouch_2_prone;
|
||||
anim.initAnimSet[ "stand_2_crouch" ] = %exposed_stand_2_crouch;
|
||||
anim.initAnimSet[ "stand_2_prone" ] = %stand_2_prone;
|
||||
anim.initAnimSet[ "prone_2_crouch" ] = %prone_2_crouch;
|
||||
anim.initAnimSet[ "prone_2_stand" ] = %prone_2_stand;
|
||||
}
|
||||
|
||||
set_animarray_burst_and_semi_fire_stand()
|
||||
{
|
||||
anim.initAnimSet[ "burst2" ] = %exposed_shoot_burst3;// ( will be stopped after second bullet )
|
||||
anim.initAnimSet[ "burst3" ] = %exposed_shoot_burst3;
|
||||
anim.initAnimSet[ "burst4" ] = %exposed_shoot_burst4;
|
||||
anim.initAnimSet[ "burst5" ] = %exposed_shoot_burst5;
|
||||
anim.initAnimSet[ "burst6" ] = %exposed_shoot_burst6;
|
||||
|
||||
anim.initAnimSet[ "semi2" ] = %exposed_shoot_semi2;
|
||||
anim.initAnimSet[ "semi3" ] = %exposed_shoot_semi3;
|
||||
anim.initAnimSet[ "semi4" ] = %exposed_shoot_semi4;
|
||||
anim.initAnimSet[ "semi5" ] = %exposed_shoot_semi5;
|
||||
}
|
||||
|
||||
|
||||
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_animarray_burst_and_semi_fire_crouch()
|
||||
{
|
||||
anim.initAnimSet[ "burst2" ] = %exposed_crouch_shoot_burst3;
|
||||
anim.initAnimSet[ "burst3" ] = %exposed_crouch_shoot_burst3;
|
||||
anim.initAnimSet[ "burst4" ] = %exposed_crouch_shoot_burst4;
|
||||
anim.initAnimSet[ "burst5" ] = %exposed_crouch_shoot_burst5;
|
||||
anim.initAnimSet[ "burst6" ] = %exposed_crouch_shoot_burst6;
|
||||
|
||||
anim.initAnimSet[ "semi2" ] = %exposed_crouch_shoot_semi2;
|
||||
anim.initAnimSet[ "semi3" ] = %exposed_crouch_shoot_semi3;
|
||||
anim.initAnimSet[ "semi4" ] = %exposed_crouch_shoot_semi4;
|
||||
anim.initAnimSet[ "semi5" ] = %exposed_crouch_shoot_semi5;
|
||||
}
|
||||
|
||||
set_animarray_custom_burst_and_semi_fire_crouch( 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_animarray_add_turn_aims_stand()
|
||||
{
|
||||
anim.initAnimSet[ "add_turn_aim_up" ] = %exposed_turn_aim_8;
|
||||
anim.initAnimSet[ "add_turn_aim_down" ] = %exposed_turn_aim_2;
|
||||
anim.initAnimSet[ "add_turn_aim_left" ] = %exposed_turn_aim_4;
|
||||
anim.initAnimSet[ "add_turn_aim_right" ] = %exposed_turn_aim_6;
|
||||
}
|
||||
|
||||
set_animarray_add_turn_aims_crouch()
|
||||
{
|
||||
anim.initAnimSet[ "add_turn_aim_up" ] = %exposed_crouch_turn_aim_8;
|
||||
anim.initAnimSet[ "add_turn_aim_down" ] = %exposed_crouch_turn_aim_2;
|
||||
anim.initAnimSet[ "add_turn_aim_left" ] = %exposed_crouch_turn_aim_4;
|
||||
anim.initAnimSet[ "add_turn_aim_right" ] = %exposed_crouch_turn_aim_6;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// 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() )
|
||||
{
|
||||
self.a.array = anim.animsets.cqbStand;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.a.array = anim.animsets.defaultStand;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Prone
|
||||
////////////////////////////////////////////
|
||||
|
||||
set_animarray_prone()
|
||||
{
|
||||
if ( usingSidearm() )
|
||||
animscripts\shared::placeWeaponOn( self.primaryweapon, "right" );
|
||||
|
||||
self.a.array = anim.animsets.defaultProne;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Moving turn
|
||||
////////////////////////////////////////////
|
||||
|
||||
init_moving_turn_animations()
|
||||
{
|
||||
anim.runTurnAnims[ "L90" ] = %run_turn_L90;
|
||||
anim.runTurnAnims[ "R90" ] = %run_turn_R90;
|
||||
anim.runTurnAnims[ "L45" ] = %run_turn_L45;
|
||||
anim.runTurnAnims[ "R45" ] = %run_turn_R45;
|
||||
anim.runTurnAnims[ "L135" ] = %run_turn_L135;
|
||||
anim.runTurnAnims[ "R135" ] = %run_turn_R135;
|
||||
anim.runTurnAnims[ "180" ] = %run_turn_180;
|
||||
|
||||
anim.cqbTurnAnims[ "L90" ] = %CQB_walk_turn_4;
|
||||
anim.cqbTurnAnims[ "R90" ] = %CQB_walk_turn_6;
|
||||
anim.cqbTurnAnims[ "L45" ] = %CQB_walk_turn_7;
|
||||
anim.cqbTurnAnims[ "R45" ] = %CQB_walk_turn_9;
|
||||
anim.cqbTurnAnims[ "L135" ] = %CQB_walk_turn_1;
|
||||
anim.cqbTurnAnims[ "R135" ] = %CQB_walk_turn_3;
|
||||
anim.cqbTurnAnims[ "180" ] = %CQB_walk_turn_2;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Misc
|
||||
////////////////////////////////////////////
|
||||
|
||||
|
||||
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[ "F" ] = %run_n_gun_F;
|
||||
self.runNGunAnims[ "L" ] = %run_n_gun_L;
|
||||
self.runNGunAnims[ "R" ] = %run_n_gun_R;
|
||||
self.runNGunAnims[ "LB" ] = %run_n_gun_L_120;
|
||||
self.runNGunAnims[ "RB" ] = %run_n_gun_R_120;
|
||||
}
|
||||
|
||||
|
||||
set_ambush_sidestep_anims()
|
||||
{
|
||||
assert( isdefined( self.a.moveAnimSet ) );
|
||||
|
||||
self.a.moveAnimSet[ "move_l" ] = %combatwalk_L;
|
||||
self.a.moveAnimSet[ "move_r" ] = %combatwalk_R;
|
||||
self.a.moveAnimSet[ "move_b" ] = %combatwalk_B;
|
||||
}
|
||||
|
||||
heat_reload_anim()
|
||||
{
|
||||
if ( self.weapon != self.primaryweapon )
|
||||
return animArrayPickRandom( "reload" );
|
||||
|
||||
if ( isdefined( self.node ) )
|
||||
{
|
||||
if ( self nearClaimNodeAndAngle() )
|
||||
{
|
||||
coverReloadAnim = undefined;
|
||||
if ( self.node.type == "Cover Left" )
|
||||
coverReloadAnim = %heat_cover_reload_R;
|
||||
else if ( self.node.type == "Cover Right" )
|
||||
coverReloadAnim = %heat_cover_reload_L;
|
||||
|
||||
if ( isdefined( coverReloadAnim ) )
|
||||
{
|
||||
//self mayMoveToPoint( reloadAnimPos );
|
||||
return coverReloadAnim;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return %heat_exposed_reload;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -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 ) ];
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\_utility;
|
||||
#include maps\_anim;
|
||||
#include animscripts\shared;
|
||||
|
||||
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
main()
|
||||
{
|
||||
animscripts\init::main();
|
||||
|
||||
civilian_init();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if ( !isdefined( level.initialized_civilian_animations ) )
|
||||
{
|
||||
level.initialized_civilian_animations = true;
|
||||
|
||||
level.scr_anim[ "default_civilian" ][ "run_combat" ][ 0 ] = %civilian_run_upright;
|
||||
|
||||
|
||||
level.scr_anim[ "default_civilian" ][ "run_hunched_combat" ][ 0 ] = %civilian_run_hunched_A;
|
||||
level.scr_anim[ "default_civilian" ][ "run_hunched_combat" ][ 1 ] = %civilian_run_hunched_C;
|
||||
level.scr_anim[ "default_civilian" ][ "run_hunched_combat" ][ 2 ] = %civilian_run_hunched_flinch;
|
||||
//%civilian_run_hunched_B;
|
||||
//%civilian_run_hunched_dodge;
|
||||
|
||||
level.scr_anim[ "default_civilian" ][ "run_noncombat" ][ 0 ] = %civilian_walk_cool;
|
||||
|
||||
weights = [];
|
||||
weights[ 0 ] = 3;
|
||||
weights[ 1 ] = 3;
|
||||
weights[ 2 ] = 1;
|
||||
//weights[ 3 ] = 1;
|
||||
//weights[ 4 ] = 1;
|
||||
|
||||
level.scr_anim[ "default_civilian" ][ "run_hunched_weights" ] = get_cumulative_weights( weights );
|
||||
|
||||
weights = [];
|
||||
weights[ 0 ] = 1;
|
||||
|
||||
level.scr_anim[ "default_civilian" ][ "run_weights" ] = get_cumulative_weights( weights );
|
||||
|
||||
level.scr_anim[ "default_civilian" ][ "idle_noncombat" ][ 0 ] = %unarmed_cowerstand_idle;
|
||||
//level.scr_anim[ "default_civilian" ][ "idle_noncombat" ][ 1 ] = %unarmed_cowerstand_pointidle;
|
||||
|
||||
level.scr_anim[ "default_civilian" ][ "idle_combat" ][ 0 ] = %casual_crouch_v2_idle;
|
||||
level.scr_anim[ "default_civilian" ][ "idle_combat" ][ 1 ] = %unarmed_cowercrouch_idle_duck;
|
||||
|
||||
// this animations look bad
|
||||
//level.scr_anim[ "default_civilian" ][ "idle_combat" ][ 0 ] = %unarmed_crouch_idle1;
|
||||
//level.scr_anim[ "default_civilian" ][ "idle_combat" ][ 1 ] = %unarmed_crouch_twitch1;
|
||||
|
||||
anim.civilianFlashedArray[ 0 ] = %unarmed_cowerstand_react;
|
||||
anim.civilianFlashedArray[ 1 ] = %unarmed_cowercrouch_react_A;
|
||||
anim.civilianFlashedArray[ 2 ] = %unarmed_cowercrouch_react_B;
|
||||
}
|
||||
|
||||
// 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 = %civilian_briefcase_walk_dodge_L;
|
||||
dodgeRight = %civilian_briefcase_walk_dodge_R;
|
||||
|
||||
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" ];
|
||||
}
|
||||
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" ];
|
||||
}
|
||||
|
||||
self.run_overrideBulletReact = [];
|
||||
self.run_overrideBulletReact[0] = %run_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.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
civilian_combatMoveTurn( angleDiff )
|
||||
{
|
||||
turnAnim = undefined;
|
||||
|
||||
if ( angleDiff < -22.5 )
|
||||
{
|
||||
if ( angleDiff > -45 )
|
||||
turnAnim = %civilian_run_upright_turnL45;
|
||||
else if ( angleDiff > -112.5 )
|
||||
turnAnim = %civilian_run_upright_turnL90;
|
||||
else if ( angleDiff > -157.5 )
|
||||
turnAnim = %civilian_run_upright_turnL135;
|
||||
else
|
||||
turnAnim = %civilian_run_upright_turn180;
|
||||
}
|
||||
else if ( angleDiff > 22.5 )
|
||||
{
|
||||
if ( angleDiff < 45 )
|
||||
turnAnim = %civilian_run_upright_turnR45;
|
||||
else if ( angleDiff < 112.5 )
|
||||
turnAnim = %civilian_run_upright_turnR90;
|
||||
else if ( angleDiff < 157.5 )
|
||||
turnAnim = %civilian_run_upright_turnR135;
|
||||
else
|
||||
turnAnim = %civilian_run_upright_turn180;
|
||||
}
|
||||
|
||||
if ( isdefined( turnAnim ) && animscripts\move::pathChange_canDoTurnAnim( turnAnim ) )
|
||||
return turnAnim;
|
||||
else
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
civilian_combatHunchedMoveTurn( angleDiff )
|
||||
{
|
||||
turnAnim = undefined;
|
||||
largeTurnAnim = undefined;
|
||||
|
||||
if ( angleDiff < -22.5 )
|
||||
{
|
||||
if ( angleDiff > -45 )
|
||||
turnAnim = %civilian_run_hunched_turnL45;
|
||||
else if ( angleDiff > -112.5 )
|
||||
{
|
||||
turnAnim = %civilian_run_hunched_turnL90;
|
||||
largeTurnAnim = randomAnimOfTwo( %civilian_run_hunched_turnL90_slide, %civilian_run_hunched_turnL90_stumble );
|
||||
}
|
||||
else if ( angleDiff > -157.5 )
|
||||
turnAnim = %civilian_run_upright_turnL135;
|
||||
else
|
||||
turnAnim = %civilian_run_upright_turn180;
|
||||
}
|
||||
else if ( angleDiff > 22.5 )
|
||||
{
|
||||
if ( angleDiff < 45 )
|
||||
turnAnim = %civilian_run_hunched_turnR45;
|
||||
else if ( angleDiff < 112.5 )
|
||||
{
|
||||
turnAnim = %civilian_run_hunched_turnR90;
|
||||
largeTurnAnim = randomAnimOfTwo( %civilian_run_hunched_turnR90_slide, %civilian_run_hunched_turnR90_stumble );
|
||||
}
|
||||
else if ( angleDiff < 157.5 )
|
||||
turnAnim = %civilian_run_upright_turnR135;
|
||||
else
|
||||
turnAnim = %civilian_run_upright_turn180;
|
||||
}
|
||||
|
||||
if ( isdefined( largeTurnAnim ) && ( randomint( 3 ) < 2 ) && animscripts\move::pathChange_canDoTurnAnim( largeTurnAnim ) )
|
||||
return largeTurnAnim;
|
||||
|
||||
if ( isdefined( turnAnim ) && animscripts\move::pathChange_canDoTurnAnim( turnAnim ) )
|
||||
return turnAnim;
|
||||
else
|
||||
return undefined;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
main()
|
||||
{
|
||||
animscripts\scripted::main();
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -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
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,971 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 )
|
||||
{
|
||||
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 )
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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" );
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
#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;
|
||||
|
||||
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 */
|
||||
{
|
||||
array = [];
|
||||
|
||||
array[ "alert_idle" ] = %corner_standL_alert_idle;
|
||||
array[ "alert_idle_twitch" ] = array(
|
||||
%corner_standL_alert_twitch01,
|
||||
%corner_standL_alert_twitch02,
|
||||
%corner_standL_alert_twitch03,
|
||||
%corner_standL_alert_twitch04,
|
||||
%corner_standL_alert_twitch05,
|
||||
%corner_standL_alert_twitch06,
|
||||
%corner_standL_alert_twitch07
|
||||
);
|
||||
array[ "alert_idle_flinch" ] = array( %corner_standL_flinch );
|
||||
|
||||
//array["alert_to_C"] = %corner_standL_trans_alert_2_C;
|
||||
//array["B_to_C"] = %corner_standL_trans_B_2_C;
|
||||
//array["C_to_alert"] = %corner_standL_trans_C_2_alert;
|
||||
//array["C_to_B"] = %corner_standL_trans_C_2_B;
|
||||
array[ "alert_to_A" ] = array( %corner_standL_trans_alert_2_A );
|
||||
array[ "alert_to_B" ] = array( %corner_standL_trans_alert_2_B_v2 );
|
||||
array[ "A_to_alert" ] = array( %corner_standL_trans_A_2_alert_v2 );
|
||||
array[ "A_to_alert_reload" ] = array();
|
||||
array[ "A_to_B" ] = array( %corner_standL_trans_A_2_B_v2 );
|
||||
array[ "B_to_alert" ] = array( %corner_standL_trans_B_2_alert_v2 );
|
||||
array[ "B_to_alert_reload" ] = array( %corner_standL_reload_B_2_alert );
|
||||
array[ "B_to_A" ] = array( %corner_standL_trans_B_2_A_v2 );
|
||||
array[ "lean_to_alert" ] = array( %CornerStndL_lean_2_alert );
|
||||
array[ "alert_to_lean" ] = array( %CornerStndL_alert_2_lean );
|
||||
array[ "look" ] = %corner_standL_look;
|
||||
array[ "reload" ] = array( %corner_standL_reload_v1 );// , %corner_standL_reload_v2 );
|
||||
array[ "grenade_exposed" ] = %corner_standL_grenade_A;
|
||||
array[ "grenade_safe" ] = %corner_standL_grenade_B;
|
||||
|
||||
array[ "blind_fire" ] = array( %corner_standL_blindfire_v1, %corner_standL_blindfire_v2 );
|
||||
|
||||
array[ "alert_to_look" ] = %corner_standL_alert_2_look;
|
||||
array[ "look_to_alert" ] = %corner_standL_look_2_alert;
|
||||
array[ "look_to_alert_fast" ] = %corner_standl_look_2_alert_fast_v1;
|
||||
array[ "look_idle" ] = %corner_standL_look_idle;
|
||||
array[ "stance_change" ] = %CornerCrL_stand_2_alert;
|
||||
|
||||
array[ "lean_aim_down" ] = %CornerStndL_lean_aim_2;
|
||||
array[ "lean_aim_left" ] = %CornerStndL_lean_aim_4;
|
||||
array[ "lean_aim_straight" ] = %CornerStndL_lean_aim_5;
|
||||
array[ "lean_aim_right" ] = %CornerStndL_lean_aim_6;
|
||||
array[ "lean_aim_up" ] = %CornerStndL_lean_aim_8;
|
||||
array[ "lean_reload" ] = %CornerStndL_lean_reload;
|
||||
|
||||
array[ "lean_idle" ] = array( %CornerStndL_lean_idle );
|
||||
|
||||
array[ "lean_single" ] = %CornerStndL_lean_fire;
|
||||
//array["lean_burst"] = %CornerStndL_lean_autoburst;
|
||||
array[ "lean_fire" ] = %CornerStndL_lean_auto;
|
||||
|
||||
if ( isDefined( anim.ramboAnims ) )
|
||||
{
|
||||
//array[ "rambo" ] = array( %corner_standL_rambo_set, %corner_standL_rambo_jam );
|
||||
array[ "rambo90" ] = anim.ramboAnims.coverleft90;
|
||||
array[ "rambo45" ] = anim.ramboAnims.coverleft45;
|
||||
array[ "grenade_rambo" ] = anim.ramboAnims.coverleftgrenade;
|
||||
}
|
||||
|
||||
self.hideYawOffset = 90;
|
||||
self.a.array = array;
|
||||
}
|
||||
|
||||
|
||||
set_animarray_crouching_left()
|
||||
{
|
||||
array = [];
|
||||
|
||||
array[ "alert_idle" ] = %CornerCrL_alert_idle;
|
||||
array[ "alert_idle_twitch" ] = array();
|
||||
array[ "alert_idle_flinch" ] = array();
|
||||
|
||||
//array["alert_to_C"] = %CornerCrL_trans_alert_2_C;
|
||||
//array["B_to_C"] = %CornerCrL_trans_B_2_C;
|
||||
//array["C_to_alert"] = %CornerCrL_trans_C_2_alert;
|
||||
//array["C_to_B"] = %CornerCrL_trans_C_2_B;
|
||||
array[ "alert_to_A" ] = array( %CornerCrL_trans_alert_2_A );
|
||||
array[ "alert_to_B" ] = array( %CornerCrL_trans_alert_2_B );
|
||||
array[ "A_to_alert" ] = array( %CornerCrL_trans_A_2_alert );
|
||||
array[ "A_to_alert_reload" ] = array();
|
||||
array[ "A_to_B" ] = array( %CornerCrL_trans_A_2_B );
|
||||
array[ "B_to_alert" ] = array( %CornerCrL_trans_B_2_alert );
|
||||
array[ "B_to_alert_reload" ] = array();
|
||||
array[ "B_to_A" ] = array( %CornerCrL_trans_B_2_A );
|
||||
array[ "lean_to_alert" ] = array( %CornerCrL_lean_2_alert );
|
||||
array[ "alert_to_lean" ] = array( %CornerCrL_alert_2_lean );
|
||||
|
||||
array[ "look" ] = %CornerCrL_look_fast;
|
||||
array[ "reload" ] = array( %CornerCrL_reloadA, %CornerCrL_reloadB );
|
||||
array[ "grenade_safe" ] = %CornerCrL_grenadeA;
|
||||
array[ "grenade_exposed" ] = %CornerCrL_grenadeB;
|
||||
|
||||
array[ "alert_to_over" ] = array( %CornerCrL_alert_2_over );
|
||||
array[ "over_to_alert" ] = array( %CornerCrL_over_2_alert );
|
||||
array[ "over_to_alert_reload" ] = array();
|
||||
array[ "blind_fire" ] = array();
|
||||
|
||||
array[ "rambo90" ] = array();
|
||||
array[ "rambo45" ] = array();
|
||||
|
||||
//array["alert_to_look"] = %CornerCrL_alert_idle; // TODO
|
||||
//array["look_to_alert"] = %CornerCrL_alert_idle; // TODO
|
||||
//array["look_to_alert_fast"] = %CornerCrL_alert_idle; // TODO
|
||||
//array["look_idle"] = %CornerCrL_alert_idle; // TODO
|
||||
array[ "stance_change" ] = %CornerCrL_alert_2_stand;
|
||||
|
||||
array[ "lean_aim_down" ] = %CornerCrL_lean_aim_2;
|
||||
array[ "lean_aim_left" ] = %CornerCrL_lean_aim_4;
|
||||
array[ "lean_aim_straight" ] = %CornerCrL_lean_aim_5;
|
||||
array[ "lean_aim_right" ] = %CornerCrL_lean_aim_6;
|
||||
array[ "lean_aim_up" ] = %CornerCrL_lean_aim_8;
|
||||
|
||||
array[ "lean_idle" ] = array( %CornerCrL_lean_idle );
|
||||
|
||||
array[ "lean_single" ] = %CornerCrL_lean_fire;
|
||||
array[ "lean_fire" ] = %CornerCrL_lean_auto;
|
||||
|
||||
self.hideYawOffset = 90;
|
||||
self.a.array = array;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,359 @@
|
||||
#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[ "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
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
#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;
|
||||
|
||||
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 */
|
||||
{
|
||||
array = [];
|
||||
|
||||
array[ "alert_idle" ] = %corner_standR_alert_idle;
|
||||
array[ "alert_idle_twitch" ] = array(
|
||||
%corner_standR_alert_twitch01,
|
||||
%corner_standR_alert_twitch02,
|
||||
%corner_standR_alert_twitch04,
|
||||
%corner_standR_alert_twitch05,
|
||||
%corner_standR_alert_twitch06,
|
||||
%corner_standR_alert_twitch07
|
||||
);
|
||||
array[ "alert_idle_flinch" ] = array( %corner_standR_flinch, %corner_standR_flinchB );
|
||||
|
||||
//array["alert_to_C"] = %corner_standR_trans_alert_2_C;
|
||||
//array["B_to_C"] = %corner_standR_trans_B_2_C;
|
||||
//array["C_to_alert"] = %corner_standR_trans_C_2_alert;
|
||||
//array["C_to_B"] = %corner_standR_trans_C_2_B;
|
||||
array[ "alert_to_A" ] = array( %corner_standR_trans_alert_2_A, %corner_standR_trans_alert_2_A_v2 );
|
||||
array[ "alert_to_B" ] = array( %corner_standR_trans_alert_2_B, %corner_standR_trans_alert_2_B_v2, %corner_standR_trans_alert_2_B_v3 );
|
||||
array[ "A_to_alert" ] = array( %corner_standR_trans_A_2_alert_v2 );
|
||||
array[ "A_to_alert_reload" ] = array();
|
||||
array[ "A_to_B" ] = array( %corner_standR_trans_A_2_B, %corner_standR_trans_A_2_B_v2 );
|
||||
array[ "B_to_alert" ] = array( %corner_standR_trans_B_2_alert, %corner_standR_trans_B_2_alert_v2, %corner_standR_trans_B_2_alert_v3 );
|
||||
array[ "B_to_alert_reload" ] = array( %corner_standR_reload_B_2_alert );
|
||||
array[ "B_to_A" ] = array( %corner_standR_trans_B_2_A, %corner_standR_trans_B_2_A_v2 );
|
||||
array[ "lean_to_alert" ] = array( %CornerStndR_lean_2_alert );
|
||||
array[ "alert_to_lean" ] = array( %CornerStndR_alert_2_lean );
|
||||
array[ "look" ] = %corner_standR_look;
|
||||
array[ "reload" ] = array( %corner_standR_reload_v1 );// , %corner_standR_reload_v2 );// v2 isn't finished, it seems
|
||||
array[ "grenade_exposed" ] = %corner_standR_grenade_A;
|
||||
array[ "grenade_safe" ] = %corner_standR_grenade_B;
|
||||
|
||||
array[ "blind_fire" ] = array( %corner_standR_blindfire_v1, %corner_standR_blindfire_v2 );
|
||||
|
||||
array[ "alert_to_look" ] = %corner_standR_alert_2_look;
|
||||
array[ "look_to_alert" ] = %corner_standR_look_2_alert;
|
||||
array[ "look_to_alert_fast" ] = %corner_standR_look_2_alert_fast;
|
||||
array[ "look_idle" ] = %corner_standR_look_idle;
|
||||
array[ "stance_change" ] = %CornerCrR_stand_2_alert;
|
||||
|
||||
array[ "lean_aim_down" ] = %CornerStndR_lean_aim_2;
|
||||
array[ "lean_aim_left" ] = %CornerStndR_lean_aim_4;
|
||||
array[ "lean_aim_straight" ] = %CornerStndR_lean_aim_5;
|
||||
array[ "lean_aim_right" ] = %CornerStndR_lean_aim_6;
|
||||
array[ "lean_aim_up" ] = %CornerStndR_lean_aim_8;
|
||||
array[ "lean_reload" ] = %CornerStndR_lean_reload;
|
||||
|
||||
array[ "lean_idle" ] = array( %CornerStndR_lean_idle );
|
||||
|
||||
array[ "lean_single" ] = %CornerStndR_lean_fire;
|
||||
//array["lean_burst"] = %CornerStndR_lean_autoburst;
|
||||
array[ "lean_fire" ] = %CornerStndR_lean_auto;
|
||||
|
||||
if ( isDefined( anim.ramboAnims ) )
|
||||
{
|
||||
//array[ "rambo" ] = array( %corner_standL_rambo_set, %corner_standL_rambo_jam );
|
||||
array[ "rambo90" ] = anim.ramboAnims.coverright90;
|
||||
array[ "rambo45" ] = anim.ramboAnims.coverright45;
|
||||
array[ "grenade_rambo" ] = anim.ramboAnims.coverrightgrenade;
|
||||
}
|
||||
|
||||
self.hideYawOffset = -90;
|
||||
self.a.array = array;
|
||||
}
|
||||
|
||||
set_animarray_crouching_right()
|
||||
{
|
||||
array = [];
|
||||
|
||||
array[ "alert_idle" ] = %CornerCrR_alert_idle;
|
||||
array[ "alert_idle_twitch" ] = array(
|
||||
%CornerCrR_alert_twitch_v1,
|
||||
%CornerCrR_alert_twitch_v2,
|
||||
%CornerCrR_alert_twitch_v3
|
||||
);
|
||||
array[ "alert_idle_flinch" ] = array();
|
||||
|
||||
//array["alert_to_C"] = %CornerCrR_trans_alert_2_C;
|
||||
//array["B_to_C"] = %CornerCrR_trans_B_2_C;
|
||||
//array["C_to_alert"] = %CornerCrR_trans_C_2_alert;
|
||||
//array["C_to_B"] = %CornerCrR_trans_C_2_B;
|
||||
array[ "alert_to_A" ] = array( %CornerCrR_trans_alert_2_A );
|
||||
array[ "alert_to_B" ] = array( %CornerCrR_trans_alert_2_B );
|
||||
array[ "A_to_alert" ] = array( %CornerCrR_trans_A_2_alert );
|
||||
array[ "A_to_alert_reload" ] = array();
|
||||
array[ "A_to_B" ] = array( %CornerCrR_trans_A_2_B );
|
||||
array[ "B_to_alert" ] = array( %CornerCrR_trans_B_2_alert );
|
||||
array[ "B_to_alert_reload" ] = array();
|
||||
array[ "B_to_A" ] = array( %CornerCrR_trans_B_2_A );
|
||||
array[ "lean_to_alert" ] = array( %CornerCrR_lean_2_alert );
|
||||
array[ "alert_to_lean" ] = array( %CornerCrR_alert_2_lean );
|
||||
array[ "reload" ] = array( %CornerCrR_reloadA, %CornerCrR_reloadB );
|
||||
array[ "grenade_exposed" ] = %CornerCrR_grenadeA;
|
||||
array[ "grenade_safe" ] = %CornerCrR_grenadeA;// TODO: need a unique animation for this; use the exposed throw because not having it limits the options of the AI too much
|
||||
|
||||
array[ "alert_to_over" ] = array( %CornerCrR_alert_2_over );
|
||||
array[ "over_to_alert" ] = array( %CornerCrR_over_2_alert );
|
||||
array[ "over_to_alert_reload" ] = array();
|
||||
|
||||
array[ "blind_fire" ] = array();
|
||||
|
||||
array[ "rambo90" ] = array();
|
||||
array[ "rambo45" ] = array();
|
||||
|
||||
array[ "alert_to_look" ] = %CornerCrR_alert_2_look;
|
||||
array[ "look_to_alert" ] = %CornerCrR_look_2_alert;
|
||||
array[ "look_to_alert_fast" ] = %CornerCrR_look_2_alert_fast;// there's a v2 we could use for this also if we want
|
||||
array[ "look_idle" ] = %CornerCrR_look_idle;
|
||||
array[ "stance_change" ] = %CornerCrR_alert_2_stand;
|
||||
|
||||
array[ "lean_aim_down" ] = %CornerCrR_lean_aim_2;
|
||||
array[ "lean_aim_left" ] = %CornerCrR_lean_aim_4;
|
||||
array[ "lean_aim_straight" ] = %CornerCrR_lean_aim_5;
|
||||
array[ "lean_aim_right" ] = %CornerCrR_lean_aim_6;
|
||||
array[ "lean_aim_up" ] = %CornerCrR_lean_aim_8;
|
||||
//array["lean_reload"] = %CornerStndR_lean_reload;
|
||||
|
||||
array[ "lean_idle" ] = array( %CornerCrR_lean_idle );
|
||||
|
||||
array[ "lean_single" ] = %CornerCrR_lean_fire;
|
||||
array[ "lean_fire" ] = %CornerCrR_lean_auto;
|
||||
|
||||
|
||||
self.hideYawOffset = -90;
|
||||
self.a.array = array;
|
||||
}
|
||||
|
||||
|
||||
@@ -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" );
|
||||
}
|
||||
@@ -0,0 +1,947 @@
|
||||
#include animscripts\Combat_utility;
|
||||
#include animscripts\Utility;
|
||||
#include common_scripts\Utility;
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
cover_wall_think( coverType )
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
|
||||
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 )
|
||||
{
|
||||
self setDefaultAimLimits( self.coverNode );
|
||||
self setup_crouching_anim_array( exposedAnimSet );
|
||||
}
|
||||
|
||||
|
||||
setup_cover_stand( exposedAnimSet )
|
||||
{
|
||||
self setDefaultAimLimits( self.coverNode );
|
||||
self setup_standing_anim_array( exposedAnimSet );
|
||||
}
|
||||
|
||||
|
||||
coverReload()
|
||||
{
|
||||
Reload( 2.0, animArray( "reload" ) );// ( reload no matter what )
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
setup_crouching_anim_array( exposedAnimSet )
|
||||
{
|
||||
anim_array = [];
|
||||
|
||||
anim_array[ "hide_idle" ] = %covercrouch_hide_idle;
|
||||
anim_array[ "hide_idle_twitch" ] = array(
|
||||
%covercrouch_twitch_1,
|
||||
%covercrouch_twitch_2,
|
||||
%covercrouch_twitch_3,
|
||||
%covercrouch_twitch_4
|
||||
//%covercrouch_twitch_5 // excluding #5 because it's a wave to someone behind him, and in idle twitches we don't know if that makes sense at the time
|
||||
);
|
||||
|
||||
anim_array[ "hide_idle_flinch" ] = array(
|
||||
/*%covercrouch_explosion_1,
|
||||
%covercrouch_explosion_2,
|
||||
%covercrouch_explosion_3*/ // these just don't look good for flinching
|
||||
);
|
||||
|
||||
anim_array[ "hide_2_crouch" ] = %covercrouch_hide_2_aim;
|
||||
anim_array[ "hide_2_stand" ] = %covercrouch_hide_2_stand;
|
||||
anim_array[ "hide_2_lean" ] = %covercrouch_hide_2_lean;
|
||||
anim_array[ "hide_2_right" ] = %covercrouch_hide_2_right;
|
||||
anim_array[ "hide_2_left" ] = %covercrouch_hide_2_left;
|
||||
|
||||
anim_array[ "crouch_2_hide" ] = %covercrouch_aim_2_hide;
|
||||
anim_array[ "stand_2_hide" ] = %covercrouch_stand_2_hide;
|
||||
anim_array[ "lean_2_hide" ] = %covercrouch_lean_2_hide;
|
||||
anim_array[ "right_2_hide" ] = %covercrouch_right_2_hide;
|
||||
anim_array[ "left_2_hide" ] = %covercrouch_left_2_hide;
|
||||
|
||||
|
||||
anim_array[ "crouch_aim" ] = %covercrouch_aim5;
|
||||
anim_array[ "stand_aim" ] = %exposed_aim_5;
|
||||
anim_array[ "lean_aim" ] = %covercrouch_lean_aim5;
|
||||
|
||||
anim_array[ "fire" ] = %exposed_shoot_auto_v2;
|
||||
anim_array[ "semi2" ] = %exposed_shoot_semi2;
|
||||
anim_array[ "semi3" ] = %exposed_shoot_semi3;
|
||||
anim_array[ "semi4" ] = %exposed_shoot_semi4;
|
||||
anim_array[ "semi5" ] = %exposed_shoot_semi5;
|
||||
|
||||
if ( weapon_pump_action_shotgun() )
|
||||
{
|
||||
if ( exposedAnimSet == "lean" || exposedAnimSet == "stand" )
|
||||
anim_array[ "single" ] = array( %shotgun_stand_fire_1A );
|
||||
else
|
||||
anim_array[ "single" ] = array( %shotgun_crouch_fire );
|
||||
}
|
||||
else
|
||||
{
|
||||
anim_array[ "single" ] = array( %exposed_shoot_semi1 );
|
||||
}
|
||||
|
||||
anim_array[ "burst2" ] = %exposed_shoot_burst3;// ( will be limited to 2 shots )
|
||||
anim_array[ "burst3" ] = %exposed_shoot_burst3;
|
||||
anim_array[ "burst4" ] = %exposed_shoot_burst4;
|
||||
anim_array[ "burst5" ] = %exposed_shoot_burst5;
|
||||
anim_array[ "burst6" ] = %exposed_shoot_burst6;
|
||||
|
||||
anim_array[ "blind_fire" ] = array( %covercrouch_blindfire_1, %covercrouch_blindfire_2, %covercrouch_blindfire_3, %covercrouch_blindfire_4 );
|
||||
|
||||
anim_array[ "reload" ] = %covercrouch_reload_hide;
|
||||
|
||||
anim_array[ "grenade_safe" ] = array( %covercrouch_grenadeA, %covercrouch_grenadeB );
|
||||
anim_array[ "grenade_exposed" ] = array( %covercrouch_grenadeA, %covercrouch_grenadeB );
|
||||
|
||||
anim_array[ "exposed_idle" ] = array( %exposed_idle_alert_v1, %exposed_idle_alert_v2, %exposed_idle_alert_v3 );
|
||||
|
||||
anim_array[ "look" ] = array( %covercrouch_hide_look );
|
||||
|
||||
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 = [];
|
||||
|
||||
anim_array[ "hide_idle" ] = %coverstand_hide_idle;
|
||||
anim_array[ "hide_idle_twitch" ] = array(
|
||||
%coverstand_hide_idle_twitch01,
|
||||
%coverstand_hide_idle_twitch02,
|
||||
%coverstand_hide_idle_twitch03,
|
||||
%coverstand_hide_idle_twitch04,
|
||||
%coverstand_hide_idle_twitch05
|
||||
);
|
||||
|
||||
anim_array[ "hide_idle_flinch" ] = array(
|
||||
%coverstand_react01,
|
||||
%coverstand_react02,
|
||||
%coverstand_react03,
|
||||
%coverstand_react04
|
||||
);
|
||||
|
||||
anim_array[ "hide_2_stand" ] = %coverstand_hide_2_aim;
|
||||
anim_array[ "stand_2_hide" ] = %coverstand_aim_2_hide;
|
||||
|
||||
anim_array[ "hide_2_over" ] = %coverstand_2_coverstandaim;
|
||||
anim_array[ "over_2_hide" ] = %coverstandaim_2_coverstand;
|
||||
|
||||
if ( exposedAnimSet == "over" )
|
||||
{
|
||||
anim_array[ "over_aim" ] = %coverstandaim_aim5;
|
||||
|
||||
anim_array[ "fire" ] = %coverstandaim_autofire;
|
||||
anim_array[ "semi2" ] = %coverstandaim_fire;
|
||||
anim_array[ "semi3" ] = %coverstandaim_fire;
|
||||
anim_array[ "semi4" ] = %coverstandaim_fire;
|
||||
anim_array[ "semi5" ] = %coverstandaim_fire;
|
||||
|
||||
anim_array[ "single" ] = array( %coverstandaim_fire );
|
||||
|
||||
anim_array[ "burst2" ] = %coverstandaim_autofire;// ( will be limited to 2 shots )
|
||||
anim_array[ "burst3" ] = %coverstandaim_autofire;
|
||||
anim_array[ "burst4" ] = %coverstandaim_autofire;
|
||||
anim_array[ "burst5" ] = %coverstandaim_autofire;
|
||||
anim_array[ "burst6" ] = %coverstandaim_autofire;
|
||||
}
|
||||
else
|
||||
{
|
||||
anim_array[ "stand_aim" ] = %exposed_aim_5;
|
||||
|
||||
anim_array[ "fire" ] = %exposed_shoot_auto_v2;
|
||||
anim_array[ "semi2" ] = %exposed_shoot_semi2;
|
||||
anim_array[ "semi3" ] = %exposed_shoot_semi3;
|
||||
anim_array[ "semi4" ] = %exposed_shoot_semi4;
|
||||
anim_array[ "semi5" ] = %exposed_shoot_semi5;
|
||||
|
||||
if ( weapon_pump_action_shotgun() )
|
||||
anim_array[ "single" ] = array( %shotgun_stand_fire_1A );
|
||||
else
|
||||
anim_array[ "single" ] = array( %exposed_shoot_semi1 );
|
||||
|
||||
anim_array[ "burst2" ] = %exposed_shoot_burst3;// ( will be limited to 2 shots )
|
||||
anim_array[ "burst3" ] = %exposed_shoot_burst3;
|
||||
anim_array[ "burst4" ] = %exposed_shoot_burst4;
|
||||
anim_array[ "burst5" ] = %exposed_shoot_burst5;
|
||||
anim_array[ "burst6" ] = %exposed_shoot_burst6;
|
||||
}
|
||||
|
||||
anim_array["blind_fire"] = array( %coverstand_blindfire_1, %coverstand_blindfire_2 /*, %coverstand_blindfire_3*/ ); // #3 looks silly
|
||||
|
||||
anim_array[ "reload" ] = %coverstand_reloadA;
|
||||
|
||||
anim_array[ "look" ] = array( %coverstand_look_quick, %coverstand_look_quick_v2 );
|
||||
|
||||
anim_array[ "grenade_safe" ] = array( %coverstand_grenadeA, %coverstand_grenadeB );
|
||||
anim_array[ "grenade_exposed" ] = array( %coverstand_grenadeA, %coverstand_grenadeB );
|
||||
|
||||
anim_array[ "exposed_idle" ] = array( %exposed_idle_alert_v1, %exposed_idle_alert_v2, %exposed_idle_alert_v3 );
|
||||
|
||||
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;
|
||||
|
||||
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 ( 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 ] );
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
#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;
|
||||
|
||||
if ( self.stairsState == "none" )
|
||||
transTime = 0.3;
|
||||
else
|
||||
transTime = 0.1; // need to transition to stairs quickly
|
||||
|
||||
// (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 animscripts\run::SetMoveNonForwardAnims( %walk_backward, %walk_left, %walk_right );
|
||||
self thread animscripts\run::SetCombatStandMoveAnimWeights( "cqb" );
|
||||
|
||||
animscripts\shared::DoNoteTracksForTime( 0.2, "runanim" );
|
||||
|
||||
self thread animscripts\run::stopShootWhileMovingThreads();
|
||||
}
|
||||
|
||||
DetermineCQBAnim()
|
||||
{
|
||||
if ( isdefined( self.customMoveAnimSet ) && isdefined( self.customMoveAnimSet[ "cqb" ] ) )
|
||||
return animscripts\run::GetRunAnim();
|
||||
|
||||
if ( self.stairsState == "up" )
|
||||
return %traverse_stair_run;
|
||||
|
||||
if ( self.stairsState == "down" )
|
||||
return %traverse_stair_run_down_01;
|
||||
|
||||
if ( self.movemode == "walk" )
|
||||
return %walk_CQB_F;
|
||||
|
||||
variation = getRandomIntFromSeed( self.a.runLoopCount, 2 );
|
||||
if ( variation == 0 )
|
||||
return %run_CQB_F_search_v1;
|
||||
|
||||
return %run_CQB_F_search_v2;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
#/
|
||||
|
||||
@@ -0,0 +1,956 @@
|
||||
#include common_scripts\utility;
|
||||
#include animscripts\utility;
|
||||
#include animscripts\combat_utility;
|
||||
#include maps\_utility;
|
||||
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
|
||||
//
|
||||
// Damage Yaw
|
||||
//
|
||||
// front
|
||||
// /----|----\
|
||||
// / 180 \
|
||||
// /\ | /\
|
||||
// / -135 | 135 \
|
||||
// | \ | / |
|
||||
// left|-90----+----90-|right
|
||||
// | / | \ |
|
||||
// \ -45 | 45 /
|
||||
// \/ | \/
|
||||
// \ 0 /
|
||||
// \----|----/
|
||||
// back
|
||||
|
||||
main()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
|
||||
// make sure the guy doesn't talk after death
|
||||
self stopsoundchannel( "voice" );
|
||||
changeTime = 0.3;
|
||||
self clearanim( %scripted_talking, changeTime );
|
||||
|
||||
// don't abort at this point unless you're going to play another animation!
|
||||
// just playing ragdoll isn't sufficient because sometimes ragdoll fails, and then
|
||||
// you'll just have a corpse standing around in limbo.
|
||||
|
||||
if ( self.a.nodeath == true )
|
||||
return;
|
||||
|
||||
if ( isdefined( self.deathFunction ) )
|
||||
{
|
||||
result = self [[ self.deathFunction ]]();
|
||||
if ( !isdefined( result ) )
|
||||
result = true;
|
||||
if ( result )
|
||||
return;
|
||||
}
|
||||
|
||||
animscripts\utility::initialize( "death" );
|
||||
|
||||
// should move this to squad manager somewhere...
|
||||
removeSelfFrom_SquadLastSeenEnemyPos( self.origin );
|
||||
|
||||
anim.numDeathsUntilCrawlingPain -- ;
|
||||
anim.numDeathsUntilCornerGrenadeDeath -- ;
|
||||
|
||||
if ( isDefined( self.ragdoll_immediate ) || self.forceRagdollImmediate )
|
||||
{
|
||||
self doImmediateRagdollDeath();
|
||||
// ragdoll can fail so don't assume that we can quit the function
|
||||
}
|
||||
|
||||
if ( isDefined( self.deathanim ) )
|
||||
{
|
||||
playDeathAnim( self.deathAnim );
|
||||
|
||||
// Added so that I can do special stuff in Level scripts on an ai
|
||||
if ( isdefined( self.deathanimscript ) )
|
||||
self [[ self.deathanimscript ]]();
|
||||
return;
|
||||
}
|
||||
|
||||
explosiveDamage = self animscripts\pain::wasDamagedByExplosive();
|
||||
|
||||
if ( self.damageLocation == "helmet" || self.damageLocation == "head" )
|
||||
self helmetPop();
|
||||
else if ( explosiveDamage && randomint( 3 ) == 0 )
|
||||
self helmetPop();
|
||||
|
||||
self clearanim( %root, 0.3 );
|
||||
|
||||
if ( !damageLocationIsAny( "head", "helmet" ) )
|
||||
{
|
||||
if ( self.dieQuietly )
|
||||
{
|
||||
// replace with actual die quietly gurglesque sound
|
||||
// if ( randomint(3) < 2 )
|
||||
// self animscripts\face::SayGenericDialogue("pain");
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayDeathSound();
|
||||
}
|
||||
}
|
||||
|
||||
if ( explosiveDamage && playExplodeDeathAnim() )
|
||||
return;
|
||||
|
||||
// different from deathFunction above, doesn't skip explosion deaths, immediate ragdoll, sounds, etc
|
||||
if ( isdefined( self.specialDeathFunc ) )
|
||||
{
|
||||
if ( [[ self.specialDeathFunc ]]() )
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: replace these with the above specialDeathFunc
|
||||
if ( specialDeath() )
|
||||
return;
|
||||
|
||||
deathAnim = getDeathAnim();
|
||||
|
||||
/#
|
||||
if ( getdvarint( "scr_paindebug" ) == 1 )
|
||||
println( "^2Playing pain: ", deathAnim, " ; pose is ", self.a.pose );
|
||||
#/
|
||||
|
||||
playDeathAnim( deathAnim );
|
||||
}
|
||||
|
||||
doImmediateRagdollDeath()
|
||||
{
|
||||
self animscripts\shared::DropAllAIWeapons();
|
||||
self.skipDeathAnim = true; // this helps playDeathAnim() do failsafes for ragdoll failures later
|
||||
|
||||
initialImpulse = 10;
|
||||
|
||||
damageType = common_scripts\_destructible::getDamageType( self.damageMod );
|
||||
if( IsDefined( self.attacker ) && self.attacker == level.player && damageType == "melee" )
|
||||
{
|
||||
initialImpulse = 5;
|
||||
}
|
||||
|
||||
damageTaken = self.damagetaken;
|
||||
if ( damageType == "bullet" )
|
||||
damageTaken = max( damageTaken, 300 );
|
||||
|
||||
directionScale = initialImpulse * damageTaken;
|
||||
directionUp = max( 0.3, self.damagedir[ 2 ] );
|
||||
direction = ( self.damagedir[ 0 ], self.damagedir[ 1 ], directionUp );
|
||||
direction *= directionScale;
|
||||
|
||||
if ( self.forceRagdollImmediate )
|
||||
direction += self.prevAnimDelta * 20 * 10; // 20 frames/sec
|
||||
|
||||
self startragdollfromimpact( self.damagelocation, direction );
|
||||
|
||||
// wait a bit so that the ragdoll can start before the death script tries to play a regular
|
||||
// death animation as a failsafe - if ragdolling, the regular death anim won't do anything when called
|
||||
wait( 0.05 );
|
||||
}
|
||||
|
||||
playDeathAnim( deathAnim )
|
||||
{
|
||||
if ( !animHasNoteTrack( deathAnim, "dropgun" ) && !animHasNoteTrack( deathAnim, "fire_spray" ) )// && !animHasNotetrack( deathAnim, "gun keep" )
|
||||
self animscripts\shared::DropAllAIWeapons();
|
||||
|
||||
//if ( isdefined( self.faceDamageDir ) )
|
||||
// self orientmode( "face angle", self.damageYaw );
|
||||
|
||||
self setFlaggedAnimKnobAllRestart( "deathanim", deathAnim, %body, 1, .1 );
|
||||
|
||||
if ( IsDefined( self.skipDeathAnim ) )
|
||||
{
|
||||
ASSERTEX( self.skipDeathAnim, "self.skipDeathAnim must be either true or undefined." );
|
||||
|
||||
if( !isdefined( self.noragdoll ) )
|
||||
self startRagDoll();
|
||||
|
||||
wait( 0.05 );
|
||||
// failsafe in case ragdoll fails: he'll still be playing a deathanim,
|
||||
// but at least he'll fall to the ground
|
||||
self AnimMode( "gravity" );
|
||||
}
|
||||
else if ( !animHasNotetrack( deathanim, "start_ragdoll" ) )
|
||||
{
|
||||
self thread waitForRagdoll( getanimlength( deathanim ) * 0.35 );
|
||||
}
|
||||
|
||||
// do we really need this anymore?
|
||||
/#
|
||||
if ( getdebugdvar( "debug_grenadehand" ) == "on" )
|
||||
{
|
||||
if ( animhasnotetrack( deathAnim, "bodyfall large" ) )
|
||||
return;
|
||||
if ( animhasnotetrack( deathAnim, "bodyfall small" ) )
|
||||
return;
|
||||
|
||||
println( "Death animation ", deathAnim, " does not have a bodyfall notetrack" );
|
||||
iprintlnbold( "Death animation needs fixing (check console and report bug in the animation to Boon)" );
|
||||
}
|
||||
#/
|
||||
|
||||
// SRS 11/20/08: blood pools don't always line up with ragdoll corpses, so skip them if
|
||||
// we did ragdoll without a death anim (which usually sends the body farther away from the death spot)
|
||||
if ( !IsDefined( self.skipDeathAnim ) )
|
||||
{
|
||||
self thread playDeathFX();
|
||||
}
|
||||
|
||||
self animscripts\shared::DoNoteTracks( "deathanim" );
|
||||
self animscripts\shared::DropAllAIWeapons();
|
||||
}
|
||||
|
||||
waitForRagdoll( time )
|
||||
{
|
||||
wait( time );
|
||||
if ( isdefined( self ) )
|
||||
self animscripts\shared::DropAllAIWeapons();
|
||||
if ( isdefined( self ) && !isdefined( self.noragdoll ) )
|
||||
self startragdoll();
|
||||
}
|
||||
|
||||
playDeathFX()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
//iprintlnbold("bleed'n");
|
||||
|
||||
if ( self.stairsState != "none" )
|
||||
return;
|
||||
|
||||
wait 2;
|
||||
|
||||
play_blood_pool();
|
||||
}
|
||||
|
||||
play_blood_pool( note, flagName )
|
||||
{
|
||||
if ( !isdefined( self ) )
|
||||
return;
|
||||
|
||||
if ( isdefined( self.skipBloodPool ) )
|
||||
{
|
||||
assertex( self.skipBloodPool, "Setting must be either true or undefined" );
|
||||
return;
|
||||
}
|
||||
|
||||
tagPos = self gettagorigin( "j_SpineUpper" ); // rough tag to play fx on
|
||||
tagAngles = self gettagangles( "j_SpineUpper" );
|
||||
forward = anglestoforward( tagAngles );
|
||||
up = anglestoup( tagAngles );
|
||||
right = anglestoright( tagAngles );
|
||||
|
||||
tagPos = tagPos + vector_multiply( forward, -8.5 ) + vector_multiply( up, 5 ) + vector_multiply( right, 0 );
|
||||
|
||||
trace = bulletTrace( tagPos + ( 0, 0, 30 ), tagPos - ( 0, 0, 100 ), false, undefined );
|
||||
|
||||
if ( trace[ "normal" ][2] > 0.9 )
|
||||
playfx( level._effect[ "deathfx_bloodpool_generic" ], tagPos );
|
||||
}
|
||||
|
||||
|
||||
// TODO: replace these with specialDeathFunc
|
||||
// Special death is for corners, rambo behavior, mg42's, anything out of the ordinary stand, crouch and prone.
|
||||
// It returns true if it handles the death for the special animation state, or false if it wants the regular
|
||||
// death function to handle it.
|
||||
specialDeath()
|
||||
{
|
||||
if ( self.a.special == "none" )
|
||||
return false;
|
||||
|
||||
switch( self.a.special )
|
||||
{
|
||||
case "cover_right":
|
||||
if ( self.a.pose == "stand" )
|
||||
{
|
||||
deathArray = [];
|
||||
deathArray[ 0 ] = %corner_standr_deathA;
|
||||
deathArray[ 1 ] = %corner_standr_deathB;
|
||||
DoDeathFromArray( deathArray );
|
||||
}
|
||||
else
|
||||
{
|
||||
deathArray = [];
|
||||
|
||||
if ( damageLocationIsAny( "head", "neck" ) )
|
||||
{
|
||||
deathArray[ 0 ] = %CornerCrR_alert_death_slideout;
|
||||
}
|
||||
else
|
||||
{
|
||||
deathArray[ 0 ] = %CornerCrR_alert_death_slideout;
|
||||
deathArray[ 1 ] = %CornerCrR_alert_death_back;
|
||||
}
|
||||
DoDeathFromArray( deathArray );
|
||||
}
|
||||
return true;
|
||||
|
||||
case "cover_left":
|
||||
if ( self.a.pose == "stand" )
|
||||
{
|
||||
deathArray = [];
|
||||
deathArray[ 0 ] = %corner_standl_deathA;
|
||||
deathArray[ 1 ] = %corner_standl_deathB;
|
||||
DoDeathFromArray( deathArray );
|
||||
}
|
||||
else
|
||||
{
|
||||
deathArray = [];
|
||||
deathArray[ 0 ] = %CornerCrL_death_side;
|
||||
deathArray[ 1 ] = %CornerCrL_death_back;
|
||||
DoDeathFromArray( deathArray );
|
||||
}
|
||||
return true;
|
||||
|
||||
case "cover_stand":
|
||||
deathArray = [];
|
||||
deathArray[ 0 ] = %coverstand_death_left;
|
||||
deathArray[ 1 ] = %coverstand_death_right;
|
||||
DoDeathFromArray( deathArray );
|
||||
return true;
|
||||
|
||||
case "cover_crouch":
|
||||
deathArray = [];
|
||||
if ( damageLocationIsAny( "head", "neck" ) && ( self.damageyaw > 135 || self.damageyaw <= -45 ) ) // Front / Left quadrant
|
||||
deathArray[ deathArray.size ] = %covercrouch_death_1;
|
||||
|
||||
if ( ( self.damageyaw > - 45 ) && ( self.damageyaw <= 45 ) ) // Back quadrant
|
||||
deathArray[ deathArray.size ] = %covercrouch_death_3;
|
||||
|
||||
deathArray[ deathArray.size ] = %covercrouch_death_2;
|
||||
|
||||
DoDeathFromArray( deathArray );
|
||||
return true;
|
||||
|
||||
case "saw":
|
||||
if ( self.a.pose == "stand" )
|
||||
DoDeathFromArray( array( %saw_gunner_death ) );
|
||||
else if ( self.a.pose == "crouch" )
|
||||
DoDeathFromArray( array( %saw_gunner_lowwall_death ) );
|
||||
else
|
||||
DoDeathFromArray( array( %saw_gunner_prone_death ) );
|
||||
return true;
|
||||
|
||||
case "dying_crawl":
|
||||
if ( isdefined( self.a.onback ) && self.a.pose == "crouch" )
|
||||
{
|
||||
deathArray = array( %dying_back_death_v2, %dying_back_death_v3, %dying_back_death_v4 );
|
||||
DoDeathFromArray( deathArray );
|
||||
}
|
||||
else
|
||||
{
|
||||
assertex( self.a.pose == "prone", self.a.pose );
|
||||
deathArray = array( %dying_crawl_death_v1, %dying_crawl_death_v2 );
|
||||
DoDeathFromArray( deathArray );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
DoDeathFromArray( deathArray )
|
||||
{
|
||||
deathAnim = deathArray[ randomint( deathArray.size ) ];
|
||||
|
||||
playDeathAnim( deathAnim );
|
||||
//nate - adding my own special death flag on top of special death.
|
||||
if ( isdefined( self.deathanimscript ) )
|
||||
self [[ self.deathanimscript ]]();
|
||||
}
|
||||
|
||||
|
||||
PlayDeathSound()
|
||||
{
|
||||
// if (self.team == "allies")
|
||||
// self playsound("allied_death");
|
||||
// else
|
||||
// self playsound("german_death");
|
||||
self animscripts\face::SayGenericDialogue( "death" );
|
||||
}
|
||||
|
||||
print3dfortime( place, text, time )
|
||||
{
|
||||
numframes = time * 20;
|
||||
for ( i = 0; i < numframes; i++ )
|
||||
{
|
||||
print3d( place, text );
|
||||
wait .05;
|
||||
}
|
||||
}
|
||||
|
||||
helmetPop()
|
||||
{
|
||||
if ( !isdefined( self ) )
|
||||
return;
|
||||
if ( !isdefined( self.hatModel ) )
|
||||
return;
|
||||
// used to check self removableHat() in cod2... probably not necessary though
|
||||
|
||||
partName = GetPartName( self.hatModel, 0 );
|
||||
model = spawn( "script_model", self.origin + ( 0, 0, 64 ) );
|
||||
model setmodel( self.hatModel );
|
||||
model.origin = self GetTagOrigin( partName );// self . origin + ( 0, 0, 64 );
|
||||
model.angles = self GetTagAngles( partName );// ( -90, 0 + randomint( 90 ), 0 + randomint( 90 ) );
|
||||
model thread helmetLaunch( self.damageDir );
|
||||
|
||||
hatModel = self.hatModel;
|
||||
self.hatModel = undefined;
|
||||
|
||||
wait 0.05;
|
||||
|
||||
if ( !isdefined( self ) )
|
||||
return;
|
||||
self detach( hatModel, "" );
|
||||
}
|
||||
|
||||
helmetLaunch( damageDir )
|
||||
{
|
||||
launchForce = damageDir;
|
||||
launchForce = launchForce * randomFloatRange( 2000, 4000 );
|
||||
|
||||
forcex = launchForce[ 0 ];
|
||||
forcey = launchForce[ 1 ];
|
||||
forcez = randomFloatRange( 1500, 3000 );
|
||||
|
||||
contactPoint = self.origin + ( randomfloatrange( -1, 1 ), randomfloatrange( -1, 1 ), randomfloatrange( -1, 1 ) ) * 5;
|
||||
|
||||
self PhysicsLaunchClient( contactPoint, ( forcex, forcey, forcez ) );
|
||||
|
||||
wait 60;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
if ( !isdefined( self ) )
|
||||
return;
|
||||
|
||||
if ( distanceSquared( self.origin, level.player.origin ) > 512 * 512 )
|
||||
break;
|
||||
|
||||
wait 30;
|
||||
}
|
||||
|
||||
self delete();
|
||||
}
|
||||
|
||||
|
||||
removeSelfFrom_SquadLastSeenEnemyPos( org )
|
||||
{
|
||||
for ( i = 0;i < anim.squadIndex.size;i++ )
|
||||
anim.squadIndex[ i ] clearSightPosNear( org );
|
||||
}
|
||||
|
||||
|
||||
clearSightPosNear( org )
|
||||
{
|
||||
if ( !isdefined( self.sightPos ) )
|
||||
return;
|
||||
|
||||
if ( distance( org, self.sightPos ) < 80 )
|
||||
{
|
||||
self.sightPos = undefined;
|
||||
self.sightTime = gettime();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
shouldDoRunningForwardDeath()
|
||||
{
|
||||
if ( self.a.movement != "run" )
|
||||
return false;
|
||||
|
||||
if ( self getMotionAngle() > 60 || self getMotionAngle() < - 60 )
|
||||
return false;
|
||||
|
||||
/*
|
||||
if ( ( self.damageyaw >= 120 ) || ( self.damageyaw <= -120 ) )// Front quadrant
|
||||
return true;
|
||||
|
||||
if ( ( self.damageyaw >= -45 ) && ( self.damageyaw <= 45 ) )// Back quadrant
|
||||
return true;
|
||||
|
||||
return false;
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
shouldDoStrongBulletDamage( damageWeapon, damageMod, damagetaken, attacker )
|
||||
{
|
||||
ASSERT( IsDefined( damageWeapon ) );
|
||||
|
||||
if ( isdefined( self.a.doingLongDeath ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( self.a.pose == "prone" || isdefined( self.a.onback ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( damageWeapon == "none" )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( damagetaken > 500 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( damageMod == "MOD_MELEE" )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// if I'm running, and the attacker is far enough away, sometimes let me do
|
||||
// a running death instead. this helps minimize repetition of strong damage animations
|
||||
// when a line of dudes is running towards you and you're mowing them down, etc.
|
||||
if( self.a.movement == "run" && !isAttackerWithinDist( attacker, 275 ) )
|
||||
{
|
||||
if( RandomInt( 100 ) < 65 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isSniperRifle( damageWeapon ) && self.maxHealth < damageTaken )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( isShotgun( damageWeapon ) && isAttackerWithinDist( attacker, 512 ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( isDesertEagle( damageWeapon ) && isAttackerWithinDist( attacker, 425 ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
isDesertEagle( damageWeapon )
|
||||
{
|
||||
if( damageWeapon == "deserteagle" )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
isAttackerWithinDist( attacker, maxDist )
|
||||
{
|
||||
if( !IsDefined( attacker ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( Distance( self.origin, attacker.origin ) > maxDist )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
getDeathAnim()
|
||||
{
|
||||
if ( shouldDoStrongBulletDamage( self.damageWeapon, self.damageMod, self.damagetaken, self.attacker ) )
|
||||
{
|
||||
deathAnim = getStrongBulletDamageDeathAnim();
|
||||
|
||||
if ( IsDefined( deathAnim ) )
|
||||
{
|
||||
return deathAnim;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isdefined( self.a.onback ) )
|
||||
{
|
||||
if ( self.a.pose == "crouch" )
|
||||
return getBackDeathAnim();
|
||||
else
|
||||
animscripts\shared::stopOnBack();
|
||||
}
|
||||
|
||||
if ( self.a.pose == "stand" )
|
||||
{
|
||||
if ( shouldDoRunningForwardDeath() )
|
||||
{
|
||||
return getRunningForwardDeathAnim();
|
||||
}
|
||||
else
|
||||
{
|
||||
return getStandDeathAnim();
|
||||
}
|
||||
}
|
||||
else if ( self.a.pose == "crouch" )
|
||||
{
|
||||
return getCrouchDeathAnim();
|
||||
}
|
||||
else if ( self.a.pose == "prone" )
|
||||
{
|
||||
return getProneDeathAnim();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// may return undefined
|
||||
// large death animation for shotguns, snipers etc.
|
||||
getStrongBulletDamageDeathAnim()
|
||||
{
|
||||
damageYaw = abs( self.damageYaw );
|
||||
|
||||
if ( damageYaw < 45 )
|
||||
return;
|
||||
|
||||
if ( damageYaw > 150 )
|
||||
{
|
||||
if ( damageLocationIsAny( "left_leg_upper", "left_leg_lower", "right_leg_upper", "right_leg_lower", "left_foot", "right_foot" ) )
|
||||
{
|
||||
deathArray = array( %death_shotgun_legs, %death_stand_sniper_leg );
|
||||
}
|
||||
else
|
||||
{
|
||||
deathArray = [];
|
||||
|
||||
if ( self.damageLocation == "torso_lower" )
|
||||
{
|
||||
deathArray[ deathArray.size ] = %death_shotgun_legs;
|
||||
deathArray[ deathArray.size ] = %death_stand_sniper_leg;
|
||||
}
|
||||
|
||||
deathArray[ deathArray.size ] = %death_shotgun_back_v1;
|
||||
deathArray[ deathArray.size ] = %exposed_death_blowback;
|
||||
deathArray[ deathArray.size ] = %death_stand_sniper_chest1;
|
||||
deathArray[ deathArray.size ] = %death_stand_sniper_chest2;
|
||||
deathArray[ deathArray.size ] = %death_stand_sniper_spin1;
|
||||
}
|
||||
|
||||
//self.faceDamageDir = true;
|
||||
}
|
||||
else if ( self.damageYaw < 0 )
|
||||
{
|
||||
deathArray = array( %death_shotgun_spinL, %death_stand_sniper_spin1, %death_stand_sniper_chest1, %death_stand_sniper_chest2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
deathArray = array( %death_shotgun_spinR, %death_stand_sniper_spin2, %death_stand_sniper_chest1, %death_stand_sniper_chest2 );
|
||||
}
|
||||
|
||||
return deathArray[ randomint( deathArray.size ) ];
|
||||
}
|
||||
|
||||
getRunningForwardDeathAnim()
|
||||
{
|
||||
deathArray = [];
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %run_death_facedown );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %run_death_roll );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %run_death_fallonback );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %run_death_flop );
|
||||
|
||||
deathArray = animscripts\pain::removeBlockedAnims( deathArray );
|
||||
|
||||
if ( !deathArray.size )
|
||||
return getStandDeathAnim();
|
||||
|
||||
return deathArray[ randomint( deathArray.size ) ];
|
||||
}
|
||||
|
||||
// remove undefined entries from array
|
||||
removeUndefined( array )
|
||||
{
|
||||
newArray = [];
|
||||
for ( index = 0; index < array.size; index++ )
|
||||
{
|
||||
if ( !isDefined( array[ index ] ) )
|
||||
continue;
|
||||
|
||||
newArray[ newArray.size ] = array[ index ];
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
|
||||
getStandPistolDeathAnim()
|
||||
{
|
||||
deathArray = [];
|
||||
|
||||
if ( abs( self.damageYaw ) < 50 )
|
||||
{
|
||||
deathArray[ deathArray.size ] = %pistol_death_2;// falls forwards
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( abs( self.damageYaw ) < 110 )
|
||||
deathArray[ deathArray.size ] = %pistol_death_2;// falls forwards
|
||||
|
||||
if ( damageLocationIsAny( "torso_lower", "torso_upper", "left_leg_upper", "left_leg_lower", "right_leg_upper", "right_leg_lower" ) )
|
||||
{
|
||||
deathArray[ deathArray.size ] = %pistol_death_3;// hit in groin from front
|
||||
if ( !damageLocationIsAny( "torso_upper" ) )
|
||||
deathArray[ deathArray.size ] = %pistol_death_3;// ( twice as likely )
|
||||
}
|
||||
|
||||
if ( !damageLocationIsAny( "head", "neck", "helmet", "left_foot", "right_foot", "left_hand", "right_hand", "gun" ) && randomint( 2 ) == 0 )
|
||||
deathArray[ deathArray.size ] = %pistol_death_4;// hit at top and falls backwards, but more dragged out
|
||||
|
||||
if ( deathArray.size == 0 || damageLocationIsAny( "torso_lower", "torso_upper", "neck", "head", "helmet", "right_arm_upper", "left_arm_upper" ) )
|
||||
deathArray[ deathArray.size ] = %pistol_death_1;// falls backwards
|
||||
}
|
||||
|
||||
return deathArray;
|
||||
}
|
||||
|
||||
getStandDeathAnim()
|
||||
{
|
||||
deathArray = [];
|
||||
extendedDeathArray = [];
|
||||
|
||||
if ( usingSidearm() )
|
||||
{
|
||||
deathArray = getStandPistolDeathAnim();
|
||||
}
|
||||
else
|
||||
{
|
||||
// torso or legs
|
||||
if ( damageLocationIsAny( "torso_lower", "left_leg_upper", "left_leg_lower", "right_leg_lower", "right_leg_lower" ) )
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_groin );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_leg );
|
||||
extendedDeathArray[ extendedDeathArray.size ] = tryAddDeathAnim( %stand_death_crotch );
|
||||
extendedDeathArray[ extendedDeathArray.size ] = tryAddDeathAnim( %stand_death_guts );
|
||||
}
|
||||
|
||||
if ( damageLocationIsAny( "head", "helmet" ) )
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_headshot );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_flop );
|
||||
}
|
||||
|
||||
if ( damageLocationIsAny( "neck" ) )
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_neckgrab );
|
||||
}
|
||||
|
||||
if ( damageLocationIsAny( "torso_upper", "left_arm_upper" ) )
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_twist );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_shoulder_spin );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_shoulderback );
|
||||
}
|
||||
|
||||
if ( damageLocationIsAny( "torso_upper" ) )
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_tumbleforward );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_stumbleforward );
|
||||
extendedDeathArray[ extendedDeathArray.size ] = tryAddDeathAnim( %stand_death_fallside );
|
||||
}
|
||||
|
||||
// quadrants
|
||||
if ( ( self.damageyaw > 135 ) || ( self.damageyaw <= -135 ) )// Front quadrant
|
||||
{
|
||||
if ( damageLocationIsAny( "neck", "head", "helmet" ) )
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_face );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_headshot_slowfall );
|
||||
extendedDeathArray[ extendedDeathArray.size ] = tryAddDeathAnim( %stand_death_head_straight_back );
|
||||
}
|
||||
|
||||
if ( damageLocationIsAny( "torso_upper" ) )
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %stand_death_tumbleback );
|
||||
extendedDeathArray[ extendedDeathArray.size ] = tryAddDeathAnim( %stand_death_chest_stunned );
|
||||
}
|
||||
}
|
||||
//else if ( ( self.damageyaw > 45 ) && ( self.damageyaw <= 135 ) )// Right quadrant
|
||||
//{
|
||||
//}
|
||||
else if ( ( self.damageyaw > -45 ) && ( self.damageyaw <= 45 ) )// Back quadrant
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_falltoknees );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_falltoknees_02 );
|
||||
}
|
||||
//else// Left quadrant
|
||||
//{
|
||||
//}
|
||||
|
||||
foundLocDamageDeath = ( deathArray.size > 0 );
|
||||
|
||||
if ( !foundLocDamageDeath || RandomInt( 100 ) < 15 )
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_02 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_death_nerve );
|
||||
}
|
||||
|
||||
if ( RandomInt( 100 ) < 10 && firingDeathAllowed() )
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddFiringDeathAnim( %exposed_death_firing_02 );
|
||||
deathArray[ deathArray.size ] = tryAddFiringDeathAnim( %exposed_death_firing );
|
||||
deathArray = removeUndefined( deathArray );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
assertex( deathArray.size > 0, deathArray.size );
|
||||
if ( deathArray.size == 0 )
|
||||
deathArray[ deathArray.size ] = %exposed_death;
|
||||
|
||||
if ( !self.a.disableLongDeath && self.stairsState == "none" && !isdefined( self.a.painOnStairs ) )
|
||||
{
|
||||
index = randomint( deathArray.size + extendedDeathArray.size );
|
||||
if ( index < deathArray.size )
|
||||
return deathArray[ index ];
|
||||
else
|
||||
return extendedDeathArray[ index - deathArray.size ];
|
||||
}
|
||||
|
||||
assertex( deathArray.size > 0, deathArray.size );
|
||||
return deathArray[ randomint( deathArray.size ) ];
|
||||
}
|
||||
|
||||
|
||||
getCrouchDeathAnim()
|
||||
{
|
||||
deathArray = [];
|
||||
|
||||
if ( damageLocationIsAny( "head", "neck" ) ) // Front / Left quadrant
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_crouch_death_fetal );
|
||||
|
||||
if ( damageLocationIsAny( "torso_upper", "torso_lower", "left_arm_upper", "right_arm_upper", "neck" ) )
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_crouch_death_flip );
|
||||
|
||||
if ( deathArray.size < 2 )
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_crouch_death_twist );
|
||||
if ( deathArray.size < 2 )
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %exposed_crouch_death_flip );
|
||||
|
||||
assertex( deathArray.size > 0, deathArray.size );
|
||||
return deathArray[ randomint( deathArray.size ) ];
|
||||
}
|
||||
|
||||
|
||||
getProneDeathAnim()
|
||||
{
|
||||
if ( isdefined( self.a.proneAiming ) )
|
||||
return %prone_death_quickdeath;
|
||||
else
|
||||
return %dying_crawl_death_v1;
|
||||
}
|
||||
|
||||
getBackDeathAnim()
|
||||
{
|
||||
deathArray = array( %dying_back_death_v1, %dying_back_death_v2, %dying_back_death_v3, %dying_back_death_v4 );
|
||||
return deathArray[ randomint( deathArray.size ) ];
|
||||
}
|
||||
|
||||
firingDeathAllowed()
|
||||
{
|
||||
if ( !isdefined( self.weapon ) || !usingRifleLikeWeapon() || !weaponIsAuto( self.weapon ) || self.dieQuietly )
|
||||
return false;
|
||||
|
||||
if ( self.a.weaponPos[ "right" ] == "none" )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
tryAddDeathAnim( animName )
|
||||
{
|
||||
assert( !animHasNoteTrack( animName, "fire" ) && !animHasNoteTrack( animName, "fire_spray" ) );
|
||||
return animName;
|
||||
}
|
||||
|
||||
tryAddFiringDeathAnim( animName )
|
||||
{
|
||||
assert( animHasNoteTrack( animName, "fire" ) || animHasNoteTrack( animName, "fire_spray" ) );
|
||||
return animName;
|
||||
}
|
||||
|
||||
playExplodeDeathAnim()
|
||||
{
|
||||
if ( isdefined( self.juggernaut ) )
|
||||
return false;
|
||||
|
||||
if ( self.damageLocation != "none" )
|
||||
return false;
|
||||
|
||||
deathArray = [];
|
||||
|
||||
if ( self.a.movement != "run" )
|
||||
{
|
||||
if ( ( self.damageyaw > 135 ) || ( self.damageyaw <= -135 ) ) // Front quadrant
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_B_v1 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_B_v2 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_B_v3 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_B_v4 );
|
||||
}
|
||||
else if ( ( self.damageyaw > 45 ) && ( self.damageyaw <= 135 ) ) // Right quadrant
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_L_v1 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_L_v2 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_L_v3 );
|
||||
}
|
||||
else if ( ( self.damageyaw > - 45 ) && ( self.damageyaw <= 45 ) ) // Back quadrant
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_F_v1 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_F_v2 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_F_v3 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_F_v4 );
|
||||
}
|
||||
else
|
||||
{ // Left quadrant
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_R_v1 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_stand_R_v2 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ( self.damageyaw > 135 ) || ( self.damageyaw <= -135 ) ) // Front quadrant
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_B_v1 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_B_v2 );
|
||||
}
|
||||
else if ( ( self.damageyaw > 45 ) && ( self.damageyaw <= 135 ) ) // Right quadrant
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_L_v1 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_L_v2 );
|
||||
}
|
||||
else if ( ( self.damageyaw > - 45 ) && ( self.damageyaw <= 45 ) ) // Back quadrant
|
||||
{
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_F_v1 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_F_v2 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_F_v3 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_F_v4 );
|
||||
}
|
||||
else
|
||||
{ // Left quadrant
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_R_v1 );
|
||||
deathArray[ deathArray.size ] = tryAddDeathAnim( %death_explosion_run_R_v2 );
|
||||
}
|
||||
}
|
||||
|
||||
deathAnim = deathArray[ randomint( deathArray.size ) ];
|
||||
|
||||
if ( getdvar( "scr_expDeathMayMoveCheck", "on" ) == "on" )
|
||||
{
|
||||
localDeltaVector = getMoveDelta( deathAnim, 0, 1 );
|
||||
endPoint = self localToWorldCoords( localDeltaVector );
|
||||
|
||||
if ( !self mayMoveToPoint( endPoint, false ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
// this should really be in the notetracks
|
||||
self animMode( "nogravity" );
|
||||
|
||||
playDeathAnim( deathAnim );
|
||||
return true;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,25 @@
|
||||
#using_animtree( "dog" );
|
||||
|
||||
main()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
if ( isdefined( self.a.nodeath ) )
|
||||
{
|
||||
assertex( self.a.nodeath, "Nodeath needs to be set to true or undefined." );
|
||||
|
||||
// allow death script to run for a bit so it doesn't turn to corpse and get deleted too soon during melee sequence
|
||||
wait 3;
|
||||
return;
|
||||
}
|
||||
|
||||
self unlink();
|
||||
|
||||
if ( isdefined( self.enemy ) && isdefined( self.enemy.syncedMeleeTarget ) && self.enemy.syncedMeleeTarget == self )
|
||||
{
|
||||
self.enemy.syncedMeleeTarget = undefined;
|
||||
}
|
||||
|
||||
self clearanim( %root, 0.2 );
|
||||
self setflaggedanimrestart( "dog_anim", %german_shepherd_death_front, 1, 0.2, 1 );
|
||||
self animscripts\shared::DoNoteTracks( "dog_anim" );
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#include animscripts\Combat_utility;
|
||||
#include maps\_utility;
|
||||
|
||||
#using_animtree( "dog" );
|
||||
|
||||
main()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
self endon( "stop_flashbang_effect" );
|
||||
|
||||
wait randomfloatrange( 0, 0.4 );
|
||||
|
||||
self clearanim( %root, 0.1 );
|
||||
|
||||
duration = self flashBangGetTimeLeftSec();
|
||||
|
||||
if ( duration > 2 && randomint( 100 ) > 60 )
|
||||
self setflaggedanimrestart( "flashed_anim", %german_shepherd_run_pain, 1, 0.2, self.animplaybackrate * 0.75 );
|
||||
else
|
||||
self setflaggedanimrestart( "flashed_anim", %german_shepherd_run_flashbang, 1, 0.2, self.animplaybackrate );
|
||||
|
||||
animLength = getanimlength( %german_shepherd_run_flashbang ) * self.animplaybackrate;
|
||||
|
||||
if ( duration < animLength )
|
||||
self animscripts\shared::DoNoteTracksForTime( duration, "flashed_anim" );
|
||||
else
|
||||
self animscripts\shared::DoNoteTracks( "flashed_anim" );
|
||||
|
||||
self.flashed = false;
|
||||
self notify( "stop_flashbang_effect" );
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
#using_animtree( "dog" );
|
||||
|
||||
main()
|
||||
{
|
||||
self useAnimTree( #animtree );
|
||||
|
||||
initDogAnimations();
|
||||
animscripts\init::firstInit();
|
||||
|
||||
self.ignoreSuppression = true;
|
||||
self.newEnemyReactionDistSq = 0;
|
||||
|
||||
self.chatInitialized = false;
|
||||
self.noDodgeMove = true;
|
||||
self.root_anim = %root;
|
||||
|
||||
self.meleeAttackDist = 0;
|
||||
self thread setMeleeAttackDist();
|
||||
|
||||
self.a = spawnStruct();
|
||||
self.a.pose = "stand"; // to use DoNoteTracks()
|
||||
self.a.nextStandingHitDying = false; // to allow dogs to use bullet shield
|
||||
self.a.movement = "run";
|
||||
|
||||
animscripts\init::set_anim_playback_rate();
|
||||
|
||||
self.suppressionThreshold = 1;
|
||||
self.disableArrivals = false;
|
||||
self.stopAnimDistSq = anim.dogStoppingDistSq;
|
||||
self.useChokePoints = false;
|
||||
self.turnRate = 0.2;
|
||||
|
||||
self thread animscripts\combat_utility::monitorFlash();
|
||||
|
||||
self.pathEnemyFightDist = 512;
|
||||
self setTalkToSpecies( "dog" );
|
||||
|
||||
self.health = int( anim.dog_health * self.health );
|
||||
}
|
||||
|
||||
|
||||
setMeleeAttackDist()
|
||||
{
|
||||
self endon( "death" );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
if ( isdefined( self.enemy ) && isplayer( self.enemy ) )
|
||||
self.meleeAttackDist = anim.dogAttackPlayerDist;
|
||||
else
|
||||
self.meleeAttackDist = anim.dogAttackAIDist;
|
||||
|
||||
self waittill( "enemy" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
initDogAnimations()
|
||||
{
|
||||
if ( !isdefined( level.dogsInitialized ) )
|
||||
{
|
||||
level.dogsInitialized = true;
|
||||
// [{+melee}] Melee the dog right when it bites to grab its throat.
|
||||
precachestring( &"SCRIPT_PLATFORM_DOG_DEATH_DO_NOTHING" );
|
||||
// [{+melee}] Melee the dog before it bites to grab its throat.
|
||||
precachestring( &"SCRIPT_PLATFORM_DOG_DEATH_TOO_LATE" );
|
||||
// [{+melee}] Wait for the dog to bite to grab its throat.
|
||||
precachestring( &"SCRIPT_PLATFORM_DOG_DEATH_TOO_SOON" );
|
||||
// [{+melee}]
|
||||
precachestring( &"SCRIPT_PLATFORM_DOG_HINT" );
|
||||
|
||||
// Watch for the ^3[{+melee}]^7 hint to grab a dog.
|
||||
precachestring( &"NEW_DOG_DEATH_DO_NOTHING_ALT" );
|
||||
// Too late. Watch for the ^3[{+melee}]^7 hint to grab a dog.
|
||||
precachestring( &"NEW_DOG_DEATH_TOO_LATE_ALT" );
|
||||
// Too early. Wait for the ^3[{+melee}]^7 hint to grab a dog.
|
||||
precachestring( &"NEW_DOG_DEATH_TOO_SOON_ALT" );
|
||||
}
|
||||
|
||||
// Initialization that should happen once per level
|
||||
if ( isDefined( anim.NotFirstTimeDogs ) )// Use this to trigger the first init
|
||||
return;
|
||||
precacheShader( "hud_dog_melee" );
|
||||
anim.NotFirstTimeDogs = 1;
|
||||
anim.dogStoppingDistSq = lengthSquared( getmovedelta( %german_shepherd_run_stop, 0, 1 ) * 1.2 ) ;
|
||||
anim.dogStartMoveDist = length( getmovedelta( %german_shepherd_run_start, 0, 1 ) );
|
||||
|
||||
// notetime = getNotetrackTimes( %german_shepherd_attack_player, "dog_melee" );
|
||||
// anim.dogAttackPlayerDist = length( getmovedelta( %german_shepherd_attack_player, 0, notetime[ 0 ] ) );
|
||||
anim.dogAttackPlayerDist = 102;// hard code for now, above is not accurate.
|
||||
|
||||
offset = getstartorigin( ( 0, 0, 0 ), ( 0, 0, 0 ), %german_shepherd_attack_AI_01_start_a );
|
||||
anim.dogAttackAIDist = length( offset );
|
||||
|
||||
anim.dogTraverseAnims = [];
|
||||
anim.dogTraverseAnims[ "wallhop" ] = %german_shepherd_run_jump_40;
|
||||
anim.dogTraverseAnims[ "window_40" ] = %german_shepherd_run_jump_window_40;
|
||||
anim.dogTraverseAnims[ "jump_down_40" ] = %german_shepherd_traverse_down_40;
|
||||
anim.dogTraverseAnims[ "jump_up_40" ] = %german_shepherd_traverse_up_40;
|
||||
anim.dogTraverseAnims[ "jump_up_80" ] = %german_shepherd_traverse_up_80;
|
||||
|
||||
// Dog start move animations
|
||||
// number indexes correspond to keyboard number directions
|
||||
anim.dogStartMoveAngles[ 8 ] = 0;
|
||||
anim.dogStartMoveAngles[ 6 ] = 90;
|
||||
anim.dogStartMoveAngles[ 4 ] = -90;
|
||||
anim.dogStartMoveAngles[ 3 ] = 180;
|
||||
anim.dogStartMoveAngles[ 1 ] = -180;
|
||||
|
||||
anim.dogStartMoveAnim[8] = %german_shepherd_run_start;
|
||||
anim.dogStartMoveAnim[6] = %german_shepherd_run_start_L;
|
||||
anim.dogStartMoveAnim[4] = %german_shepherd_run_start_R;
|
||||
anim.dogStartMoveAnim[3] = %german_shepherd_run_start_180_L;
|
||||
anim.dogStartMoveAnim[1] = %german_shepherd_run_start_180_R;
|
||||
|
||||
anim.dogLookPose[ "attackIdle" ][ 2 ] = %german_shepherd_attack_look_down;
|
||||
anim.dogLookPose[ "attackIdle" ][ 4 ] = %german_shepherd_attack_look_left;
|
||||
anim.dogLookPose[ "attackIdle" ][ 6 ] = %german_shepherd_attack_look_right;
|
||||
anim.dogLookPose[ "attackIdle" ][ 8 ] = %german_shepherd_attack_look_up;
|
||||
|
||||
anim.dogLookPose[ "normal" ][ 2 ] = %german_shepherd_look_down;
|
||||
anim.dogLookPose[ "normal" ][ 4 ] = %german_shepherd_look_left;
|
||||
anim.dogLookPose[ "normal" ][ 6 ] = %german_shepherd_look_right;
|
||||
anim.dogLookPose[ "normal" ][ 8 ] = %german_shepherd_look_up;
|
||||
|
||||
// effects used by dog
|
||||
level._effect[ "dog_bite_blood" ] = loadfx( "impacts/deathfx_dogbite" );
|
||||
level._effect[ "deathfx_bloodpool" ] = loadfx( "impacts/deathfx_bloodpool_view" );
|
||||
|
||||
// setup random timings for dogs attacking the player
|
||||
slices = 5;
|
||||
array = [];
|
||||
for ( i = 0; i <= slices; i++ )
|
||||
{
|
||||
array[ array.size ] = i / slices;
|
||||
}
|
||||
level.dog_melee_index = 0;
|
||||
level.dog_melee_timing_array = maps\_utility::array_randomize( array );
|
||||
|
||||
setdvar( "friendlySaveFromDog", "0" );
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
#include maps\_utility;
|
||||
#include animscripts\utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "dog" );
|
||||
|
||||
main()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
// self endon( "movemode" );
|
||||
|
||||
self clearanim( %root, 0.2 );
|
||||
self clearanim( %german_shepherd_run_stop, 0 );
|
||||
|
||||
if ( !isdefined( self.traverseComplete ) && !isdefined( self.skipStartMove ) && self.a.movement == "run" && ( !isdefined( self.disableExits ) || self.disableExits == false ) )
|
||||
self startMove();
|
||||
|
||||
self thread randomSoundDuringRunLoop();
|
||||
|
||||
self.traverseComplete = undefined;
|
||||
self.skipStartMove = undefined;
|
||||
|
||||
if ( self.a.movement == "run" )
|
||||
{
|
||||
weights = undefined;
|
||||
weights = self getRunAnimWeights();
|
||||
|
||||
self setanimrestart( %german_shepherd_run, weights[ "center" ], 0.2, 1 );
|
||||
self setanimrestart( %german_shepherd_run_lean_L, weights[ "left" ], 0.1, 1 );
|
||||
self setanimrestart( %german_shepherd_run_lean_R, weights[ "right" ], 0.1, 1 );
|
||||
self setflaggedanimknob( "dog_run", %german_shepherd_run_knob, 1, 0.2, self.moveplaybackrate );
|
||||
animscripts\shared::DoNoteTracksForTime( 0.1, "dog_run" );
|
||||
}
|
||||
else
|
||||
{
|
||||
self setflaggedanimrestart( "dog_walk", %german_shepherd_walk, 1, 0.2, self.moveplaybackrate );
|
||||
}
|
||||
|
||||
//self thread animscripts\dog\dog_stop::lookAtTarget( "normal" );
|
||||
self thread pathChangeCheck();
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
self moveLoop();
|
||||
|
||||
if ( self.a.movement == "run" )
|
||||
{
|
||||
if ( self.disableArrivals == false )
|
||||
self thread stopMove();
|
||||
|
||||
// if a "run" notify is received while stopping, clear stop anim and go back to moveLoop
|
||||
self waittill( "run" );
|
||||
self clearanim( %german_shepherd_run_stop, 0.1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
moveLoop()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
self endon( "stop_soon" );
|
||||
|
||||
self.moveLoopCleanupFunc = undefined;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
if ( self.disableArrivals )
|
||||
self.stopAnimDistSq = 0;
|
||||
else
|
||||
self.stopAnimDistSq = anim.dogStoppingDistSq;
|
||||
|
||||
if ( isDefined( self.moveLoopCleanupFunc ) )
|
||||
{
|
||||
self [[self.moveLoopCleanupFunc]]();
|
||||
self.moveLoopCleanupFunc = undefined;
|
||||
}
|
||||
|
||||
if ( isdefined( self.moveLoopOverrideFunc ) )
|
||||
self [[ self.moveLoopOverrideFunc ]]();
|
||||
else
|
||||
self moveLoopStep();
|
||||
}
|
||||
}
|
||||
|
||||
moveLoopStep()
|
||||
{
|
||||
self endon( "move_loop_restart" );
|
||||
|
||||
if ( self.a.movement == "run" )
|
||||
{
|
||||
weights = self getRunAnimWeights();
|
||||
|
||||
self clearanim( %german_shepherd_walk, 0.3 );
|
||||
|
||||
self setanim( %german_shepherd_run, weights[ "center" ], 0.2, 1 );
|
||||
self setanim( %german_shepherd_run_lean_L, weights[ "left" ], 0.2, 1 );
|
||||
self setanim( %german_shepherd_run_lean_R, weights[ "right" ], 0.2, 1 );
|
||||
self setflaggedanimknob( "dog_run", %german_shepherd_run_knob, 1, 0.2, self.moveplaybackrate );
|
||||
|
||||
animscripts\shared::DoNoteTracksForTime( 0.2, "dog_run" );
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( self.a.movement == "walk" );
|
||||
|
||||
self clearanim( %german_shepherd_run_knob, 0.3 );
|
||||
self setflaggedanim( "dog_walk", %german_shepherd_walk, 1, 0.2, self.moveplaybackrate );
|
||||
animscripts\shared::DoNoteTracksForTime( 0.2, "dog_walk" );
|
||||
}
|
||||
}
|
||||
|
||||
pathChangeCheck()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
|
||||
self.ignorePathChange = undefined; // this will be turned on / off in other threads at appropriate times
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
// no other thread should end on "path_changed"
|
||||
self waittill( "path_changed", doingReacquire, newDir );
|
||||
|
||||
// no need to check for doingReacquire since faceMotion should be a good check
|
||||
if ( isdefined( self.ignorePathChange ) || isdefined( self.noTurnAnims ) )
|
||||
continue;
|
||||
|
||||
if ( self.a.movement != "run" )
|
||||
continue;
|
||||
|
||||
angleDiff = AngleClamp180( self.angles[ 1 ] - vectortoyaw( newDir ) );
|
||||
|
||||
turnAnim = pathChange_getDogTurnAnim( angleDiff );
|
||||
|
||||
if ( isdefined( turnAnim ) )
|
||||
{
|
||||
self.turnAnim = turnAnim;
|
||||
self.turnTime = getTime();
|
||||
self.moveLoopOverrideFunc = ::pathChange_doDogTurnAnim;
|
||||
|
||||
self notify( "move_loop_restart" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pathChange_getDogTurnAnim( angleDiff )
|
||||
{
|
||||
turnAnim = undefined;
|
||||
|
||||
if ( angleDiff < -135 )
|
||||
{
|
||||
turnAnim = %german_shepherd_run_start_180_L;
|
||||
}
|
||||
else if ( angleDiff > 135 )
|
||||
{
|
||||
turnAnim = %german_shepherd_run_start_180_R;
|
||||
}
|
||||
|
||||
return turnAnim;
|
||||
}
|
||||
|
||||
|
||||
pathChange_doDogTurnAnim()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
|
||||
self.moveLoopOverrideFunc = undefined;
|
||||
|
||||
turnAnim = self.turnAnim;
|
||||
|
||||
if ( gettime() > self.turnTime + 50 )
|
||||
return; // too late
|
||||
|
||||
self animMode( "zonly_physics", false );
|
||||
self clearanim( %root, 0.2 );
|
||||
|
||||
self.moveLoopCleanupFunc = ::pathChange_cleanupDogTurnAnim;
|
||||
|
||||
self.ignorePathChange = true;
|
||||
|
||||
self setflaggedanimrestart( "turnAnim", turnAnim, 1, 0.2, self.movePlaybackRate );
|
||||
self OrientMode( "face current" );
|
||||
|
||||
// code move at 60%
|
||||
playTime = getanimlength( turnAnim ) * self.movePlaybackRate;
|
||||
self animscripts\shared::DoNoteTracksForTime( playTime * 0.60, "turnAnim" );
|
||||
|
||||
self.ignorePathChange = undefined;
|
||||
self OrientMode( "face motion" ); // want to face motion, don't do l / r / b anims
|
||||
self animmode( "none", false );
|
||||
|
||||
// cut off at 85%
|
||||
self animscripts\shared::DoNoteTracksForTime( playTime * 0.25, "turnAnim" );
|
||||
}
|
||||
|
||||
pathChange_cleanupDogTurnAnim()
|
||||
{
|
||||
self.ignorePathChange = undefined;
|
||||
|
||||
self OrientMode( "face default" );
|
||||
self clearanim( %root, 0.2 );
|
||||
self animMode( "none", false );
|
||||
}
|
||||
|
||||
startMoveTrackLookAhead()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
for ( i = 0; i < 2; i++ )
|
||||
{
|
||||
lookaheadAngle = vectortoangles( self.lookaheaddir );
|
||||
self OrientMode( "face angle", lookaheadAngle );
|
||||
}
|
||||
}
|
||||
|
||||
playMoveStartAnim()
|
||||
{
|
||||
endPos = self.origin;
|
||||
endPos += vector_multiply( self.lookaheaddir, anim.dogStartMoveDist );
|
||||
|
||||
tooClose = distanceSquared( self.origin, self.pathgoalpos ) < anim.dogStartMoveDist * anim.dogStartMoveDist;
|
||||
|
||||
if ( !tooClose && self mayMoveToPoint( endPos ) )
|
||||
{
|
||||
lookaheadAngle = vectortoangles( self.lookaheaddir );
|
||||
angle = AngleClamp180( lookaheadAngle[ 1 ] - self.angles[ 1 ] );
|
||||
|
||||
if ( angle >= 0 )
|
||||
{
|
||||
if ( angle < 45 )
|
||||
index = 8;
|
||||
else if ( angle < 135 )
|
||||
index = 6;
|
||||
else
|
||||
index = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( angle > -45 )
|
||||
index = 8;
|
||||
else if ( angle > -135 )
|
||||
index = 4;
|
||||
else
|
||||
index = 1;
|
||||
}
|
||||
|
||||
self setanimrestart( anim.dogStartMoveAnim[ index ], 1, 0.2, 1 );
|
||||
|
||||
animEndAngle = self.angles[ 1 ] + anim.dogStartMoveAngles[ index ];
|
||||
offsetAngle = AngleClamp180( lookaheadAngle[ 1 ] - animEndAngle );
|
||||
|
||||
self OrientMode( "face angle", self.angles[ 1 ] + offsetAngle );
|
||||
self animMode( "zonly_physics", false );
|
||||
|
||||
// code move at 60%
|
||||
playTime = getanimlength( anim.dogStartMoveAnim[ index ] ) * self.movePlaybackRate;
|
||||
self animscripts\shared::DoNoteTracksForTime( playTime * 0.60, "turnAnim" );
|
||||
|
||||
self OrientMode( "face motion" ); // want to face motion, don't do l / r / b anims
|
||||
self animmode( "none", false );
|
||||
|
||||
// cut off at 85%
|
||||
self animscripts\shared::DoNoteTracksForTime( playTime * 0.25, "turnAnim" );
|
||||
|
||||
|
||||
self clearanim( %root, 0.2 );
|
||||
}
|
||||
}
|
||||
|
||||
startMove()
|
||||
{
|
||||
if ( isdefined( self.pathgoalpos ) )
|
||||
{
|
||||
wait 0.05; // wait for lookaheaddir to settle
|
||||
|
||||
if ( isdefined( self.pathgoalpos ) )
|
||||
{
|
||||
self playMoveStartAnim();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// just use code movement
|
||||
self OrientMode( "face default" );
|
||||
self setanimrestart( %german_shepherd_run_start, 1, 0.2, 1 );
|
||||
self setflaggedanimknobrestart( "dog_prerun", %german_shepherd_run_start_knob, 1, 0.2, self.moveplaybackrate );
|
||||
|
||||
self animscripts\shared::DoNoteTracks( "dog_prerun" );
|
||||
|
||||
self animMode( "none", false );
|
||||
|
||||
self clearanim( %root, 0.2 );
|
||||
}
|
||||
|
||||
|
||||
stopMove()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
self endon( "run" );
|
||||
|
||||
self clearanim( %german_shepherd_run_knob, 0.1 );
|
||||
self setflaggedanimrestart( "stop_anim", %german_shepherd_run_stop, 1, 0.2, 1 );
|
||||
self animscripts\shared::DoNoteTracks( "stop_anim" );
|
||||
}
|
||||
|
||||
|
||||
dogPlaySoundAndNotify( sound, notifyStr )
|
||||
{
|
||||
self play_sound_on_tag_endon_death( sound, "tag_eye" );
|
||||
if ( isalive( self ) )
|
||||
self notify( notifyStr );
|
||||
}
|
||||
|
||||
randomSoundDuringRunLoop()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
|
||||
wait 0.2; // incase move script gets killed right away
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
/#
|
||||
if ( getdebugdvar( "debug_dog_sound" ) != "" )
|
||||
iprintln( "dog " + ( self getentnum() ) + " bark start " + getTime() );
|
||||
#/
|
||||
sound = undefined;
|
||||
if ( isdefined( self.script_growl ) )
|
||||
sound = "anml_dog_growl";
|
||||
else if ( !isdefined( self.script_nobark ) )
|
||||
sound = "anml_dog_bark";
|
||||
|
||||
if ( !isdefined( sound ) )
|
||||
break;
|
||||
|
||||
self thread dogPlaySoundAndNotify( sound, "randomRunSound" );
|
||||
self waittill( "randomRunSound" );
|
||||
/#
|
||||
if ( getdebugdvar( "debug_dog_sound" ) != "" )
|
||||
iprintln( "dog " + ( self getentnum() ) + " bark end " + getTime() );
|
||||
#/
|
||||
|
||||
wait( randomfloatrange( 0.1, 0.3 ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
getRunAnimWeights()
|
||||
{
|
||||
weights = [];
|
||||
weights[ "center" ] = 0;
|
||||
weights[ "left" ] = 0;
|
||||
weights[ "right" ] = 0;
|
||||
|
||||
if ( self.leanAmount > 0 )
|
||||
{
|
||||
if ( self.leanAmount < 0.95 )
|
||||
self.leanAmount = 0.95;
|
||||
|
||||
weights[ "left" ] = 0;
|
||||
weights[ "right" ] = ( 1 - self.leanAmount ) * 20;
|
||||
|
||||
if ( weights[ "right" ] > 1 )
|
||||
weights[ "right" ] = 1;
|
||||
else if ( weights[ "right" ] < 0 )
|
||||
weights[ "right" ] = 0;
|
||||
|
||||
weights[ "center" ] = 1 - weights[ "right" ];
|
||||
}
|
||||
else if ( self.leanAmount < 0 )
|
||||
{
|
||||
if ( self.leanAmount > - 0.95 )
|
||||
self.leanAmount = -0.95;
|
||||
|
||||
weights[ "right" ] = 0;
|
||||
weights[ "left" ] = ( 1 + self.leanAmount ) * 20;
|
||||
|
||||
if ( weights[ "left" ] > 1 )
|
||||
weights[ "left" ] = 1;
|
||||
if ( weights[ "left" ] < 0 )
|
||||
weights[ "left" ] = 0;
|
||||
|
||||
weights[ "center" ] = 1 - weights[ "left" ];
|
||||
}
|
||||
else
|
||||
{
|
||||
weights[ "left" ] = 0;
|
||||
weights[ "right" ] = 0;
|
||||
weights[ "center" ] = 1;
|
||||
}
|
||||
|
||||
return weights;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#using_animtree( "dog" );
|
||||
|
||||
main()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
|
||||
if ( isdefined( self.enemy ) && isdefined( self.enemy.syncedMeleeTarget ) && self.enemy.syncedMeleeTarget == self )
|
||||
{
|
||||
self unlink();
|
||||
self.enemy.syncedMeleeTarget = undefined;
|
||||
}
|
||||
|
||||
self clearanim( %root, 0.2 );
|
||||
self setflaggedanimrestart( "dog_pain_anim", %german_shepherd_run_pain, 1, 0.2, 1 );
|
||||
|
||||
self animscripts\shared::DoNoteTracks( "dog_pain_anim" );
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#using_animtree( "dog" );
|
||||
|
||||
main()
|
||||
{
|
||||
self endon( "death" );
|
||||
self notify( "killanimscript" );
|
||||
|
||||
self.codeScripted[ "root" ] = %root; // TEMP!
|
||||
|
||||
self endon( "end_sequence" );
|
||||
self startscriptedanim( self.codeScripted[ "notifyName" ], self.codeScripted[ "origin" ], self.codeScripted[ "angles" ], self.codeScripted[ "anim" ], self.codeScripted[ "animMode" ], self.codeScripted[ "root" ] );
|
||||
|
||||
self.codeScripted = undefined;
|
||||
|
||||
if ( isdefined( self.deathstring_passed ) )
|
||||
self.deathstring = self.deathstring_passed;
|
||||
|
||||
self waittill( "killanimscript" );
|
||||
}
|
||||
|
||||
init( notifyName, origin, angles, theAnim, animMode, root )
|
||||
{
|
||||
self.codeScripted[ "notifyName" ] = notifyName;
|
||||
self.codeScripted[ "origin" ] = origin;
|
||||
self.codeScripted[ "angles" ] = angles;
|
||||
self.codeScripted[ "anim" ] = theAnim;
|
||||
if ( isDefined( animMode ) )
|
||||
self.codeScripted[ "animMode" ] = animMode;
|
||||
else
|
||||
self.codeScripted[ "animMode" ] = "normal";
|
||||
if ( isDefined( root ) )
|
||||
self.codeScripted[ "root" ] = root;
|
||||
else
|
||||
self.codeScripted[ "root" ] = %root;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
#using_animtree( "dog" );
|
||||
|
||||
main()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
|
||||
self clearanim( %root, 0.2 );
|
||||
self clearanim( %german_shepherd_idle, 0.2 );
|
||||
self clearanim( %german_shepherd_attackidle_knob, 0.2 );
|
||||
|
||||
self thread lookAtTarget( "attackIdle" );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
if ( shouldAttackIdle() )
|
||||
{
|
||||
self clearanim( %german_shepherd_idle, 0.2 );
|
||||
self randomAttackIdle();
|
||||
}
|
||||
else
|
||||
{
|
||||
self orientmode( "face current" );
|
||||
self clearanim( %german_shepherd_attackidle_knob, 0.2 );
|
||||
self setflaggedanimrestart( "dog_idle", %german_shepherd_idle, 1, 0.2, self.animplaybackrate );
|
||||
}
|
||||
|
||||
animscripts\shared::DoNoteTracks( "dog_idle" );
|
||||
}
|
||||
}
|
||||
|
||||
isFacingEnemy( toleranceCosAngle )
|
||||
{
|
||||
assert( isdefined( self.enemy ) );
|
||||
|
||||
vecToEnemy = self.enemy.origin - self.origin;
|
||||
distToEnemy = length( vecToEnemy );
|
||||
|
||||
if ( distToEnemy < 1 )
|
||||
return true;
|
||||
|
||||
forward = anglesToForward( self.angles );
|
||||
|
||||
return( ( forward[ 0 ] * vecToEnemy[ 0 ] ) + ( forward[ 1 ] * vecToEnemy[ 1 ] ) ) / distToEnemy > toleranceCosAngle;
|
||||
}
|
||||
|
||||
randomAttackIdle()
|
||||
{
|
||||
if ( isFacingEnemy( -0.5 ) ) // cos120
|
||||
self orientmode( "face current" );
|
||||
else
|
||||
self orientmode( "face enemy" );
|
||||
|
||||
self clearanim( %german_shepherd_attackidle_knob, 0.1 );
|
||||
|
||||
if ( should_growl() )
|
||||
{
|
||||
// just growl
|
||||
self setflaggedanimrestart( "dog_idle", %german_shepherd_attackidle_growl, 1, 0.2, 1 );
|
||||
return;
|
||||
}
|
||||
|
||||
idleChance = 33;
|
||||
barkChance = 66;
|
||||
|
||||
if ( isdefined( self.mode ) )
|
||||
{
|
||||
if ( self.mode == "growl" )
|
||||
{
|
||||
idleChance = 15;
|
||||
barkChance = 30;
|
||||
}
|
||||
else if ( self.mode == "bark" )
|
||||
{
|
||||
idleChance = 15;
|
||||
barkChance = 85;
|
||||
}
|
||||
}
|
||||
|
||||
rand = randomInt( 100 );
|
||||
if ( rand < idleChance )
|
||||
self setflaggedanimrestart( "dog_idle", %german_shepherd_attackidle, 1, 0.2, self.animplaybackrate );
|
||||
else if ( rand < barkChance )
|
||||
self setflaggedanimrestart( "dog_idle", %german_shepherd_attackidle_bark, 1, 0.2, self.animplaybackrate );
|
||||
else
|
||||
self setflaggedanimrestart( "dog_idle", %german_shepherd_attackidle_growl, 1, 0.2, self.animplaybackrate );
|
||||
}
|
||||
|
||||
shouldAttackIdle()
|
||||
{
|
||||
return( isdefined( self.enemy ) && isalive( self.enemy ) && distanceSquared( self.origin, self.enemy.origin ) < 1000000 );
|
||||
}
|
||||
|
||||
should_growl()
|
||||
{
|
||||
if ( isdefined( self.script_growl ) )
|
||||
return true;
|
||||
if ( !isalive( self.enemy ) )
|
||||
return true;
|
||||
return !( self cansee( self.enemy ) );
|
||||
}
|
||||
|
||||
lookAtTarget( lookPoseSet )
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
self endon( "stop tracking" );
|
||||
|
||||
self clearanim( %german_shepherd_look_2, 0 );
|
||||
self clearanim( %german_shepherd_look_4, 0 );
|
||||
self clearanim( %german_shepherd_look_6, 0 );
|
||||
self clearanim( %german_shepherd_look_8, 0 );
|
||||
|
||||
self setDefaultAimLimits();
|
||||
self.rightAimLimit = 90;
|
||||
self.leftAimLimit = -90;
|
||||
|
||||
self setanimlimited( anim.dogLookPose[ lookPoseSet ][ 2 ], 1, 0 );
|
||||
self setanimlimited( anim.dogLookPose[ lookPoseSet ][ 4 ], 1, 0 );
|
||||
self setanimlimited( anim.dogLookPose[ lookPoseSet ][ 6 ], 1, 0 );
|
||||
self setanimlimited( anim.dogLookPose[ lookPoseSet ][ 8 ], 1, 0 );
|
||||
|
||||
self animscripts\shared::setAnimAimWeight( 1, 0.2 );
|
||||
|
||||
/#
|
||||
assert( !isdefined( self.trackLoopThread ) );
|
||||
self.trackLoopThread = thisthread;
|
||||
self.trackLoopThreadType = "lookAtTarget";
|
||||
#/
|
||||
|
||||
self animscripts\shared::trackLoop( %german_shepherd_look_2, %german_shepherd_look_4, %german_shepherd_look_6, %german_shepherd_look_8 );
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,502 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -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" );
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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" );
|
||||
}
|
||||
@@ -0,0 +1,910 @@
|
||||
#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 );
|
||||
|
||||
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;
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
// 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" );
|
||||
|
||||
self DoCustomAnim( turret, self.turretReloadAnim, true );
|
||||
}
|
||||
|
||||
DoCustomAnim( turret, anime, centerTurretFirst )
|
||||
{
|
||||
// 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" );
|
||||
|
||||
/*
|
||||
// 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, 1 );
|
||||
|
||||
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 );
|
||||
|
||||
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 );
|
||||
|
||||
// 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 );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
#include maps\_utility;
|
||||
#include common_scripts\utility;
|
||||
#include animscripts\hummer_turret\common;
|
||||
|
||||
main( turret )
|
||||
{
|
||||
turret.fireInterval = 0.1; // time between shots
|
||||
turret.closeEnoughAimDegrees = 45; // 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;
|
||||
|
||||
humvee_turret_init( turret, "minigun" );
|
||||
wait( 0.05 );
|
||||
|
||||
turret notify( "turret_ready" );
|
||||
}
|
||||
|
||||
minigun_cleanup_func( gunner, turret )
|
||||
{
|
||||
if ( turret GetBarrelSpinRate() > 0 )
|
||||
{
|
||||
turret StopBarrelSpin();
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
turret.extraFireTime_min = 600; // ms
|
||||
turret.extraFireTime_max = 900;
|
||||
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;
|
||||
|
||||
// the weapon will need periodic operator "maintenance"
|
||||
turret.secsOfFiringBeforeReload = 15; // secs
|
||||
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( turret.extraFireTime_min, turret.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();
|
||||
|
||||
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
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,60 @@
|
||||
#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 );
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,752 @@
|
||||
// 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
main()
|
||||
{
|
||||
prof_begin( "animscript_init" );
|
||||
self.a = spawnStruct();
|
||||
self.a.laserOn = false;
|
||||
self.primaryweapon = self.weapon;
|
||||
|
||||
firstInit();
|
||||
|
||||
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.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\animset::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();
|
||||
|
||||
prof_end( "animscript_init" );
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
firstInit()
|
||||
{
|
||||
// Initialization that should happen once per level
|
||||
if ( isDefined( anim.NotFirstTime ) )// Use this to trigger the first init
|
||||
return;
|
||||
anim.NotFirstTime = true;
|
||||
|
||||
animscripts\animset::init_anim_sets();
|
||||
|
||||
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::empty;
|
||||
|
||||
initDeveloperDvars();
|
||||
|
||||
setdvar( "scr_expDeathMayMoveCheck", "on" );
|
||||
|
||||
maps\_names::setup_names();
|
||||
|
||||
anim.animFlagNameIndex = 0;
|
||||
|
||||
animscripts\init_move_transitions::initMoveStartStopTransitions();
|
||||
animscripts\reactions::initReactionAnims();
|
||||
|
||||
anim.combatMemoryTimeConst = 10000;
|
||||
anim.combatMemoryTimeRand = 6000;
|
||||
|
||||
initGrenades();
|
||||
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[ "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::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 );
|
||||
}
|
||||
|
||||
initGrenades()
|
||||
{
|
||||
for ( i = 0; i < level.players.size; i++ )
|
||||
{
|
||||
player = level.players[ i ];
|
||||
player.grenadeTimers[ "fraggrenade" ] = randomIntRange( 1000, 20000 );
|
||||
player.grenadeTimers[ "flash_grenade" ] = randomIntRange( 1000, 20000 );
|
||||
player.grenadeTimers[ "double_grenade" ] = randomIntRange( 1000, 60000 );
|
||||
player.numGrenadesInProgressTowardsPlayer = 0;
|
||||
player.lastGrenadeLandedNearPlayerTime = -1000000;
|
||||
player.lastFragGrenadeToPlayerStart = -1000000;
|
||||
player thread setNextPlayerGrenadeTime();
|
||||
}
|
||||
anim.grenadeTimers[ "AI_fraggrenade" ] = randomIntRange( 0, 20000 );
|
||||
anim.grenadeTimers[ "AI_flash_grenade" ] = randomIntRange( 0, 20000 );
|
||||
anim.grenadeTimers[ "AI_smoke_grenade_american" ] = randomIntRange( 0, 20000 );
|
||||
|
||||
/#
|
||||
thread animscripts\combat_utility::grenadeTimerDebug();
|
||||
#/
|
||||
|
||||
initGrenadeThrowAnims();
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,918 @@
|
||||
#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;
|
||||
|
||||
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[ "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.431431; // delta of (34.0755, 2.01125, 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.451451; // delta of (33.0388, 0.964628, 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 )
|
||||
{
|
||||
return anim.coverExitSplit[ approachType ][ dir ];
|
||||
|
||||
/*exitAnim = anim.coverExit[ approachType ][ dir ];
|
||||
exitAlignTimes = getNotetrackTimes( exitAnim, "exit_align" );
|
||||
|
||||
assert( exitAlignTimes.size == 1 );
|
||||
if ( exitAlignTimes.size == 0 )
|
||||
return .5;
|
||||
|
||||
return exitAlignTimes[0];*/
|
||||
}
|
||||
|
||||
getTransSplitTime( approachType, dir )
|
||||
{
|
||||
return anim.coverTransSplit[ approachType ][ dir ];
|
||||
}
|
||||
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
@@ -0,0 +1,407 @@
|
||||
#include animscripts\SetPoseMovement;
|
||||
#include animscripts\Utility;
|
||||
#include common_scripts\Utility;
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
main()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
animscripts\utility::initialize( "reactions" );
|
||||
|
||||
self newEnemySurprisedReaction();
|
||||
}
|
||||
|
||||
|
||||
initReactionAnims()
|
||||
{
|
||||
anim.runningReactToBullets = [];
|
||||
anim.runningReactToBullets[ anim.runningReactToBullets.size ] = %run_react_duck;
|
||||
anim.runningReactToBullets[ anim.runningReactToBullets.size ] = %run_react_flinch;
|
||||
anim.runningReactToBullets[ anim.runningReactToBullets.size ] = %run_react_stumble;
|
||||
|
||||
anim.lastRunningReactAnim = 0;
|
||||
|
||||
|
||||
anim.coverReactions = [];
|
||||
anim.coverReactions[ "cover_stand" ] = array( %stand_cover_reaction_A, %stand_cover_reaction_B );
|
||||
anim.coverReactions[ "cover_crouch" ] = array( %crouch_cover_reaction_A, %crouch_cover_reaction_B );
|
||||
anim.coverReactions[ "cover_left" ] = array( %CornerStndL_react_A );
|
||||
anim.coverReactions[ "cover_right" ] = array( %CornerStndR_react_A );
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
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\run::SetMoveNonForwardAnims( %walk_backward, %walk_left, %walk_right );
|
||||
// self thread animscripts\run::SetCombatStandMoveAnimWeights( "walk" );
|
||||
|
||||
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 );
|
||||
|
||||
reactAnim = [];
|
||||
reactAnim[ 0 ] = %exposed_idle_reactA;
|
||||
reactAnim[ 1 ] = %exposed_idle_reactB;
|
||||
reactAnim[ 2 ] = %exposed_idle_twitch;
|
||||
reactAnim[ 3 ] = %exposed_idle_twitch_v4;
|
||||
|
||||
reaction = reactAnim[ randomint( reactAnim.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 );
|
||||
|
||||
diveAnim = randomAnimOfTwo( %exposed_dive_grenade_B, %exposed_dive_grenade_F );
|
||||
|
||||
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 );
|
||||
self setFlaggedAnimKnobRestart( "crouch", %exposed_stand_2_crouch, 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 )
|
||||
{
|
||||
twitchAnim = randomAnimOfTwo( %exposed_crouch_idle_twitch_v2, %exposed_crouch_idle_twitch_v3 );
|
||||
|
||||
self clearanim( %root, 0.1 );
|
||||
self setFlaggedAnimKnobRestart( "twitch", twitchAnim, 1, 0.1, 1 );
|
||||
self animscripts\shared::DoNoteTracks( "twitch" );
|
||||
|
||||
//if ( cointoss() )
|
||||
// self handsignal( "go" );
|
||||
}
|
||||
else
|
||||
{
|
||||
turnAnim = randomAnimOfTwo( %exposed_crouch_turn_180_left, %exposed_crouch_turn_180_right );
|
||||
|
||||
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.coverReactions[ self.prevScript ] ) )
|
||||
{
|
||||
nodeForward = anglesToForward( self.node.angles );
|
||||
dirToReactionTarget = vectorNormalize( self.reactionTargetPos - self.origin );
|
||||
|
||||
if ( vectorDot( nodeForward, dirToReactionTarget ) < -0.5 )
|
||||
{
|
||||
self orientmode( "face current" );
|
||||
index = randomint( anim.coverReactions[ self.prevScript ].size );
|
||||
reactAnim = anim.coverReactions[ self.prevScript ][ index ];
|
||||
}
|
||||
}
|
||||
|
||||
if ( !isdefined( reactAnim ) )
|
||||
{
|
||||
reactAnimArray = [];
|
||||
reactAnimArray[ 0 ] = %exposed_backpedal;
|
||||
reactAnimArray[ 1 ] = %exposed_idle_reactB;
|
||||
|
||||
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" );
|
||||
reactAnimArray[ 0 ] = %crouch_cover_reaction_A;
|
||||
reactAnimArray[ 1 ] = %crouch_cover_reaction_B;
|
||||
}
|
||||
}
|
||||
|
||||
reactAnim = reactAnimArray[ randomint( reactAnimArray.size ) ];
|
||||
}
|
||||
|
||||
return reactAnim;
|
||||
}
|
||||
|
||||
|
||||
stealthNewEnemyReactAnim()
|
||||
{
|
||||
self clearanim( %root, 0.2 );
|
||||
|
||||
if ( randomint( 4 ) < 3 )
|
||||
{
|
||||
self orientmode( "face enemy" );
|
||||
self setFlaggedAnimKnobRestart( "reactanim", %exposed_idle_reactB, 1, 0.2, 1 );
|
||||
time = getAnimLength( %exposed_idle_reactB );
|
||||
self animscripts\shared::DoNoteTracksForTime( time * 0.8, "reactanim" );
|
||||
|
||||
self orientmode( "face current" );
|
||||
}
|
||||
else
|
||||
{
|
||||
self orientmode( "face enemy" );
|
||||
self setFlaggedAnimKnobRestart( "reactanim", %exposed_backpedal, 1, 0.2, 1 );
|
||||
time = getAnimLength( %exposed_backpedal );
|
||||
self animscripts\shared::DoNoteTracksForTime( time * 0.8, "reactanim" );
|
||||
|
||||
self orientmode( "face current" );
|
||||
|
||||
self clearanim( %root, 0.2 );
|
||||
self setFlaggedAnimKnobRestart( "reactanim", %exposed_backpedal_v2, 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();
|
||||
}
|
||||
@@ -0,0 +1,800 @@
|
||||
#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";
|
||||
|
||||
|
||||
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[ "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\animset::init_animset_complete_custom_stand( animset );
|
||||
self animscripts\animset::init_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\animset::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" );
|
||||
}
|
||||
@@ -0,0 +1,939 @@
|
||||
#include animscripts\Utility;
|
||||
#include animscripts\Combat_Utility;
|
||||
#include animscripts\SetPoseMovement;
|
||||
#include common_scripts\utility;
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
MoveRun()
|
||||
{
|
||||
desiredPose = [[ self.choosePoseFunc ]]( "stand" );
|
||||
|
||||
switch( desiredPose )
|
||||
{
|
||||
case "stand":
|
||||
if ( BeginStandRun() )// returns false( and does nothing ) if we're already stand - running
|
||||
return;
|
||||
|
||||
if ( isDefined( self.run_overrideanim ) )
|
||||
{
|
||||
animscripts\move::MoveStandMoveOverride( self.run_overrideanim, self.run_override_weights );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( changeWeaponStandRun() )
|
||||
return;
|
||||
|
||||
if ( ReloadStandRun() )
|
||||
return;
|
||||
|
||||
if ( self animscripts\utility::IsInCombat() )
|
||||
MoveStandCombatNormal();
|
||||
else
|
||||
MoveStandNoncombatNormal();
|
||||
break;
|
||||
|
||||
case "crouch":
|
||||
if ( BeginCrouchRun() )// returns false( and does nothing ) if we're already crouch - running
|
||||
return;
|
||||
|
||||
if ( isDefined( self.crouchrun_combatanim ) )
|
||||
MoveCrouchRunOverride();
|
||||
else
|
||||
MoveCrouchRunNormal();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( desiredPose == "prone" );
|
||||
if ( BeginProneRun() )// returns false( and does nothing ) if we're already prone - running
|
||||
return;
|
||||
|
||||
ProneCrawl();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GetRunAnim()
|
||||
{
|
||||
if ( !isdefined( self.a.moveAnimSet ) )
|
||||
return %run_lowready_F;
|
||||
|
||||
if ( !self.faceMotion )
|
||||
{
|
||||
if ( self.stairsState == "none" || abs( self getMotionAngle() ) > 45 )
|
||||
return moveAnim( "move_f" );
|
||||
}
|
||||
|
||||
if ( self.stairsState == "up" )
|
||||
return moveAnim( "stairs_up" );
|
||||
else if ( self.stairsState == "down" )
|
||||
return moveAnim( "stairs_down" );
|
||||
|
||||
return moveAnim( "straight" );
|
||||
}
|
||||
|
||||
GetCrouchRunAnim()
|
||||
{
|
||||
if ( !isdefined( self.a.moveAnimSet ) )
|
||||
return %crouch_fastwalk_F;
|
||||
|
||||
return moveAnim( "crouch" );
|
||||
}
|
||||
|
||||
|
||||
ProneCrawl()
|
||||
{
|
||||
self.a.movement = "run";
|
||||
self setflaggedanimknob( "runanim", moveAnim( "prone" ), 1, .3, self.moveplaybackrate );
|
||||
animscripts\shared::DoNoteTracksForTime( 0.25, "runanim" );
|
||||
}
|
||||
|
||||
|
||||
InitRunNGun()
|
||||
{
|
||||
if ( !isdefined( self.runNGun ) )
|
||||
{
|
||||
self notify( "stop_move_anim_update" );
|
||||
self.update_move_anim_type = undefined;
|
||||
|
||||
self clearanim( %combatrun_backward, 0.2 );
|
||||
self clearanim( %combatrun_right, 0.2 );
|
||||
self clearanim( %combatrun_left, 0.2 );
|
||||
|
||||
self clearanim( %w_aim_2, 0.2 );
|
||||
self clearanim( %w_aim_4, 0.2 );
|
||||
self clearanim( %w_aim_6, 0.2 );
|
||||
self clearanim( %w_aim_8, 0.2 );
|
||||
|
||||
self.runNGun = true;
|
||||
}
|
||||
}
|
||||
|
||||
StopRunNGun()
|
||||
{
|
||||
if ( isdefined( self.runNGun ) )
|
||||
{
|
||||
self clearanim( %run_n_gun, 0.2 );
|
||||
self.runNGun = undefined;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
RunNGun( validTarget )
|
||||
{
|
||||
if ( validTarget )
|
||||
{
|
||||
enemyyaw = self GetPredictedYawToEnemy( 0.2 );
|
||||
leftWeight = enemyyaw < 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
enemyyaw = 0;
|
||||
leftWeight = self.runNGunWeight < 0;
|
||||
}
|
||||
|
||||
rightWeight = 1 - leftWeight;
|
||||
|
||||
maxRunNGunAngle = self.maxRunNGunAngle;
|
||||
runNGunTransitionPoint = self.runNGunTransitionPoint;
|
||||
runNGunIncrement = self.runNGunIncrement;
|
||||
|
||||
if ( !validTarget || ( squared( enemyyaw ) > maxRunNGunAngle * maxRunNGunAngle ) )
|
||||
{
|
||||
// phase out run n gun
|
||||
self clearAnim( %add_fire, 0 );
|
||||
if ( squared( self.runNGunWeight ) < runNGunIncrement * runNGunIncrement )
|
||||
{
|
||||
self.runNGunWeight = 0;
|
||||
self.runNGun = undefined;
|
||||
return false;
|
||||
}
|
||||
else if ( self.runNGunWeight > 0 )
|
||||
{
|
||||
self.runNGunWeight = self.runNGunWeight - runNGunIncrement;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.runNGunWeight = self.runNGunWeight + runNGunIncrement;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newWeight = enemyyaw / maxRunNGunAngle;
|
||||
diff = newWeight - self.runNGunWeight;
|
||||
|
||||
if ( abs( diff ) < runNGunTransitionPoint * 0.7 )
|
||||
self.runNGunWeight = newWeight;
|
||||
else if ( diff > 0 )
|
||||
self.runNGunWeight = self.runNGunWeight + runNGunIncrement;
|
||||
else
|
||||
self.runNGunWeight = self.runNGunWeight - runNGunIncrement;
|
||||
}
|
||||
|
||||
InitRunNGun();
|
||||
|
||||
absRunNGunWeight = abs( self.runNGunWeight );
|
||||
|
||||
if ( absRunNGunWeight > runNGunTransitionPoint )
|
||||
{
|
||||
weight = ( absRunNGunWeight - runNGunTransitionPoint ) / runNGunTransitionPoint;
|
||||
weight = clamp( weight, 0, 1 );
|
||||
|
||||
self clearanim( self.runNGunAnims[ "F" ], 0.2 );
|
||||
self setAnimLimited( self.runNGunAnims[ "L" ], ( 1.0 - weight ) * leftWeight, 0.2 );
|
||||
self setAnimLimited( self.runNGunAnims[ "R" ], ( 1.0 - weight ) * rightWeight, 0.2 );
|
||||
self setAnimLimited( self.runNGunAnims[ "LB" ], weight * leftWeight, 0.2 );
|
||||
self setAnimLimited( self.runNGunAnims[ "RB" ], weight * rightWeight, 0.2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
weight = clamp( absRunNGunWeight / runNGunTransitionPoint, 0, 1 );
|
||||
|
||||
self setAnimLimited( self.runNGunAnims[ "F" ], 1.0 - weight, 0.2 );
|
||||
self setAnimLimited( self.runNGunAnims[ "L" ], weight * leftWeight, 0.2 );
|
||||
self setAnimLimited( self.runNGunAnims[ "R" ], weight * rightWeight, 0.2 );
|
||||
|
||||
if ( runNGunTransitionPoint < 1 )
|
||||
{
|
||||
self clearanim( self.runNGunAnims[ "LB" ], 0.2 );
|
||||
self clearanim( self.runNGunAnims[ "RB" ], 0.2 );
|
||||
}
|
||||
}
|
||||
|
||||
self setFlaggedAnimKnob( "runanim", %run_n_gun, 1, 0.3, 0.8 );
|
||||
|
||||
self.a.allowedPartialReloadOnTheRunTime = gettime() + 500;
|
||||
|
||||
if ( validTarget && isplayer( self.enemy ) )
|
||||
self updatePlayerSightAccuracy();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RunNGun_Backward()
|
||||
{
|
||||
// we don't blend the running-backward animation because it
|
||||
// doesn't blend well with the run-left and run-right animations.
|
||||
// it's also easier to just play one animation than rework everything
|
||||
// to consider the possibility of multiple "backwards" animations
|
||||
|
||||
InitRunNGun();
|
||||
|
||||
self setFlaggedAnimKnob( "runanim", %combatwalk_B, 1, 0.3, 0.8 );
|
||||
|
||||
if ( isplayer( self.enemy ) )
|
||||
self updatePlayerSightAccuracy();
|
||||
|
||||
animscripts\shared::DoNoteTracksForTime( 0.2, "runanim" );
|
||||
|
||||
self thread stopShootWhileMovingThreads();
|
||||
|
||||
self clearAnim( %combatwalk_B, 0.2 );
|
||||
}
|
||||
|
||||
|
||||
ReactToBulletsInterruptCheck()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
wait 0.2;
|
||||
|
||||
if ( !isdefined( self.reactingToBullet ) )
|
||||
break;
|
||||
|
||||
if ( !isdefined( self.pathGoalPos ) || distanceSquared( self.pathGoalPos, self.origin ) < squared( 80 ) )
|
||||
{
|
||||
EndRunningReactToBullets();
|
||||
self notify( "interrupt_react_to_bullet" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EndRunningReactToBullets()
|
||||
{
|
||||
self orientmode( "face default" );
|
||||
self.reactingToBullet = undefined;
|
||||
self.requestReactToBullet = undefined;
|
||||
}
|
||||
|
||||
RunningReactToBullets()
|
||||
{
|
||||
self.aim_while_moving_thread = undefined;
|
||||
self notify( "end_face_enemy_tracking" );
|
||||
|
||||
/#
|
||||
assert( !isdefined( self.trackLoopThread ) );
|
||||
self.trackLoopThread = undefined;
|
||||
#/
|
||||
|
||||
self endon( "interrupt_react_to_bullet" );
|
||||
|
||||
self.reactingToBullet = true;
|
||||
self orientmode( "face motion" );
|
||||
|
||||
reactAnimIndex = randomint( anim.runningReactToBullets.size );
|
||||
if ( reactAnimIndex == anim.lastRunningReactAnim )
|
||||
reactAnimIndex = ( reactAnimIndex + 1 ) % anim.runningReactToBullets.size;
|
||||
|
||||
anim.lastRunningReactAnim = reactAnimIndex;
|
||||
|
||||
reactAnim = anim.runningReactToBullets[ reactAnimIndex ];
|
||||
self setFlaggedAnimKnobRestart( "reactanim", reactAnim, 1, 0.5 );
|
||||
|
||||
self thread ReactToBulletsInterruptCheck();
|
||||
self animscripts\shared::DoNoteTracks( "reactanim" );
|
||||
|
||||
EndRunningReactToBullets();
|
||||
}
|
||||
|
||||
|
||||
CustomRunningReactToBullets()
|
||||
{
|
||||
self.aim_while_moving_thread = undefined;
|
||||
self notify( "end_face_enemy_tracking" );
|
||||
|
||||
/#
|
||||
assert( !isdefined( self.trackLoopThread ) );
|
||||
self.trackLoopThread = undefined;
|
||||
#/
|
||||
|
||||
self.reactingToBullet = true;
|
||||
self orientmode( "face motion" );
|
||||
|
||||
assert( isdefined( self.run_overrideBulletReact ) );
|
||||
|
||||
reactAnimIndex = randomint( self.run_overrideBulletReact.size );
|
||||
reactAnim = self.run_overrideBulletReact[ reactAnimIndex ];
|
||||
|
||||
self setFlaggedAnimKnobRestart( "reactanim", reactAnim, 1, 0.5 );
|
||||
self thread ReactToBulletsInterruptCheck();
|
||||
self animscripts\shared::DoNoteTracks( "reactanim" );
|
||||
|
||||
EndRunningReactToBullets();
|
||||
}
|
||||
|
||||
|
||||
GetSprintAnim()
|
||||
{
|
||||
sprintAnim = undefined;
|
||||
|
||||
if ( isdefined( self.grenade ) )
|
||||
sprintAnim = moveAnim( "sprint_short" );
|
||||
|
||||
if ( !isdefined( sprintAnim ) )
|
||||
sprintAnim = moveAnim( "sprint" );
|
||||
|
||||
return sprintAnim;
|
||||
}
|
||||
|
||||
ShouldSprint()
|
||||
{
|
||||
if ( isdefined( self.sprint ) )
|
||||
return true;
|
||||
|
||||
if ( isdefined( self.grenade ) && isdefined( self.enemy ) && self.frontShieldAngleCos == 1 )
|
||||
return ( distanceSquared( self.origin, self.enemy.origin ) > 300 * 300 );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ShouldSprintForVariation()
|
||||
{
|
||||
if ( isdefined( self.neverSprintForVariation ) )
|
||||
return false;
|
||||
|
||||
if ( !self.faceMotion || self.stairsState != "none" )
|
||||
return false;
|
||||
|
||||
time = gettime();
|
||||
|
||||
if ( isdefined( self.dangerSprintTime ) )
|
||||
{
|
||||
if ( time < self.dangerSprintTime )
|
||||
return true;
|
||||
|
||||
// if already sprinted, don't do it again for at least 5 seconds
|
||||
if ( time - self.dangerSprintTime < 6000 )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !isdefined( self.enemy ) || !isSentient( self.enemy ) )
|
||||
return false;
|
||||
|
||||
if ( randomInt( 100 ) < 25 && ( self lastKnownTime( self.enemy ) + 2000 ) > time )
|
||||
{
|
||||
self.dangerSprintTime = time + 2000 + randomint( 1000 );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
GetMovePlaybackRate()
|
||||
{
|
||||
rate = self.moveplaybackrate;
|
||||
|
||||
if ( self.lookaheadHitsStairs && self.stairsState == "none" && self.lookaheadDist < 300 )
|
||||
rate *= 0.75;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
MoveStandCombatNormal()
|
||||
{
|
||||
//self clearanim( %walk_and_run_loops, 0.2 );
|
||||
|
||||
rate = GetMovePlaybackRate();
|
||||
|
||||
self setanimknob( %combatrun, 1.0, 0.5, rate );
|
||||
|
||||
decidedAnimation = false;
|
||||
|
||||
if ( isdefined( self.requestReactToBullet ) && gettime() - self.requestReactToBullet < 100 && randomFloat( 1 ) < self.a.reactToBulletChance )
|
||||
{
|
||||
StopRunNGun();
|
||||
RunningReactToBullets();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( self ShouldSprint() )
|
||||
{
|
||||
self setFlaggedAnimKnob( "runanim", GetSprintAnim(), 1, 0.5 );
|
||||
decidedAnimation = true;
|
||||
}
|
||||
else if ( isdefined( self.enemy ) && animscripts\move::MayShootWhileMoving() )
|
||||
{
|
||||
runShootWhileMovingThreads();
|
||||
|
||||
if ( !self.faceMotion )
|
||||
{
|
||||
self thread faceEnemyAimTracking();
|
||||
}
|
||||
else if ( ( self.shootStyle != "none" && !isdefined( self.noRunNGun ) ) )
|
||||
{
|
||||
self notify( "end_face_enemy_tracking" );
|
||||
self.aim_while_moving_thread = undefined;
|
||||
|
||||
/#
|
||||
assert( !isdefined( self.trackLoopThread ) );
|
||||
self.trackLoopThread = undefined;
|
||||
#/
|
||||
|
||||
if ( CanShootWhileRunningForward() )
|
||||
{
|
||||
decidedAnimation = self RunNGun( true );
|
||||
}
|
||||
else if ( CanShootWhileRunningBackward() )
|
||||
{
|
||||
self RunNGun_Backward();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( isdefined( self.runNGunWeight ) && self.runNGunWeight != 0 )
|
||||
{
|
||||
// can't shoot enemy anymore but still need to clear out runNGun
|
||||
decidedAnimation = self RunNGun( false );
|
||||
}
|
||||
}
|
||||
else if ( isdefined( self.runNGunWeight ) && self.runNGunWeight != 0 )
|
||||
{
|
||||
decidedAnimation = self RunNGun( false );
|
||||
}
|
||||
|
||||
if ( !decidedAnimation )
|
||||
{
|
||||
StopRunNGun();
|
||||
|
||||
if ( isdefined( self.requestReactToBullet ) && gettime() - self.requestReactToBullet < 100 && self.a.reactToBulletChance != 0 )
|
||||
{
|
||||
RunningReactToBullets();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ShouldSprintForVariation() )
|
||||
runAnim = moveAnim( "sprint_short" );
|
||||
else
|
||||
runAnim = GetRunAnim();
|
||||
|
||||
self setFlaggedAnimKnobLimited( "runanim", runAnim, 1, 0.1, 1, true );
|
||||
self SetMoveNonForwardAnims( moveAnim( "move_b" ), moveAnim( "move_l" ), moveAnim( "move_r" ), self.sideStepRate );
|
||||
|
||||
// Play the appropriately weighted run animations for the direction he's moving
|
||||
self thread SetCombatStandMoveAnimWeights( "run" );
|
||||
}
|
||||
|
||||
animscripts\shared::DoNoteTracksForTime( 0.2, "runanim" );
|
||||
|
||||
self thread stopShootWhileMovingThreads();
|
||||
}
|
||||
|
||||
faceEnemyAimTracking()
|
||||
{
|
||||
self notify( "want_aim_while_moving" );
|
||||
|
||||
assert( isdefined( self.aim_while_moving_thread ) == isdefined( self.trackLoopThread ) );
|
||||
assertex( !isdefined( self.trackLoopThread ) || (self.trackLoopThreadType == "faceEnemyAimTracking"), self.trackLoopThreadType );
|
||||
|
||||
if ( isdefined( self.aim_while_moving_thread ) )
|
||||
return;
|
||||
|
||||
self.aim_while_moving_thread = true;
|
||||
|
||||
/#
|
||||
self.trackLoopThread = thisthread;
|
||||
self.trackLoopThreadType = "faceEnemyAimTracking";
|
||||
#/
|
||||
|
||||
self endon( "killanimscript" );
|
||||
self endon( "end_face_enemy_tracking" );
|
||||
|
||||
self setDefaultAimLimits();
|
||||
|
||||
self setAnimLimited( %walk_aim_2 );
|
||||
self setAnimLimited( %walk_aim_4 );
|
||||
self setAnimLimited( %walk_aim_6 );
|
||||
self setAnimLimited( %walk_aim_8 );
|
||||
|
||||
self animscripts\shared::trackLoop( %w_aim_2, %w_aim_4, %w_aim_6, %w_aim_8 );
|
||||
}
|
||||
|
||||
endFaceEnemyAimTracking()
|
||||
{
|
||||
self.aim_while_moving_thread = undefined;
|
||||
self notify( "end_face_enemy_tracking" );
|
||||
|
||||
/#
|
||||
assert( !isdefined( self.trackLoopThread ) );
|
||||
self.trackLoopThread = undefined;
|
||||
#/
|
||||
}
|
||||
|
||||
runShootWhileMovingThreads()
|
||||
{
|
||||
self notify( "want_shoot_while_moving" );
|
||||
|
||||
if ( isdefined( self.shoot_while_moving_thread ) )
|
||||
return;
|
||||
self.shoot_while_moving_thread = true;
|
||||
|
||||
self thread RunDecideWhatAndHowToShoot();
|
||||
self thread RunShootWhileMoving();
|
||||
}
|
||||
|
||||
stopShootWhileMovingThreads()// we don't stop them if we shoot while moving again
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
self endon( "want_shoot_while_moving" );
|
||||
self endon( "want_aim_while_moving" );
|
||||
|
||||
wait .05;
|
||||
|
||||
self notify( "end_shoot_while_moving" );
|
||||
self notify( "end_face_enemy_tracking" );
|
||||
self.shoot_while_moving_thread = undefined;
|
||||
self.aim_while_moving_thread = undefined;
|
||||
|
||||
/#
|
||||
assert( !isdefined( self.trackLoopThread ) );
|
||||
self.trackLoopThread = undefined;
|
||||
#/
|
||||
|
||||
self.runNGun = undefined;
|
||||
}
|
||||
|
||||
|
||||
RunDecideWhatAndHowToShoot()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
self endon( "end_shoot_while_moving" );
|
||||
self animscripts\shoot_behavior::decideWhatAndHowToShoot( "normal" );
|
||||
}
|
||||
RunShootWhileMoving()
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
self endon( "end_shoot_while_moving" );
|
||||
self animscripts\move::shootWhileMoving();
|
||||
}
|
||||
|
||||
aimedSomewhatAtEnemy()
|
||||
{
|
||||
weaponAngles = self getMuzzleAngle();
|
||||
anglesToShootPos = vectorToAngles( self.enemy getShootAtPos() - self getMuzzlePos() );
|
||||
|
||||
if ( AbsAngleClamp180( weaponAngles[ 1 ] - anglesToShootPos[ 1 ] ) > 15 )
|
||||
return false;
|
||||
|
||||
return AbsAngleClamp180( weaponAngles[ 0 ] - anglesToShootPos[ 0 ] ) <= 20;
|
||||
}
|
||||
|
||||
CanShootWhileRunningForward()
|
||||
{
|
||||
// continue runNGun if runNGunWeight != 0
|
||||
if ( ( !isdefined( self.runNGunWeight ) || self.runNGunWeight == 0 ) && abs( self getMotionAngle() ) > self.maxRunNGunAngle )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CanShootWhileRunningBackward()
|
||||
{
|
||||
if ( 180 - abs( self getMotionAngle() ) >= 45 )
|
||||
return false;
|
||||
|
||||
enemyyaw = self GetPredictedYawToEnemy( 0.2 );
|
||||
if ( abs( enemyyaw ) > 30 )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CanShootWhileRunning()
|
||||
{
|
||||
return animscripts\move::MayShootWhileMoving() && isdefined( self.enemy ) && ( CanShootWhileRunningForward() || CanShootWhileRunningBackward() );
|
||||
}
|
||||
|
||||
GetPredictedYawToEnemy( lookAheadTime )
|
||||
{
|
||||
assert( isdefined( self.enemy ) );
|
||||
|
||||
selfPredictedPos = self.origin;
|
||||
moveAngle = self.angles[ 1 ] + self getMotionAngle();
|
||||
selfPredictedPos += ( cos( moveAngle ), sin( moveAngle ), 0 ) * length( self.velocity ) * lookAheadTime;
|
||||
|
||||
yaw = self.angles[ 1 ] - VectorToYaw( self.enemy.origin - selfPredictedPos );
|
||||
yaw = AngleClamp180( yaw );
|
||||
return yaw;
|
||||
}
|
||||
|
||||
MoveStandNoncombatNormal()
|
||||
{
|
||||
self endon( "movemode" );
|
||||
|
||||
self clearanim( %combatrun, 0.6 );
|
||||
|
||||
rate = GetMovePlaybackRate();
|
||||
|
||||
self setanimknoball( %combatrun, %body, 1, 0.2, rate );
|
||||
|
||||
if ( self ShouldSprint() )
|
||||
runAnim = GetSprintAnim();
|
||||
else
|
||||
runAnim = GetRunAnim();
|
||||
|
||||
if ( self.stairsState == "none" )
|
||||
transTime = 0.3; // 0.3 because it pops when the AI goes from combat to noncombat
|
||||
else
|
||||
transTime = 0.1; // need to transition to stairs quickly
|
||||
|
||||
self setflaggedanimknob( "runanim", runAnim, 1, transTime, 1, true );
|
||||
|
||||
self SetMoveNonForwardAnims( moveAnim( "move_b" ), moveAnim( "move_l" ), moveAnim( "move_r" ) );
|
||||
self thread SetCombatStandMoveAnimWeights( "run" );
|
||||
|
||||
animscripts\shared::DoNoteTracksForTime( 0.2, "runanim" );
|
||||
}
|
||||
|
||||
MoveCrouchRunOverride()
|
||||
{
|
||||
self endon( "movemode" );
|
||||
|
||||
self setflaggedanimknoball( "runanim", self.crouchrun_combatanim, %body, 1, 0.4, self.moveplaybackrate );
|
||||
animscripts\shared::DoNoteTracks( "runanim" );
|
||||
}
|
||||
|
||||
MoveCrouchRunNormal()
|
||||
{
|
||||
self endon( "movemode" );
|
||||
|
||||
// Play the appropriately weighted crouchrun animations for the direction he's moving
|
||||
forward_anim = GetCrouchRunAnim();
|
||||
|
||||
self setanimknob( forward_anim, 1, 0.4 );
|
||||
|
||||
self thread UpdateMoveAnimWeights( "crouchrun", forward_anim, %crouch_fastwalk_B, %crouch_fastwalk_L, %crouch_fastwalk_R );
|
||||
|
||||
self setflaggedanimknoball( "runanim", %crouchrun, %body, 1, 0.2, self.moveplaybackrate );
|
||||
|
||||
animscripts\shared::DoNoteTracksForTime( 0.2, "runanim" );
|
||||
}
|
||||
|
||||
ReloadStandRun()
|
||||
{
|
||||
reloadIfEmpty = isdefined( self.a.allowedPartialReloadOnTheRunTime ) && self.a.allowedPartialReloadOnTheRunTime > gettime();
|
||||
reloadIfEmpty = reloadIfEmpty || ( isdefined( self.enemy ) && distanceSquared( self.origin, self.enemy.origin ) < 256 * 256 );
|
||||
if ( reloadIfEmpty )
|
||||
{
|
||||
if ( !self NeedToReload( 0 ) )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !self NeedToReload( .5 ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( isdefined( self.grenade ) )
|
||||
return false;
|
||||
|
||||
if ( !self.faceMotion || self.stairsState != "none" )
|
||||
return false;
|
||||
|
||||
// if not allowed to shoot, not allowed to reload
|
||||
if ( isdefined( self.dontShootWhileMoving ) || isdefined( self.noRunReload ) )
|
||||
return false;
|
||||
|
||||
if ( self CanShootWhileRunning() && !self NeedToReload( 0 ) )
|
||||
return false;
|
||||
|
||||
if ( !isdefined( self.pathGoalPos ) || distanceSquared( self.origin, self.pathGoalPos ) < 256 * 256 )
|
||||
return false;
|
||||
|
||||
motionAngle = AngleClamp180( self getMotionAngle() );
|
||||
|
||||
// want to be running forward; otherwise we won't see the animation play!
|
||||
if ( abs( motionAngle ) > 25 )
|
||||
return false;
|
||||
|
||||
if ( !usingRifleLikeWeapon() )
|
||||
return false;
|
||||
|
||||
// need to restart the run cycle because the reload animation has to be played from start to finish!
|
||||
// the goal is to play it only when we're near the end of the run cycle.
|
||||
if ( !runLoopIsNearBeginning() )
|
||||
return false;
|
||||
|
||||
// call in a separate function so we can cleanup if we get an endon
|
||||
ReloadStandRunInternal();
|
||||
|
||||
// notify "abort_reload" in case the reload didn't finish, maybe due to "movemode" notify. works with handleDropClip() in shared.gsc
|
||||
self notify( "abort_reload" );
|
||||
|
||||
self orientmode( "face default" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ReloadStandRunInternal()
|
||||
{
|
||||
self endon( "movemode" );
|
||||
|
||||
self orientmode( "face motion" );
|
||||
|
||||
flagName = "reload_" + getUniqueFlagNameIndex();
|
||||
|
||||
self setFlaggedAnimKnobAllRestart( flagName, %run_lowready_reload, %body, 1, 0.25 );
|
||||
|
||||
self.update_move_front_bias = true;
|
||||
|
||||
self SetMoveNonForwardAnims( moveAnim( "move_b" ), moveAnim( "move_l" ), moveAnim( "move_r" ) );
|
||||
self thread SetCombatStandMoveAnimWeights( "run" );
|
||||
animscripts\shared::DoNoteTracks( flagName );
|
||||
|
||||
self.update_move_front_bias = undefined;
|
||||
}
|
||||
|
||||
runLoopIsNearBeginning()
|
||||
{
|
||||
// there are actually 3 loops (left foot, right foot) in one animation loop.
|
||||
|
||||
animfraction = self getAnimTime( %walk_and_run_loops );
|
||||
loopLength = getAnimLength( %run_lowready_F ) / 3.0;
|
||||
animfraction *= 3.0;
|
||||
if ( animfraction > 3 )
|
||||
animfraction -= 2.0;
|
||||
else if ( animfraction > 2 )
|
||||
animfraction -= 1.0;
|
||||
|
||||
if ( animfraction < .15 / loopLength )
|
||||
return true;
|
||||
if ( animfraction > 1 - .3 / loopLength )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SetMoveNonForwardAnims( backAnim, leftAnim, rightAnim, rate )
|
||||
{
|
||||
if ( !isdefined( rate ) )
|
||||
rate = 1;
|
||||
|
||||
self setAnimKnobLimited( backAnim, 1, 0.1, rate, true );
|
||||
self setAnimKnobLimited( leftAnim, 1, 0.1, rate, true );
|
||||
self setAnimKnobLimited( rightAnim, 1, 0.1, rate, true );
|
||||
}
|
||||
|
||||
SetCombatStandMoveAnimWeights( moveAnimType )
|
||||
{
|
||||
UpdateMoveAnimWeights( moveAnimType, %combatrun_forward, %combatrun_backward, %combatrun_left, %combatrun_right );
|
||||
}
|
||||
|
||||
UpdateMoveAnimWeights( moveAnimType, frontAnim, backAnim, leftAnim, rightAnim )
|
||||
{
|
||||
if ( isdefined( self.update_move_anim_type ) && self.update_move_anim_type == moveAnimType )
|
||||
return;
|
||||
|
||||
self notify( "stop_move_anim_update" );
|
||||
|
||||
self.update_move_anim_type = moveAnimType;
|
||||
self.wasFacingMotion = undefined;
|
||||
|
||||
self endon( "killanimscript" );
|
||||
self endon( "move_interrupt" );
|
||||
self endon( "stop_move_anim_update" );
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
UpdateRunWeightsOnce( frontAnim, backAnim, leftAnim, rightAnim );
|
||||
wait .05;
|
||||
waittillframeend;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateRunWeightsOnce( frontAnim, backAnim, leftAnim, rightAnim )
|
||||
{
|
||||
//assert( !isdefined( self.runNGun ) || isdefined( self.update_move_front_bias ) );
|
||||
|
||||
if ( self.faceMotion && !self shouldCQB() && !isdefined( self.update_move_front_bias ) )
|
||||
{
|
||||
// once you start to face motion, don't need to change weights
|
||||
if ( !isdefined( self.wasFacingMotion ) )
|
||||
{
|
||||
self.wasFacingMotion = 1;
|
||||
self setanim( frontAnim, 1, 0.2, 1, true );
|
||||
self setanim( backAnim, 0, 0.2, 1, true );
|
||||
self setanim( leftAnim, 0, 0.2, 1, true );
|
||||
self setanim( rightAnim, 0, 0.2, 1, true );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.wasFacingMotion = undefined;
|
||||
|
||||
// Play the appropriately weighted animations for the direction he's moving.
|
||||
animWeights = animscripts\utility::QuadrantAnimWeights( self getMotionAngle() );
|
||||
|
||||
if ( isdefined( self.update_move_front_bias ) )
|
||||
{
|
||||
animWeights[ "back" ] = 0.0;
|
||||
if ( animWeights[ "front" ] < .2 )
|
||||
animWeights[ "front" ] = .2;
|
||||
}
|
||||
|
||||
self setanim( frontAnim, animWeights[ "front" ], 0.2, 1, true );
|
||||
self setanim( backAnim, animWeights[ "back" ], 0.2, 1, true );
|
||||
self setanim( leftAnim, animWeights[ "left" ], 0.2, 1, true );
|
||||
self setanim( rightAnim, animWeights[ "right" ], 0.2, 1, true );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// change our weapon while running if we want to and can
|
||||
changeWeaponStandRun()
|
||||
{
|
||||
// right now this only handles shotguns, but it could do other things too
|
||||
wantShotgun = ( isdefined( self.wantShotgun ) && self.wantShotgun );
|
||||
usingShotgun = isShotgun( self.weapon );
|
||||
if ( wantShotgun == usingShotgun )
|
||||
return false;
|
||||
|
||||
if ( !isdefined( self.pathGoalPos ) || distanceSquared( self.origin, self.pathGoalPos ) < 256 * 256 )
|
||||
return false;
|
||||
|
||||
if ( usingSidearm() )
|
||||
return false;
|
||||
assert( self.weapon == self.primaryweapon || self.weapon == self.secondaryweapon );
|
||||
|
||||
if ( self.weapon == self.primaryweapon )
|
||||
{
|
||||
if ( !wantShotgun )
|
||||
return false;
|
||||
if ( isShotgun( self.secondaryweapon ) )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( self.weapon == self.secondaryweapon );
|
||||
|
||||
if ( wantShotgun )
|
||||
return false;
|
||||
if ( isShotgun( self.primaryweapon ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
// want to be running forward; otherwise we won't see the animation play!
|
||||
motionAngle = AngleClamp180( self getMotionAngle() );
|
||||
if ( abs( motionAngle ) > 25 )
|
||||
return false;
|
||||
|
||||
if ( !runLoopIsNearBeginning() )
|
||||
return false;
|
||||
|
||||
if ( wantShotgun )
|
||||
shotgunSwitchStandRunInternal( "shotgunPullout", %shotgun_CQBrun_pullout, "gun_2_chest", "none", self.secondaryweapon, "shotgun_pickup" );
|
||||
else
|
||||
shotgunSwitchStandRunInternal( "shotgunPutaway", %shotgun_CQBrun_putaway, "gun_2_back", "back", self.primaryweapon, "shotgun_pickup" );
|
||||
|
||||
self notify( "switchEnded" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
shotgunSwitchStandRunInternal( flagName, switchAnim, dropGunNotetrack, putGunOnTag, newGun, pickupNewGunNotetrack )
|
||||
{
|
||||
self endon( "movemode" );
|
||||
|
||||
self setFlaggedAnimKnobAllRestart( flagName, switchAnim, %body, 1, 0.25 );
|
||||
|
||||
self.update_move_front_bias = true;
|
||||
|
||||
self SetMoveNonForwardAnims( moveAnim( "move_b" ), moveAnim( "move_l" ), moveAnim( "move_r" ) );
|
||||
self thread SetCombatStandMoveAnimWeights( "run" );
|
||||
|
||||
self thread watchShotgunSwitchNotetracks( flagName, dropGunNotetrack, putGunOnTag, newGun, pickupNewGunNotetrack );
|
||||
|
||||
animscripts\shared::DoNoteTracksForTimeIntercept( getAnimLength( switchAnim ) - 0.25, flagName, ::interceptNotetracksForWeaponSwitch );
|
||||
|
||||
self.update_move_front_bias = undefined;
|
||||
}
|
||||
|
||||
interceptNotetracksForWeaponSwitch( notetrack )
|
||||
{
|
||||
if ( notetrack == "gun_2_chest" || notetrack == "gun_2_back" )
|
||||
return true;// "don't do the default behavior for this notetrack"
|
||||
}
|
||||
|
||||
watchShotgunSwitchNotetracks( flagName, dropGunNotetrack, putGunOnTag, newGun, pickupNewGunNotetrack )
|
||||
{
|
||||
self endon( "killanimscript" );
|
||||
self endon( "movemode" );
|
||||
self endon( "switchEnded" );
|
||||
|
||||
self waittillmatch( flagName, dropGunNotetrack );
|
||||
|
||||
animscripts\shared::placeWeaponOn( self.weapon, putGunOnTag );
|
||||
self thread shotgunSwitchFinish( newGun );
|
||||
|
||||
self waittillmatch( flagName, pickupNewGunNotetrack );
|
||||
self notify( "complete_weapon_switch" );
|
||||
}
|
||||
|
||||
shotgunSwitchFinish( newGun )
|
||||
{
|
||||
self endon( "death" );
|
||||
|
||||
self waittill_any( "killanimscript", "movemode", "switchEnded", "complete_weapon_switch" );
|
||||
|
||||
self.lastweapon = self.weapon;
|
||||
|
||||
animscripts\shared::placeWeaponOn( newGun, "right" );
|
||||
assert( self.weapon == newGun );// placeWeaponOn should have handled this
|
||||
|
||||
// reset ammo (assume fully loaded weapon)
|
||||
self.bulletsInClip = weaponClipSize( self.weapon );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
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";
|
||||
|
||||
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" );
|
||||
|
||||
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 ( ;; )
|
||||
{
|
||||
if ( turret.doFiring )
|
||||
{
|
||||
thread DoShoot( turret );
|
||||
|
||||
self waitTimeOrUntilTurretStateChange( randomFloatRange( turret_burst, turret_burst + turret_burst_range ), turret );
|
||||
turret notify( "turretstatechange" );
|
||||
|
||||
if ( turret.doFiring )
|
||||
{
|
||||
thread DoAim( turret );
|
||||
wait( randomFloatRange( turret_delay, turret_delay + turret_delay_range ) );
|
||||
}
|
||||
}
|
||||
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 );
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// 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[ "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, animMode, root )
|
||||
{
|
||||
self.codeScripted[ "notifyName" ] = notifyName;
|
||||
self.codeScripted[ "origin" ] = origin;
|
||||
self.codeScripted[ "angles" ] = angles;
|
||||
self.codeScripted[ "anim" ] = theAnim;
|
||||
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(),".");#/
|
||||
}
|
||||
*/
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,696 @@
|
||||
#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 ( usingRocketLauncher() )
|
||||
result = rpgShoot();
|
||||
else if ( usingSidearm() )
|
||||
result = pistolShoot();
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
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 ( 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!
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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" );
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
// "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.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" ] ]]();
|
||||
}
|
||||
@@ -0,0 +1,396 @@
|
||||
#include maps\_utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
main( turret )
|
||||
{
|
||||
self endon( "killanimscript" );// code
|
||||
|
||||
assert( isdefined( turret ) );
|
||||
|
||||
animscripts\utility::initialize( "technical" );
|
||||
|
||||
// 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 = "technical";
|
||||
|
||||
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" );
|
||||
|
||||
pauseUntilTime = getTime();
|
||||
turretState = "start";
|
||||
|
||||
self animscripts\shared::placeWeaponOn( self.weapon, "none" );
|
||||
turret show();
|
||||
|
||||
self.a.postScriptFunc = ::preplacedPostScriptFunc;
|
||||
|
||||
turret notify( "stop_burst_fire_unmanned" );
|
||||
|
||||
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 ( ;; )
|
||||
{
|
||||
if ( turret.doFiring )
|
||||
{
|
||||
thread DoShoot( turret );
|
||||
|
||||
self waitTimeOrUntilTurretStateChange( randomFloatRange( turret_burst, turret_burst + turret_burst_range ), turret );
|
||||
turret notify( "turretstatechange" );
|
||||
|
||||
if ( turret.doFiring )
|
||||
{
|
||||
thread DoAim( turret );
|
||||
wait( randomFloatRange( turret_delay, turret_delay + turret_delay_range ) );
|
||||
}
|
||||
}
|
||||
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 ) )
|
||||
{
|
||||
if ( self turret_should_shoot( turret, fovdot ) )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
turret_should_shoot( turret, fovdot )
|
||||
{
|
||||
ASSERT( IsDefined( self.enemy ) );
|
||||
|
||||
enemypos = self.enemy.origin;
|
||||
turretAimPos = turret getTagAngles( "tag_aim" );
|
||||
|
||||
if( within_fov( turret.origin, turretAimPos, enemypos, fovdot ) || distanceSquared( turret.origin, enemyPos ) < 200 * 200 )
|
||||
{
|
||||
if( !self turret_would_hit_friend( turret ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
turret_would_hit_friend( turret, friendlyTeam )
|
||||
{
|
||||
tag = "tag_flash";
|
||||
start = turret GetTagOrigin( tag );
|
||||
vec = AnglesToForward( turret GetTagAngles( tag ) );
|
||||
end = vector_multiply( vec, 10000 );
|
||||
|
||||
trace = BulletTrace( start, end, true, undefined );
|
||||
ent = trace[ "entity" ];
|
||||
|
||||
if( IsDefined( ent ) )
|
||||
{
|
||||
if( ( IsDefined( ent.team ) && ent.team == self.team ) || ( IsDefined( ent.script_team ) && ent.script_team == self.team ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
turretTimer( duration, turret )
|
||||
{
|
||||
if ( duration <= 0 )
|
||||
return;
|
||||
|
||||
self endon( "killanimscript" );// code
|
||||
turret endon( "turretstatechange" );// code
|
||||
|
||||
wait( duration );
|
||||
turret notify( "turretstatechange" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
|
||||
// ==================================
|
||||
|
||||
#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
|
||||
turret endon( "death" );// code or script
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
turret ShootTurret();
|
||||
wait( 0.15 );
|
||||
}
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
|
||||
//==================
|
||||
/* OLD STUFF
|
||||
//==================
|
||||
main( shoot, recover, aim, turret )
|
||||
{
|
||||
self endon( "killanimscript" );// code
|
||||
|
||||
animscripts\utility::initialize( "technical" );
|
||||
|
||||
self.a.special = "technical";
|
||||
|
||||
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" );
|
||||
|
||||
pauseUntilTime = getTime();
|
||||
turretState = "start";
|
||||
|
||||
self animscripts\shared::placeWeaponOn( self.weapon, "none" );
|
||||
self.a.postScriptFunc = ::preplacedPostScriptFunc;
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
duration = ( pauseUntilTime - getTime() ) * 0.001;
|
||||
if ( turret isFiringTurret() && ( duration <= 0 ) )
|
||||
{
|
||||
if ( turretState != "fire" )
|
||||
{
|
||||
turretState = "fire";
|
||||
thread [[ shoot ]]( turret );// non blocking
|
||||
}
|
||||
|
||||
duration = turret_burst + randomFloat( turret_burst_range );
|
||||
|
||||
thread turretTimer( duration, turret );
|
||||
|
||||
|
||||
|
||||
turret waittill( "turretstatechange" );// code or script
|
||||
|
||||
duration = turret_delay + randomFloat( turret_delay_range );
|
||||
|
||||
pauseUntilTime = getTime() + int( duration * 1000 );
|
||||
|
||||
if ( isDefined( recover ) )
|
||||
{
|
||||
turretState = "recover";
|
||||
[[ recover ]]( turret );// blocking
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( turretState != "aim" )
|
||||
{
|
||||
turretState = "aim";
|
||||
thread [[ aim ]]( turret );// non blocking
|
||||
}
|
||||
|
||||
thread turretTimer( duration, turret );
|
||||
|
||||
turret waittill( "turretstatechange" );// code or script
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
turretTimer( duration, turret )
|
||||
{
|
||||
if ( duration <= 0 )
|
||||
return;
|
||||
|
||||
self endon( "killanimscript" );// code
|
||||
turret endon( "turretstatechange" );// code
|
||||
|
||||
wait( duration );
|
||||
turret notify( "turretstatechange" );
|
||||
}
|
||||
|
||||
|
||||
preplacedPostScriptFunc( animscript )
|
||||
{
|
||||
self animscripts\shared::placeWeaponOn( self.weapon, "right" );
|
||||
}
|
||||
*/
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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" );
|
||||
}
|
||||
@@ -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" );
|
||||
}
|
||||
@@ -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" );
|
||||
}
|
||||
@@ -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" );
|
||||
}
|
||||
@@ -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" );
|
||||
}
|
||||
@@ -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" );
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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");#/
|
||||
}
|
||||
@@ -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");#/
|
||||
}
|
||||
|
||||
@@ -0,0 +1,346 @@
|
||||
#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" );
|
||||
|
||||
// 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;
|
||||
self setFlaggedAnimKnoballRestart( "traverseAnim", traverseAnim, %body, 1, .2, 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";
|
||||
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.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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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");#/
|
||||
}
|
||||
@@ -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 = self 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");#/
|
||||
}
|
||||
|
||||
@@ -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" );
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// 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()
|
||||
{
|
||||
// do not do code prone in this script
|
||||
|
||||
self endon( "killanimscript" );
|
||||
|
||||
startnode = self getnegotiationstartnode();
|
||||
assert( isdefined( startnode ) );
|
||||
self OrientMode( "face angle", startnode.angles[ 1 ] );
|
||||
|
||||
realHeight = startnode.traverse_height - startnode.origin[ 2 ];
|
||||
destination = ( realHeight );
|
||||
|
||||
reps = 6;
|
||||
offset = ( 0, 0, destination / reps );
|
||||
self traverseMode( "noclip" );// So he doesn't get stuck if the wall is a little too high
|
||||
for ( i = 0;i < reps;i++ )
|
||||
{
|
||||
self teleport( self.origin + offset );
|
||||
wait( 0.05 );
|
||||
}
|
||||
self traverseMode( "gravity" );
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#include animscripts\utility;
|
||||
#include animscripts\traverse\shared;
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
main()
|
||||
{
|
||||
if ( self.type == "dog" )
|
||||
dog_jump_up( 52.0, 5 );
|
||||
else
|
||||
low_wall_human();
|
||||
}
|
||||
|
||||
low_wall_human()
|
||||
{
|
||||
traverseData = [];
|
||||
traverseData[ "traverseAnim" ] = %traverse_stepup_52;
|
||||
traverseData[ "traverseHeight" ] = 52.0;
|
||||
|
||||
DoTraverse( traverseData );
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include animscripts\traverse\shared;
|
||||
#using_animtree( "generic_human" );
|
||||
main()
|
||||
{
|
||||
self advancedTraverse( %trench_jump_out, 47.8 );
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#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 ] );
|
||||
|
||||
self setFlaggedAnimKnoballRestart( "stepanim", %gully_trenchjump, %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 );
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
#include animscripts\Utility;
|
||||
#include animscripts\traverse\shared;
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
main()
|
||||
{
|
||||
self.traverseDeath = 1;
|
||||
self advancedTraverse2( %traverse40, 90 );
|
||||
}
|
||||
|
||||
|
||||
advancedTraverse2( 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 );
|
||||
|
||||
self setFlaggedAnimKnoballRestart( "traverse", traverseAnim, %body, 1, 0.15, 1 );
|
||||
timer = gettime();
|
||||
self thread animscripts\shared::DoNoteTracksForever( "traverse", "no clear", ::handle_death );
|
||||
if ( !animhasnotetrack( traverseAnim, "gravity on" ) )
|
||||
{
|
||||
timer = 1.23;
|
||||
timerOffset = 0.2;
|
||||
// wait (timer - timerOffset);
|
||||
wait 5.0;
|
||||
self traverseMode( "gravity" );
|
||||
wait( timerOffset );
|
||||
}
|
||||
else
|
||||
{
|
||||
self waittillmatch( "traverse", "gravity on" );
|
||||
self traverseMode( "gravity" );
|
||||
if ( !animhasnotetrack( traverseAnim, "blend" ) )
|
||||
wait( 0.2 );
|
||||
else
|
||||
self waittillmatch( "traverse", "blend" );
|
||||
}
|
||||
}
|
||||
|
||||
handle_death( note )
|
||||
{
|
||||
println( note );
|
||||
|
||||
if ( note != "traverse_death" )
|
||||
return;
|
||||
|
||||
self endon( "killanimscript" );
|
||||
|
||||
if ( self.health == 1 )
|
||||
{
|
||||
self.a.nodeath = true;
|
||||
if ( self.traverseDeath > 1 )
|
||||
self setFlaggedAnimKnobAll( "deathanim", %traverse90_end_death, %body, 1, .2, 1 );
|
||||
else
|
||||
self setFlaggedAnimKnobAll( "deathanim", %traverse90_start_death, %body, 1, .2, 1 );
|
||||
|
||||
self animscripts\face::SayGenericDialogue( "death" );
|
||||
}
|
||||
self.traverseDeath++ ;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Wall_dive.gsc
|
||||
// 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" );// JBW Was getting caught on wall in test / obstacle
|
||||
|
||||
// orient to the Negotiation start node
|
||||
startnode = self getnegotiationstartnode();
|
||||
assert( isdefined( startnode ) );
|
||||
self OrientMode( "face angle", startnode.angles[ 1 ] );
|
||||
|
||||
self setFlaggedAnimKnoballRestart( "diveanim", %jump_over_low_wall, %body, 1, .1, 1 );
|
||||
self playsound( "dive_wall" );
|
||||
self waittillmatch( "diveanim", "gravity on" );
|
||||
self traverseMode( "gravity" );
|
||||
self animscripts\shared::DoNoteTracks( "diveanim" );
|
||||
self.a.movement = "run";
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// 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
|
||||
|
||||
#include animscripts\traverse\shared;
|
||||
|
||||
main()
|
||||
{
|
||||
if ( self.type == "dog" )
|
||||
dog_wall_and_window_hop( "wallhop", 40 );
|
||||
else
|
||||
wall_hop_human();
|
||||
}
|
||||
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
wall_hop_human()
|
||||
{
|
||||
if ( randomint( 100 ) < 30 )
|
||||
self advancedTraverse( %traverse_wallhop_3, 39.875 );
|
||||
else
|
||||
self advancedTraverse( %traverse_wallhop, 39.875 );
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include animscripts\utility;
|
||||
#include animscripts\traverse\shared;
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
main()
|
||||
{
|
||||
if ( self.type == "dog" )
|
||||
dog_wall_and_window_hop( "window_40", 40 );
|
||||
else
|
||||
low_wall_human();
|
||||
}
|
||||
|
||||
low_wall_human()
|
||||
{
|
||||
traverseData = [];
|
||||
traverseData[ "traverseAnim" ] = %traverse40;
|
||||
traverseData[ "traverseToCoverAnim" ] = %traverse40_2_cover;
|
||||
traverseData[ "coverType" ] = "Cover Crouch";
|
||||
traverseData[ "traverseHeight" ] = 40.0;
|
||||
traverseData[ "interruptDeathAnim" ][ 0 ] = array( %traverse40_death_start, %traverse40_death_start_2 );
|
||||
traverseData[ "interruptDeathAnim" ][ 1 ] = array( %traverse40_death_end, %traverse40_death_end_2 );
|
||||
|
||||
DoTraverse( traverseData );
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#include animscripts\Utility;
|
||||
#include animscripts\traverse\shared;
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
main()
|
||||
{
|
||||
self.traverseDeath = 1;
|
||||
self advancedTraverse2( %traverse90, 96 );
|
||||
}
|
||||
|
||||
|
||||
advancedTraverse2( 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);
|
||||
|
||||
self setFlaggedAnimKnoballRestart( "traverse", traverseAnim, %body, 1, 0.15, 1 );
|
||||
timer = gettime();
|
||||
self thread animscripts\shared::DoNoteTracksForever( "traverse", "no clear", ::handle_death );
|
||||
if ( !animhasnotetrack( traverseAnim, "gravity on" ) )
|
||||
{
|
||||
timer = 1.23;
|
||||
timerOffset = 0.2;
|
||||
// wait (timer - timerOffset);
|
||||
wait 5.0;
|
||||
self traverseMode( "gravity" );
|
||||
wait( timerOffset );
|
||||
}
|
||||
else
|
||||
{
|
||||
self waittillmatch( "traverse", "gravity on" );
|
||||
self traverseMode( "gravity" );
|
||||
if ( !animhasnotetrack( traverseAnim, "blend" ) )
|
||||
wait( 0.2 );
|
||||
else
|
||||
self waittillmatch( "traverse", "blend" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
handle_death( note )
|
||||
{
|
||||
println( note );
|
||||
|
||||
if ( note != "traverse_death" )
|
||||
return;
|
||||
|
||||
self endon( "killanimscript" );
|
||||
|
||||
if ( self.health == 1 )
|
||||
{
|
||||
self.a.nodeath = true;
|
||||
if ( self.traverseDeath > 1 )
|
||||
self setFlaggedAnimKnobAll( "deathanim", %traverse90_end_death, %body, 1, .2, 1 );
|
||||
else
|
||||
self setFlaggedAnimKnobAll( "deathanim", %traverse90_start_death, %body, 1, .2, 1 );
|
||||
|
||||
self animscripts\face::SayGenericDialogue( "death" );
|
||||
}
|
||||
self.traverseDeath++ ;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Window.gsc
|
||||
// Makes the character climb through a window with a 36 unit high lower edge.
|
||||
// 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" );// JBW - hitting window
|
||||
|
||||
// orient to the Negotiation start node
|
||||
startnode = self getnegotiationstartnode();
|
||||
assert( isdefined( startnode ) );
|
||||
self OrientMode( "face angle", startnode.angles[ 1 ] );
|
||||
|
||||
self setFlaggedAnimKnoballRestart( "diveanim", %windowclimb, %body, 1, .1, 1 );
|
||||
self waittillmatch( "diveanim", "gravity on" );
|
||||
self traverseMode( "gravity" );
|
||||
self animscripts\shared::DoNoteTracks( "diveanim" );
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#include animscripts\traverse\shared;
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
main()
|
||||
{
|
||||
if ( self.type == "dog" )
|
||||
dog_wall_and_window_hop( "wallhop", 40 );
|
||||
else
|
||||
self advancedWindowTraverse( %windowclimb, 35 );
|
||||
}
|
||||
|
||||
advancedWindowTraverse( 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 setFlaggedAnimKnoballRestart( "traverse", traverseAnim, %body, 1, 0.15, 1 );
|
||||
|
||||
// self waittillmatch("traverse", "gravity on");
|
||||
|
||||
// keeps the actor from sinking in to the ground or from levitating to some extent.
|
||||
wait 0.7;
|
||||
self thread teleportThread( realHeight - normalHeight );
|
||||
wait 0.9;
|
||||
// wait 1.6;
|
||||
|
||||
self traverseMode( "gravity" );
|
||||
|
||||
self animscripts\shared::DoNoteTracks( "traverse" );
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include animscripts\utility;
|
||||
#include animscripts\traverse\shared;
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
main()
|
||||
{
|
||||
if ( self.type == "dog" )
|
||||
{
|
||||
dog_wall_and_window_hop( "window_40", 40 );
|
||||
}
|
||||
else
|
||||
{
|
||||
low_wall_human();
|
||||
}
|
||||
}
|
||||
|
||||
low_wall_human()
|
||||
{
|
||||
traverseData = [];
|
||||
traverseData[ "traverseAnim" ] = %traverse_window_M_2_dive;
|
||||
traverseData[ "traverseStopsAtEnd" ] = true;
|
||||
traverseData[ "traverseHeight" ] = 36.0;
|
||||
|
||||
DoTraverse( traverseData );
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
#include animscripts\traverse\shared;
|
||||
#include maps\_utility;
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
main()
|
||||
{
|
||||
|
||||
traverseAnim = %windowclimb_fall;
|
||||
landAnim = %windowclimb_land;
|
||||
normalHeight = 35;
|
||||
|
||||
// do not do code prone in this script
|
||||
self.desired_anim_pose = "crouch";
|
||||
animscripts\utility::UpdateAnimPose();
|
||||
|
||||
self endon( "killanimscript" );
|
||||
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 setFlaggedAnimKnoballRestart( "traverse", traverseAnim, %body, 1, 0.15, 1 );
|
||||
thread animscripts\shared::DoNoteTracksForever( "traverse", "stop_traverse_notetracks" );
|
||||
|
||||
|
||||
// keeps the actor from sinking in to the ground or from levitating to some extent.
|
||||
wait 1.5;
|
||||
angles = ( 0, startnode.angles[ 1 ], 0 );
|
||||
forward = anglestoforward( angles );
|
||||
forward = vector_multiply( forward, 85 );
|
||||
trace = bullettrace( startnode.origin + forward, startnode.origin + forward + ( 0, 0, -500 ), false, undefined );
|
||||
// thread showLine(startnode.origin + forward, trace["position"]);
|
||||
endheight = trace[ "position" ][ 2 ];
|
||||
|
||||
finaldif = startnode.origin[ 2 ] - endheight;
|
||||
heightChange = 0;
|
||||
for ( i = 0;i < level.window_down_height.size;i++ )
|
||||
{
|
||||
if ( finaldif < level.window_down_height[ i ] )
|
||||
continue;
|
||||
heightChange = finaldif - level.window_down_height[ i ];
|
||||
}
|
||||
assertEx( heightChange > 0, "window_jump at " + startnode.origin + " is too high off the ground" );
|
||||
// heightChange -= 0;
|
||||
self thread teleportThread( heightChange * - 1 );
|
||||
|
||||
// thread printerdebugger(heightchange, trace["position"]);
|
||||
|
||||
oldheight = self.origin[ 2 ];
|
||||
change = 0;
|
||||
level.traverseFall = [];
|
||||
for ( ;; )
|
||||
{
|
||||
/*
|
||||
/#
|
||||
thread printer(self.origin);
|
||||
#/
|
||||
*/
|
||||
change = oldheight - self.origin[ 2 ];
|
||||
if ( self.origin[ 2 ] - change < endheight )// predict when he's about to hit the ground
|
||||
{
|
||||
break;
|
||||
}
|
||||
oldheight = self.origin[ 2 ];
|
||||
wait( 0.05 );
|
||||
}
|
||||
if ( isdefined( self.groundtype ) )
|
||||
self playsound( "Land_" + self.groundtype );
|
||||
|
||||
self notify( "stop_traverse_notetracks" );
|
||||
self setFlaggedAnimKnoballRestart( "traverse", landAnim, %body, 1, 0.15, 1 );
|
||||
// self waittillmatch("traverse", "gravity on");
|
||||
self traverseMode( "gravity" );
|
||||
self animscripts\shared::DoNoteTracks( "traverse" );
|
||||
// wait 0.9;
|
||||
}
|
||||
|
||||
printer( org )
|
||||
{
|
||||
level notify( "print_this_" + org );
|
||||
level endon( "print_this_" + org );
|
||||
for ( ;; )
|
||||
{
|
||||
print3d( org, ".", ( 1, 1, 1 ), 5 );
|
||||
wait( 0.05 );
|
||||
}
|
||||
}
|
||||
|
||||
showline( start, end )
|
||||
{
|
||||
for ( ;; )
|
||||
{
|
||||
line( start, end + ( -1, -1, -1 ), ( 1, 0, 0 ) );
|
||||
wait( 0.05 );
|
||||
}
|
||||
}
|
||||
|
||||
printerdebugger( msg, org )
|
||||
{
|
||||
level notify( "prrint_this_" + org );
|
||||
level endon( "prrint_this_" + org );
|
||||
for ( ;; )
|
||||
{
|
||||
print3d( org, msg, ( 1, 1, 1 ), 5 );
|
||||
wait( 0.05 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/#
|
||||
dif = startNode.origin[2] - self.origin[2];
|
||||
included = false;
|
||||
for (i=0;i<level.traverseFall.size;i++)
|
||||
{
|
||||
if (level.traverseFall[i] != dif)
|
||||
continue;
|
||||
included = true;
|
||||
break;
|
||||
}
|
||||
if (!includeD)
|
||||
level.traverseFall[level.traverseFall.size] = dif;
|
||||
if (getdebugdvar("debug_traversefall") != "")
|
||||
{
|
||||
setdvar("debug_traversefall", "");
|
||||
for (i=0;i<level.traverseFall.size;i++)
|
||||
println (" level.window_down_height[", i, "] = ", level.traverseFall[i], ";");
|
||||
}
|
||||
#/
|
||||
*/
|
||||
@@ -0,0 +1,26 @@
|
||||
#include animscripts\traverse\shared;
|
||||
#include animscripts\utility;
|
||||
#include maps\_utility;
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
|
||||
main()
|
||||
{
|
||||
if ( self.type == "dog" )
|
||||
dog_wall_and_window_hop( "window_40", 40 );
|
||||
else
|
||||
jump_through_window_human();
|
||||
}
|
||||
|
||||
jump_through_window_human()
|
||||
{
|
||||
traverseData = [];
|
||||
traverseData[ "traverseAnim" ] = %traverse_window_M_2_run;
|
||||
traverseData[ "traverseToCoverAnim" ] = %traverse_window_M_2_stop;
|
||||
traverseData[ "coverType" ] = "Cover Crouch";
|
||||
traverseData[ "traverseHeight" ] = 36.0;
|
||||
traverseData[ "interruptDeathAnim" ][ 0 ] = array( %traverse_window_death_start );
|
||||
traverseData[ "interruptDeathAnim" ][ 1 ] = array( %traverse_window_death_end );
|
||||
|
||||
DoTraverse( traverseData );
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include animscripts\traverse\shared;
|
||||
#include animscripts\utility;
|
||||
#include maps\_utility;
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
|
||||
main()
|
||||
{
|
||||
if ( self.type == "dog" )
|
||||
dog_wall_and_window_hop( "window_40", 40 );
|
||||
else
|
||||
jump_through_window_human();
|
||||
}
|
||||
|
||||
jump_through_window_human()
|
||||
{
|
||||
traverseData = [];
|
||||
traverseData[ "traverseAnim" ] = %traverse_window_quick;
|
||||
traverseData[ "coverType" ] = "Cover Crouch";
|
||||
traverseData[ "traverseHeight" ] = 36.0;
|
||||
traverseData[ "interruptDeathAnim" ][ 0 ] = array( %traverse_window_death_start );
|
||||
traverseData[ "interruptDeathAnim" ][ 1 ] = array( %traverse_window_death_end );
|
||||
|
||||
DoTraverse( traverseData );
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,122 @@
|
||||
#include animscripts\SetPoseMovement;
|
||||
#include animscripts\Utility;
|
||||
#include common_scripts\utility;
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
MoveWalk()
|
||||
{
|
||||
// Decide what pose to use
|
||||
preferredPose = undefined;
|
||||
if ( isdefined( self.pathGoalPos ) && distanceSquared( self.origin, self.pathGoalPos ) > 64 * 64 )
|
||||
preferredPose = "stand";
|
||||
|
||||
desiredPose = [[ self.choosePoseFunc ]]( preferredPose );
|
||||
|
||||
switch( desiredPose )
|
||||
{
|
||||
case "stand":
|
||||
if ( BeginStandWalk() )
|
||||
return;
|
||||
|
||||
if ( isdefined( self.walk_overrideanim ) )
|
||||
{
|
||||
animscripts\move::MoveStandMoveOverride( self.walk_overrideanim, self.walk_override_weights );
|
||||
return;
|
||||
}
|
||||
|
||||
DoWalkAnim( GetWalkAnim( "straight" ) );
|
||||
break;
|
||||
|
||||
case "crouch":
|
||||
if ( BeginCrouchWalk() )
|
||||
return;
|
||||
|
||||
DoWalkAnim( GetWalkAnim( "crouch" ) );
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( desiredPose == "prone" );
|
||||
if ( BeginProneWalk() )
|
||||
return;
|
||||
|
||||
self.a.movement = "walk";
|
||||
DoWalkAnim( GetWalkAnim( "prone" ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoWalkAnimOverride( walkAnim )
|
||||
{
|
||||
self endon( "movemode" );
|
||||
self clearanim( %combatrun, 0.6 );
|
||||
self setanimknoball( %combatrun, %body, 1, 0.5, self.moveplaybackrate );
|
||||
|
||||
if ( isarray( self.walk_overrideanim ) )
|
||||
{
|
||||
if ( isdefined( self.walk_override_weights ) )
|
||||
moveAnim = choose_from_weighted_array( self.walk_overrideanim, self.walk_override_weights );
|
||||
else
|
||||
moveAnim = self.walk_overrideanim[ randomint( self.walk_overrideanim.size ) ];
|
||||
}
|
||||
else
|
||||
{
|
||||
moveAnim = self.walk_overrideanim;
|
||||
}
|
||||
|
||||
self setflaggedanimknob( "moveanim", moveAnim, 1, 0.2 );
|
||||
animscripts\shared::DoNoteTracks( "moveanim" );
|
||||
}
|
||||
|
||||
GetWalkAnim( desiredAnim )
|
||||
{
|
||||
if ( self.stairsState == "up" )
|
||||
return moveAnim( "stairs_up" );
|
||||
else if ( self.stairsState == "down" )
|
||||
return moveAnim( "stairs_down" );
|
||||
|
||||
walkAnim = moveAnim( desiredAnim );
|
||||
|
||||
if ( isarray( walkAnim ) )
|
||||
walkAnim = walkAnim[ randomint( walkAnim.size ) ];
|
||||
|
||||
return walkAnim;
|
||||
}
|
||||
|
||||
DoWalkAnim( walkAnim )
|
||||
{
|
||||
self endon( "movemode" );
|
||||
|
||||
rate = self.moveplaybackrate;
|
||||
|
||||
if ( self.stairsState != "none" )
|
||||
rate *= 0.6;
|
||||
|
||||
if ( self.a.pose == "stand" )
|
||||
{
|
||||
if ( isdefined( self.enemy ) )
|
||||
{
|
||||
self thread animscripts\cqb::CQBTracking();
|
||||
// (we don't use %body because that would reset the aiming knobs)
|
||||
self setFlaggedAnimKnobAll( "walkanim", animscripts\cqb::DetermineCQBAnim(), %walk_and_run_loops, 1, 1, rate, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
self setFlaggedAnimKnobAll( "walkanim", walkAnim, %body, 1, 1, rate, true );
|
||||
}
|
||||
|
||||
self animscripts\run::SetMoveNonForwardAnims( moveAnim( "move_b" ), moveAnim( "move_l" ), moveAnim( "move_r" ) );
|
||||
self thread animscripts\run::SetCombatStandMoveAnimWeights( "walk" );
|
||||
}
|
||||
else
|
||||
{
|
||||
self setFlaggedAnimKnobAll( "walkanim", walkAnim, %body, 1, 1, rate, true );
|
||||
|
||||
self animscripts\run::SetMoveNonForwardAnims( moveAnim( "move_b" ), moveAnim( "move_l" ), moveAnim( "move_r" ) );
|
||||
self thread animscripts\run::SetCombatStandMoveAnimWeights( "walk" );
|
||||
}
|
||||
|
||||
self animscripts\shared::DoNoteTracksForTime( 0.2, "walkanim" );
|
||||
|
||||
self thread animscripts\run::stopShootWhileMovingThreads();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
// Weapon configuration for anim scripts.
|
||||
// Supplies information for all AI weapons.
|
||||
#using_animtree( "generic_human" );
|
||||
|
||||
|
||||
usingAutomaticWeapon()
|
||||
{
|
||||
return( WeaponIsAuto( self.weapon ) || WeaponBurstCount( self.weapon ) > 0 );
|
||||
}
|
||||
|
||||
usingSemiAutoWeapon()
|
||||
{
|
||||
return( weaponIsSemiAuto( self.weapon ) );
|
||||
}
|
||||
|
||||
autoShootAnimRate()
|
||||
{
|
||||
if ( usingAutomaticWeapon() )
|
||||
{
|
||||
// The auto fire animation fires 10 shots a second, so we divide the weapon's fire rate by
|
||||
// 10 to get the correct anim playback rate.
|
||||
// return weaponFireTime( self.weapon ) * 10;
|
||||
return 0.1 / weaponFireTime( self.weapon );
|
||||
}
|
||||
else
|
||||
{
|
||||
// println ("weaponList::standAimShootAnims: No auto fire rate for "+self.weapon);
|
||||
return 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
burstShootAnimRate()
|
||||
{
|
||||
if ( usingAutomaticWeapon() )
|
||||
{
|
||||
return 0.1 / weaponFireTime( self.weapon );
|
||||
}
|
||||
else
|
||||
{
|
||||
// println ("weaponList::standAimShootAnims: No auto fire rate for "+self.weapon);
|
||||
return 0.2; // Equates to 2 shots a second, decent for a non - auto weapon.
|
||||
}
|
||||
}
|
||||
|
||||
waitAfterShot()
|
||||
{
|
||||
return 0.25;
|
||||
}
|
||||
|
||||
shootAnimTime( semiAutoFire )
|
||||
{
|
||||
if ( !usingAutomaticWeapon() || ( isdefined( semiAutofire ) && ( semiAutofire == true ) ) )
|
||||
{
|
||||
// We randomize the result a little from the real time, just to make things more
|
||||
// interesting. In reality, the 20Hz server is going to make this much less variable.
|
||||
rand = 0.5 + randomfloat( 1 );// 0.8 + 0.4
|
||||
return weaponFireTime( self.weapon ) * rand;
|
||||
}
|
||||
else
|
||||
{
|
||||
return weaponFireTime( self.weapon );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RefillClip()
|
||||
{
|
||||
assertEX( isDefined( self.weapon ), "self.weapon is not defined for " + self.model );
|
||||
|
||||
if ( self.weapon == "none" )
|
||||
{
|
||||
self.bulletsInClip = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( weaponClass( self.weapon ) == "rocketlauncher" )
|
||||
{
|
||||
if ( !self.a.rocketVisible )
|
||||
self thread animscripts\combat_utility::showRocketWhenReloadIsDone();
|
||||
/*
|
||||
// TODO: proper rocket ammo tracking
|
||||
if ( self.a.rockets < 1 )
|
||||
self animscripts\shared::placeWeaponOn( self.secondaryweapon, "right" );
|
||||
*/
|
||||
}
|
||||
|
||||
if ( !isDefined( self.bulletsInClip ) )
|
||||
{
|
||||
self.bulletsInClip = weaponClipSize( self.weapon );
|
||||
}
|
||||
else
|
||||
{
|
||||
self.bulletsInClip = weaponClipSize( self.weapon );
|
||||
}
|
||||
|
||||
assertEX( isDefined( self.bulletsInClip ), "RefillClip failed" );
|
||||
|
||||
if ( self.bulletsInClip <= 0 )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
add_weapon( name, type, time, clipsize, anims )
|
||||
{
|
||||
assert( isdefined( name ) );
|
||||
assert( isdefined( type ) );
|
||||
if ( !isdefined( time ) )
|
||||
time = 3.0;
|
||||
if ( !isdefined( clipsize ) )
|
||||
time = 1;
|
||||
if ( !isdefined( anims ) )
|
||||
anims = "rifle";
|
||||
|
||||
name = tolower( name );
|
||||
anim.AIWeapon[ name ][ "type" ] = type;
|
||||
anim.AIWeapon[ name ][ "time" ] = time;
|
||||
anim.AIWeapon[ name ][ "clipsize" ] = clipsize;
|
||||
anim.AIWeapon[ name ][ "anims" ] = anims;
|
||||
}
|
||||
|
||||
addTurret( turret )
|
||||
{
|
||||
anim.AIWeapon[ tolower( turret ) ][ "type" ] = "turret";
|
||||
}
|
||||
Reference in new issue
Block a user