1925 lines
49 KiB
Text
1925 lines
49 KiB
Text
#include maps\_utility;
|
|
|
|
// TREYARCH: Added to make the math stuff work again since ABS and whatnot was changed / removed.
|
|
#include animscripts\Utility;
|
|
#include animscripts\SetPoseMovement;
|
|
#include animscripts\Combat_utility;
|
|
#include animscripts\shared;
|
|
#include common_scripts\Utility;
|
|
#include maps\_spawner;
|
|
|
|
#using_animtree( "fakeshooters" );
|
|
init()
|
|
{
|
|
/#
|
|
// CODER_MOD: Bryce( 05/08/08 ): Useful output for debugging replay system
|
|
if( getdebugdvar( "replay_debug" ) == "1" )
|
|
{
|
|
println( "File: _drones.gsc. Function: init()\n" );
|
|
}
|
|
|
|
// MikeD: Do not start the drones if compiling reflections
|
|
if( GetDvar( "r_reflectionProbeGenerate" ) == "1" )
|
|
{
|
|
return;
|
|
}
|
|
#/
|
|
|
|
// SCRIPTER_MOD
|
|
// JesseS( 3/16/2007 ): took out weaponlist call since it disappeared...
|
|
//animscripts\weaponList::initWeaponList();
|
|
setAnimArray();
|
|
level.drone_impact = loadfx( "impacts/flesh_hit" );
|
|
level.drone_muzzleflash = loadfx( "weapon/muzzleflashes/standardflashworld" );
|
|
|
|
if( !isdefined( level.traceHeight ) )
|
|
{
|
|
level.traceHeight = 400;
|
|
}
|
|
|
|
if( !isdefined( level.droneStepHeight ) )
|
|
{
|
|
level.droneStepHeight = 100;
|
|
}
|
|
|
|
if( !isdefined( level.max_drones ) )
|
|
{
|
|
level.max_drones = [];
|
|
}
|
|
|
|
if( !isdefined( level.max_drones["axis"] ) )
|
|
{
|
|
level.max_drones["axis"] = 32;
|
|
}
|
|
if ( level.max_drones["axis"] > 32 )
|
|
{
|
|
level.max_drones["axis"] = 32;
|
|
}
|
|
if( !isdefined( level.max_drones["allies"] ) )
|
|
{
|
|
level.max_drones["allies"] = 32;
|
|
}
|
|
if ( level.max_drones["allies"] > 32 )
|
|
{
|
|
level.max_drones["allies"] = 32;
|
|
}
|
|
if ( isSplitScreen() )
|
|
{
|
|
level.max_drones["axis"] = 8;
|
|
level.max_drones["allies"] = 8;
|
|
}
|
|
|
|
if( !isdefined( level.drones ) )
|
|
{
|
|
level.drones = [];
|
|
}
|
|
|
|
if( !isdefined( level.drones["axis"] ) )
|
|
{
|
|
level.drones["axis"] = struct_arrayspawn();
|
|
}
|
|
|
|
if( !isdefined( level.drones["allies"] ) )
|
|
{
|
|
level.drones["allies"] = struct_arrayspawn();
|
|
}
|
|
|
|
init_struct_targeted_origins();
|
|
|
|
array_thread( getentarray( "drone_axis", "targetname" ), ::drone_triggers_think );
|
|
array_thread( getentarray( "drone_allies", "targetname" ), ::drone_triggers_think );
|
|
|
|
// CODER_MOD: Bryce( 05/08/08 ): Useful output for debugging replay system
|
|
/#
|
|
if( getdebugdvar( "replay_debug" ) == "1" )
|
|
{
|
|
println( "File: _drones.gsc. Function: init() - COMPLETE\n" );
|
|
}
|
|
#/
|
|
}
|
|
|
|
build_struct_targeted_origins()
|
|
{
|
|
if( !isdefined( self.target ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self.targeted = level.struct_targetname[self.target];
|
|
|
|
if( !isdefined( self.targeted ) )
|
|
{
|
|
self.targeted = [];
|
|
}
|
|
}
|
|
|
|
init_struct_targeted_origins()
|
|
{
|
|
level.struct_targetname = [];
|
|
|
|
count = level.struct.size;
|
|
|
|
for( i = 0; i < count; i++ )
|
|
{
|
|
struct = level.struct[i];
|
|
if( !isdefined( struct.targetname ) )
|
|
{
|
|
continue;
|
|
}
|
|
struct_targetname = level.struct_targetname[struct.targetname];
|
|
if( !isdefined( struct_targetname ) )
|
|
{
|
|
targetname_count = 0;
|
|
}
|
|
else
|
|
{
|
|
targetname_count = struct_targetname.size;
|
|
}
|
|
level.struct_targetname[struct.targetname][targetname_count] = struct;
|
|
}
|
|
|
|
for( i = 0; i < count; i++ )
|
|
{
|
|
struct = level.struct[i];
|
|
if( !isdefined( struct.target ) )
|
|
{
|
|
continue;
|
|
}
|
|
struct.targeted = level.struct_targetname[struct.target];
|
|
}
|
|
}
|
|
|
|
drone_triggers_think()
|
|
{
|
|
self endon( "death" );
|
|
|
|
if( self.targetname == "drone_allies" )
|
|
{
|
|
team = "allies";
|
|
}
|
|
else
|
|
{
|
|
team = "axis";
|
|
}
|
|
|
|
self build_struct_targeted_origins();
|
|
|
|
qFakeDeath = true;
|
|
if( ( isdefined( self.script_allowdeath ) ) &&( self.script_allowdeath == 0 ) )
|
|
{
|
|
qFakeDeath = false;
|
|
}
|
|
|
|
qSightTrace = false;
|
|
if( ( isdefined( self.script_trace ) ) &&( self.script_trace > 0 ) )
|
|
{
|
|
qSightTrace = true;
|
|
}
|
|
|
|
//make sure it has data
|
|
assert( isdefined( self.targeted ) );
|
|
assert( isdefined( self.targeted[0] ) );
|
|
|
|
// MikeD( 06/26/06 ): Added the ability to kill this thread, if script_ender is defined.
|
|
if( IsDefined( self.script_ender ) )
|
|
{
|
|
level endon( self.script_ender );
|
|
}
|
|
|
|
self waittill( "trigger" );
|
|
|
|
if( !isdefined( self.script_repeat ) )
|
|
{
|
|
repeat_times = 999999;
|
|
}
|
|
else
|
|
{
|
|
repeat_times = self.script_repeat;
|
|
}
|
|
|
|
if( ( ( isdefined( self.script_noteworthy ) ) &&( self.script_noteworthy == "looping" ) ) ||( ( isdefined( self.script_looping ) ) &&( self.script_looping > 0 ) ) )
|
|
{
|
|
//looping
|
|
assert( isdefined( self.script_delay ) ||( isdefined( self.script_delay_min ) && isdefined( self.script_delay_max ) ) );
|
|
self endon( "stop_drone_loop" );
|
|
for( i = 0; i < repeat_times; i++ )
|
|
{
|
|
// SCRIPTER_MOD
|
|
// JesseS( 3/16/2007 ): kill old drone spawn wais, rather then building them up
|
|
level notify( "new drone spawn wave" );
|
|
|
|
//how many drones should spawn?
|
|
spawnSize = undefined;
|
|
if( isdefined( self.script_drones_min ) )
|
|
{
|
|
max = self.targeted.size;
|
|
if( isdefined( self.script_drones_max ) )
|
|
{
|
|
max = self.script_drones_max;
|
|
}
|
|
if( self.script_drones_min == max )
|
|
{
|
|
spawnSize = max;
|
|
}
|
|
else
|
|
{
|
|
spawnSize = ( self.script_drones_min + randomint( max - self.script_drones_min ) );
|
|
}
|
|
}
|
|
|
|
self thread drone_spawngroup( self.targeted, qFakeDeath, spawnSize, qSightTrace, team );
|
|
|
|
if( isdefined( self.script_delay ) )
|
|
{
|
|
if( self.script_delay < 0 )
|
|
{
|
|
return;
|
|
}
|
|
wait( self.script_delay );
|
|
}
|
|
else
|
|
{
|
|
wait( self.script_delay_min + randomfloat( self.script_delay_max - self.script_delay_min ) );
|
|
}
|
|
if( ( isdefined( self.script_requires_player ) ) &&( self.script_requires_player > 0 ) )
|
|
{
|
|
self waittill( "trigger" );
|
|
}
|
|
|
|
if( !isdefined( self.script_repeat ) )
|
|
{
|
|
repeat_times = 999999;
|
|
}
|
|
|
|
}
|
|
}
|
|
else //one time only
|
|
{
|
|
//how many drones should spawn?
|
|
spawnSize = undefined;
|
|
if( isdefined( self.script_drones_min ) )
|
|
{
|
|
max = self.targeted.size;
|
|
if( isdefined( self.script_drones_max ) )
|
|
{
|
|
max = self.script_drones_max;
|
|
}
|
|
if( self.script_drones_min == max )
|
|
{
|
|
spawnSize = max;
|
|
}
|
|
else
|
|
{
|
|
spawnSize = ( self.script_drones_min + randomint( max - self.script_drones_min ) );
|
|
}
|
|
}
|
|
|
|
// slayback 10/21/07: added initial delay option for one-time drone spawners
|
|
self drone_triggers_delay_first_spawn();
|
|
|
|
self thread drone_spawngroup( self.targeted, qFakeDeath, spawnSize, qSightTrace, team );
|
|
|
|
if( isDefined( self.count ) && self.count > 1 )
|
|
{
|
|
wait( 0.05 );
|
|
self.count--;
|
|
self thread drone_triggers_think();
|
|
}
|
|
}
|
|
}
|
|
|
|
// slayback 10/21/07: if delay is specified on non-looping triggers, wait before spawning drones
|
|
// self = the drone spawn trigger
|
|
drone_triggers_delay_first_spawn()
|
|
{
|
|
if( IsDefined( self.script_delay ) )
|
|
{
|
|
if( self.script_delay > 0 )
|
|
{
|
|
wait( self.script_delay );
|
|
}
|
|
}
|
|
else if( IsDefined( self.script_delay_min ) && IsDefined( self.script_delay_max ) )
|
|
{
|
|
if( self.script_delay_max > self.script_delay_min )
|
|
{
|
|
wait( RandomFloatRange( self.script_delay_min, self.script_delay_max ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
drone_spawngroup( spawnpoint, qFakeDeath, spawnSize, qSightTrace, team )
|
|
{
|
|
spawncount = spawnpoint.size;
|
|
if( isdefined( spawnSize ) )
|
|
{
|
|
spawncount = spawnSize;
|
|
spawnpoint = array_randomize( spawnpoint );
|
|
}
|
|
|
|
if( spawncount > spawnpoint.size )
|
|
{
|
|
spawncount = spawnpoint.size;
|
|
}
|
|
|
|
for( i = 0; i < spawncount; i++ )
|
|
{
|
|
if (isdefined(self.script_int))
|
|
{
|
|
wait randomfloat(0.1, 1.0);
|
|
}
|
|
|
|
while(!self ok_to_trigger_spawn())
|
|
{
|
|
wait_network_frame();
|
|
}
|
|
|
|
spawnpoint[i] thread drone_spawn( qFakeDeath, qSightTrace, team );
|
|
|
|
level._numTriggerSpawned ++;
|
|
}
|
|
}
|
|
|
|
#using_animtree( "fakeshooters" );
|
|
drone_spawn( qFakeDeath, qSightTrace, team )
|
|
{
|
|
// SCRIPTER_MOD
|
|
// JesseS( 3/16/2007 ): Added check to make sure we dont get a bunch of these queued up
|
|
// by co-op guys
|
|
level endon( "new drone spawn wave" );
|
|
|
|
if( !isdefined( qFakeDeath ) )
|
|
{
|
|
qFakeDeath = false;
|
|
}
|
|
|
|
//if qSightTrace, wait until player can't see the drone spawn point
|
|
if( !isdefined( qSightTrace ) )
|
|
{
|
|
qSightTrace = false;
|
|
}
|
|
|
|
while( ( qSightTrace ) &&( self spawnpoint_playersView() ) )
|
|
{
|
|
wait 0.2;
|
|
}
|
|
|
|
if( level.drones[team].lastindex > level.max_drones[team] )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//spawn a drone
|
|
guy = spawn( "script_model", groundpos( self.origin ) );
|
|
|
|
if( IsDefined( self.angles ) )
|
|
{
|
|
guy.angles = self.angles;
|
|
}
|
|
else if( IsDefined( self.targeted ) )
|
|
{
|
|
guy.angles = VectorToAngles( self.targeted[0].origin - guy.origin );
|
|
}
|
|
|
|
assert( isdefined( level.drone_spawnFunction[team] ) );
|
|
guy [[level.drone_spawnFunction[team]]]();
|
|
guy drone_assign_weapon( team );
|
|
guy.targetname = "drone";
|
|
// Added by Alex Liu 10/16/07 to allow script to identify specific drones
|
|
// Drones now have the same script_noteworthy as their spawn points( the structs, not the trigger )
|
|
guy.script_noteworthy = self.script_noteworthy;
|
|
guy MakeFakeAI();
|
|
guy.team = team;
|
|
guy.fakeDeath = qFakeDeath;
|
|
guy.drone_run_cycle = %combat_run_fast_3;
|
|
guy thread drone_think( self );
|
|
|
|
// CODER_MOD: Austin (6/24/08): used to track berserker kill streaks
|
|
if ( guy.fakeDeath && maps\_collectibles::has_collectible( "collectible_berserker" ) )
|
|
{
|
|
guy thread maps\_collectibles_game::berserker_death();
|
|
}
|
|
}
|
|
|
|
spawnpoint_playersView()
|
|
{
|
|
//first check if it's within the players FOV
|
|
if( !isdefined( level.cos80 ) )
|
|
{
|
|
level.cos80 = cos( 80 );
|
|
}
|
|
|
|
// SCRIPTER_MOD
|
|
// JesseS( 3/16/2007 ): Added check for all players POV
|
|
players = get_players();
|
|
player_view_count = 0;
|
|
success = false;
|
|
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
prof_begin( "drone_math" );
|
|
forwardvec = anglestoforward( players[i].angles );
|
|
normalvec = vectorNormalize( self.origin - players[i] GetOrigin() );
|
|
vecdot = vectordot( forwardvec, normalvec );
|
|
prof_end( "drone_math" );
|
|
|
|
if( vecdot > level.cos80 ) //it's within the players FOV so try a trace now
|
|
{
|
|
prof_begin( "drone_math" );
|
|
success = bullettracepassed( players[i] GetEye(), self.origin +( 0, 0, 48 ), false, self );
|
|
prof_end( "drone_math" );
|
|
|
|
if( success )
|
|
{
|
|
player_view_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( player_view_count != 0 )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//isn't in the field of view so it must be out of sight
|
|
return false;
|
|
}
|
|
|
|
drone_assign_weapon( team )
|
|
{
|
|
if( team == "allies" )
|
|
{
|
|
if( IsDefined( level.drone_weaponlist_allies ) && level.drone_weaponlist_allies.size > 0 )
|
|
{
|
|
randWeapon = randomint( level.drone_weaponlist_allies.size );
|
|
|
|
self.weapon = level.drone_weaponlist_allies[randWeapon];
|
|
ASSERTEX( IsDefined( self.weapon ), "_drones::couldn't assign weapon from level.drone_weaponlist because the array value is undefined." );
|
|
}
|
|
else
|
|
{
|
|
switch( level.campaign )
|
|
{
|
|
case "american":
|
|
self.weapon = drone_allies_assignWeapon_american();
|
|
break;
|
|
case "british":
|
|
self.weapon = drone_allies_assignWeapon_british();
|
|
break;
|
|
case "russian":
|
|
self.weapon = drone_allies_assignWeapon_russian();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( IsDefined( level.drone_weaponlist_axis ) && level.drone_weaponlist_axis.size > 0 )
|
|
{
|
|
randWeapon = randomint( level.drone_weaponlist_axis.size );
|
|
|
|
self.weapon = level.drone_weaponlist_axis[randWeapon];
|
|
ASSERTEX( IsDefined( self.weapon ), "_drones::couldn't assign weapon from level.drone_weaponlist because the array value is undefined." );
|
|
}
|
|
else
|
|
{
|
|
switch( level.campaign )
|
|
{
|
|
case "american":
|
|
self.weapon = drone_axis_assignWeapon_japanese();
|
|
break;
|
|
case "british":
|
|
self.weapon = drone_axis_assignWeapon_german();
|
|
break;
|
|
case "russian":
|
|
self.weapon = drone_axis_assignWeapon_german();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
weaponModel = GetWeaponModel( self.weapon );
|
|
self Attach( weaponModel, "tag_weapon_right" );
|
|
self.bulletsInClip = WeaponClipSize( self.weapon );
|
|
}
|
|
|
|
drone_allies_assignWeapon_american()
|
|
{
|
|
array = [];
|
|
array[array.size] = "m1garand";
|
|
|
|
return array[randomint( array.size )];
|
|
}
|
|
|
|
drone_allies_assignWeapon_british()
|
|
{
|
|
array = [];
|
|
array[array.size] = "lee_enfield";
|
|
|
|
return array[randomint( array.size )];
|
|
}
|
|
|
|
drone_allies_assignWeapon_russian()
|
|
{
|
|
array = [];
|
|
array[array.size] = "mosin_rifle";
|
|
array[array.size] = "ppsh";
|
|
|
|
return array[randomint( array.size )];
|
|
}
|
|
|
|
drone_axis_assignWeapon_german()
|
|
{
|
|
array = [];
|
|
array[array.size] = "kar98k";
|
|
|
|
return array[randomint( array.size )];
|
|
}
|
|
|
|
drone_axis_assignWeapon_japanese()
|
|
{
|
|
array = [];
|
|
array[array.size] = "type99_rifle";
|
|
|
|
return array[randomint( array.size )];
|
|
}
|
|
|
|
drone_setName()
|
|
{
|
|
wait( 0.25 );
|
|
if( !isdefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//set friendlyname on allies
|
|
if( self.team != "allies" )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( !IsDefined( level.names ) )
|
|
{
|
|
maps\_names::setup_names();
|
|
}
|
|
|
|
if( isdefined( self.script_friendname ) )
|
|
{
|
|
self.name = self.script_friendname;
|
|
}
|
|
else
|
|
{
|
|
switch( level.campaign )
|
|
{
|
|
case "american":
|
|
self maps\_names::get_name_for_nationality( "american" );
|
|
break;
|
|
case "russian":
|
|
self maps\_names::get_name_for_nationality( "russian" );
|
|
break;
|
|
case "british":
|
|
self maps\_names::get_name_for_nationality( "british" );
|
|
break;
|
|
}
|
|
}
|
|
assert( isdefined( self.name ) );
|
|
|
|
subText = undefined;
|
|
if( !isdefined( self.weapon ) )
|
|
{
|
|
subText = ( &"WEAPON_RIFLEMAN" );
|
|
}
|
|
else
|
|
{
|
|
switch( self.weapon )
|
|
{
|
|
case "m1garand":
|
|
case "m1garand_wet":
|
|
case "lee_enfield":
|
|
case "m1carbine":
|
|
case "SVT40":
|
|
case "mosin_rifle":
|
|
subText = ( &"WEAPON_RIFLEMAN" );
|
|
break;
|
|
case "thompson":
|
|
case "thompson_wet":
|
|
subText = ( &"WEAPON_SUBMACHINEGUNNER" );
|
|
break;
|
|
case "BAR":
|
|
case "ppsh":
|
|
subText = ( &"WEAPON_SUPPORTGUNNER" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( ( isdefined( self.model ) ) &&( issubstr( self.model, "medic" ) ) )
|
|
{
|
|
subText = ( &"WEAPON_MEDICPLACEHOLDER" );
|
|
}
|
|
assert( isdefined( subText ) );
|
|
|
|
self setlookattext( self.name, subText );
|
|
}
|
|
|
|
|
|
drone_think( firstNode )
|
|
{
|
|
self endon( "death" );
|
|
|
|
self.health = 1000000;
|
|
self thread drone_setName();
|
|
|
|
level thread maps\_friendlyfire::friendly_fire_think( self );
|
|
self thread drones_clear_variables();
|
|
|
|
structarray_add( level.drones[self.team], self );
|
|
|
|
level notify( "new_drone" );
|
|
if( level.script != "pel1" )
|
|
{
|
|
self.turrettarget = spawn( "script_origin", self.origin+( 0, 0, 50 ) );
|
|
self.turrettarget linkto( self );
|
|
}
|
|
self endon( "drone_death" );
|
|
assert( isdefined( firstNode ) );
|
|
|
|
//fake death if this drone is told to do so
|
|
if( ( isdefined( self.fakeDeath ) ) &&( self.fakeDeath == true ) )
|
|
{
|
|
self thread drone_fakeDeath();
|
|
}
|
|
|
|
self endon( "drone_shooting" );
|
|
|
|
if( IsDefined( level.drone_think_func ) )
|
|
{
|
|
self [[level.drone_think_func]]();
|
|
}
|
|
|
|
self.no_death_sink = false;
|
|
if( IsDefined( firstNode.script_drone_no_sink ) && firstNode.script_drone_no_sink )
|
|
{
|
|
self.no_death_sink = true;
|
|
}
|
|
|
|
self drone_runChain( firstNode );
|
|
|
|
wait( 0.05 );
|
|
|
|
self.running = undefined;
|
|
|
|
idle_org = self.origin;
|
|
idle_ang = self.angles;
|
|
self useAnimTree( #animtree );
|
|
idleAnim[0] = %stand_alert_1;
|
|
idleAnim[1] = %stand_alert_2;
|
|
idleAnim[2] = %stand_alert_3;
|
|
|
|
while( isdefined( self ) )
|
|
{
|
|
self AnimScripted( "drone_idle_anim", idle_org, idle_ang, idleAnim[randomint( idleAnim.size )] );
|
|
self waittillmatch( "drone_idle_anim", "end" );
|
|
}
|
|
}
|
|
|
|
#using_animtree( "fakeshooters" );
|
|
drone_mortarDeath( direction )
|
|
{
|
|
self useAnimTree( #animtree );
|
|
switch( direction )
|
|
{
|
|
case "up":
|
|
self thread drone_doDeath( %death_explosion_up10 );
|
|
break;
|
|
case "forward":
|
|
self thread drone_doDeath( %death_explosion_forward13 );
|
|
break;
|
|
case "back":
|
|
self thread drone_doDeath( %death_explosion_back13 );
|
|
break;
|
|
case "left":
|
|
self thread drone_doDeath( %death_explosion_left11 );
|
|
break;
|
|
case "right":
|
|
self thread drone_doDeath( %death_explosion_right13 );
|
|
break;
|
|
}
|
|
}
|
|
|
|
#using_animtree( "fakeshooters" );
|
|
drone_fakeDeath( instant )
|
|
{
|
|
if( !isdefined( instant ) )
|
|
{
|
|
instant = false;
|
|
}
|
|
|
|
self endon( "delete" );
|
|
self endon( "drone_death" );
|
|
|
|
// SRS testing special explosive death anims
|
|
explosivedeath = false;
|
|
explosion_ori = ( 0, 0, 0 );
|
|
// LDS testing special flamebased death anims
|
|
flamedeath = false;
|
|
|
|
while( isdefined( self ) )
|
|
{
|
|
if( !instant )
|
|
{
|
|
self setCanDamage( true );
|
|
self waittill( "damage", amount, attacker, direction_vec, damage_ori, type );
|
|
|
|
// SRS testing special explosive death anims
|
|
if( type == "MOD_GRENADE" || type == "MOD_GRENADE_SPLASH" || type == "MOD_EXPLOSIVE" ||
|
|
type == "MOD_EXPLOSIVE_SPLASH" || type == "MOD_PROJECTILE" || type == "MOD_PROJECTILE_SPLASH" )
|
|
{
|
|
self.damageweapon = "none";
|
|
explosivedeath = true;
|
|
explosion_ori = damage_ori;
|
|
}
|
|
else if( type == "MOD_BURNED" )
|
|
{
|
|
flamedeath = true;
|
|
}
|
|
|
|
self notify( "death", attacker, type );
|
|
|
|
// SCRIPTER_MOD
|
|
// JesseS( 3/16/2007 ): changed attacker == level.player to isplayer( attacker )
|
|
if( self.team == "axis" && ( isplayer( attacker ) || attacker == level.playervehicle ) )
|
|
{
|
|
level notify( "player killed drone" );
|
|
}
|
|
}
|
|
|
|
if( ( isdefined( self.customFirstAnim ) ) &&( self.customFirstAnim == true ) )
|
|
{
|
|
self waittill( "customFirstAnim done" );
|
|
}
|
|
|
|
if( !isdefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self notify( "Stop shooting" );
|
|
self.dontDelete = true;
|
|
|
|
deathAnim = undefined;
|
|
self useAnimTree( #animtree );
|
|
|
|
// SRS Did the guy take damage from an explosive?
|
|
if( explosivedeath )
|
|
{
|
|
// Alex Liu( 4-8-08 )
|
|
// determin direction to play animation
|
|
direction = drone_get_explosion_death_dir( self.origin, self.angles, explosion_ori, 50 );
|
|
|
|
self thread drone_mortarDeath( direction );
|
|
return;
|
|
}
|
|
else if( flamedeath )
|
|
{
|
|
deaths[0] = %ai_flame_death_a;
|
|
deaths[1] = %ai_flame_death_b;
|
|
deaths[2] = %ai_flame_death_c;
|
|
deaths[3] = %ai_flame_death_d;
|
|
}
|
|
// Bloodlust - if not explosive death, then check if drone is running
|
|
else if( isdefined( self.running ) )
|
|
{
|
|
deaths[0] = %death_run_stumble;
|
|
deaths[1] = %death_run_onfront;
|
|
deaths[2] = %death_run_onleft;
|
|
deaths[3] = %death_run_forward_crumple;
|
|
}
|
|
else
|
|
{
|
|
deaths[0] = %death_stand_dropinplace;
|
|
}
|
|
|
|
self thread drone_doDeath( deaths[randomint( deaths.size )] );
|
|
return;
|
|
}
|
|
}
|
|
|
|
#using_animtree( "fakeshooters" );
|
|
drone_delayed_bulletdeath( waitTime, deathRemoveNotify )
|
|
{
|
|
self endon( "delete" );
|
|
self endon( "drone_death" );
|
|
|
|
self.dontDelete = true;
|
|
|
|
if( !isdefined( waitTime ) )
|
|
{
|
|
waitTime = 0;
|
|
}
|
|
|
|
if( waitTime > 0 )
|
|
{
|
|
wait( waitTime );
|
|
}
|
|
|
|
self thread drone_fakeDeath( true );
|
|
}
|
|
|
|
do_death_sound()
|
|
{
|
|
camp = level.campaign;
|
|
team = self.team;
|
|
|
|
alias = undefined;
|
|
|
|
if(camp == "american" && team == "allies")
|
|
alias = "generic_death_american";
|
|
if(camp == "american" && team == "axis")
|
|
alias = "generic_death_japanese";
|
|
if(camp == "russian" && team == "allies")
|
|
alias = "generic_death_russian";
|
|
if(camp == "russian" && team == "axis")
|
|
alias = "generic_death_german";
|
|
|
|
if(isdefined(alias) && SoundExists(alias))
|
|
self thread play_sound_in_space( alias );
|
|
}
|
|
|
|
#using_animtree( "fakeshooters" );
|
|
drone_doDeath( deathAnim, deathRemoveNotify )
|
|
{
|
|
self moveTo( self.origin, 0.05, 0, 0 );
|
|
|
|
traceDeath = false;
|
|
|
|
if( ( isdefined( self.running ) ) && self.running )
|
|
{
|
|
traceDeath = true;
|
|
}
|
|
|
|
self.running = undefined;
|
|
self notify( "drone_death" );
|
|
self notify( "Stop shooting" );
|
|
self unlink();
|
|
self useAnimTree( #animtree );
|
|
self thread drone_doDeath_impacts();
|
|
|
|
do_death_sound();
|
|
|
|
prof_begin( "drone_math" );
|
|
cancelRunningDeath = false;
|
|
if( traceDeath )
|
|
{
|
|
//trace last frame of animation to prevent the body from clipping on something coming up in its path
|
|
//backup animation if trace fails: %death_stand_dropinplace
|
|
|
|
offset = getcycleoriginoffset( self.angles, deathAnim );
|
|
endAnimationLocation = ( self.origin + offset );
|
|
endAnimationLocation = physicstrace( ( endAnimationLocation +( 0, 0, 128 ) ), ( endAnimationLocation -( 0, 0, 128 ) ) );
|
|
//thread debug_line( endAnimationLocation +( 0, 0, 256 ), endAnimationLocation -( 0, 0, 256 ) );
|
|
d1 = abs( endAnimationLocation[2] - self.origin[2] );
|
|
|
|
if( d1 > 20 )
|
|
{
|
|
cancelRunningDeath = true;
|
|
}
|
|
else
|
|
{
|
|
//trace even more forward than the animation( bounding box reasons )
|
|
forwardVec = anglestoforward( self.angles );
|
|
rightVec = anglestoright( self.angles );
|
|
upVec = anglestoup( self.angles );
|
|
relativeOffset = ( 50, 0, 0 );
|
|
secondPos = endAnimationLocation;
|
|
secondPos += vector_multiply( forwardVec, relativeOffset[0] );
|
|
secondPos += vector_multiply( rightVec, relativeOffset[1] );
|
|
secondPos += vector_multiply( upVec, relativeOffset[2] );
|
|
secondPos = physicstrace( ( secondPos +( 0, 0, 128 ) ), ( secondPos -( 0, 0, 128 ) ) );
|
|
d2 = abs( secondPos[2] - self.origin[2] );
|
|
if( d2 > 20 )
|
|
{
|
|
cancelRunningDeath = true;
|
|
}
|
|
}
|
|
}
|
|
prof_end( "drone_math" );
|
|
|
|
if( cancelRunningDeath )
|
|
{
|
|
deathAnim = %death_stand_dropinplace;
|
|
}
|
|
|
|
self animscripted( "drone_death_anim", self.origin, self.angles, deathAnim, "deathplant" );
|
|
self thread drone_ragdoll( deathAnim );
|
|
self waittillmatch( "drone_death_anim", "end" );
|
|
|
|
if( !isdefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self setcontents( 0 );
|
|
if( isdefined( deathRemoveNotify ) )
|
|
{
|
|
level waittill( deathRemoveNotify );
|
|
}
|
|
else
|
|
{
|
|
wait 3;
|
|
}
|
|
|
|
if( !isdefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( !isdefined(self.no_death_sink) || (isdefined(self.no_death_sink) && !self.no_death_sink ))
|
|
{
|
|
self MoveTo( self.origin - ( 0, 0, 100 ), 7 );
|
|
|
|
wait( 3 );
|
|
}
|
|
|
|
if( !isdefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self.dontDelete = undefined;
|
|
self thread drone_delete();
|
|
}
|
|
|
|
drone_ragdoll( deathAnim )
|
|
{
|
|
time = self GetAnimTime( deathAnim );
|
|
|
|
wait( time * 0.55 );
|
|
|
|
if( isdefined( self.weapon ) )
|
|
{
|
|
weaponModel = GetWeaponModel( self.weapon );
|
|
if( isdefined( weaponModel ) )
|
|
{
|
|
self detach( weaponModel, "tag_weapon_right" );
|
|
}
|
|
}
|
|
|
|
self StartRagDoll();
|
|
}
|
|
|
|
drone_doDeath_impacts()
|
|
{
|
|
bone[0] = "J_Knee_LE";
|
|
bone[1] = "J_Ankle_LE";
|
|
bone[2] = "J_Clavicle_LE";
|
|
bone[3] = "J_Shoulder_LE";
|
|
bone[4] = "J_Elbow_LE";
|
|
|
|
impacts = ( 1 + randomint( 2 ) );
|
|
for( i = 0; i < impacts; i++ )
|
|
{
|
|
playfxontag( level.drone_impact, self, bone[randomint( bone.size )] );
|
|
self playsound( "bullet_small_flesh" );
|
|
wait( 0.05 );
|
|
}
|
|
}
|
|
|
|
drone_runChain( point_start )
|
|
{
|
|
self endon( "drone_death" );
|
|
self endon( "drone_shooting" );
|
|
//self endon( "drone_cover" );
|
|
|
|
runPos = undefined;
|
|
while( isdefined( self ) )
|
|
{
|
|
//check for script_death, script_death_min, script_death_max, and script_delete
|
|
//-----------------------------------------------------------------------------
|
|
if( isdefined( point_start.script_death ) )
|
|
{
|
|
//drone will die in this many seconds
|
|
self.dontDelete = true;
|
|
self thread drone_delayed_bulletdeath( 0 );
|
|
}
|
|
else
|
|
if( ( isdefined( point_start.script_death_min ) ) &&( isdefined( point_start.script_death_max ) ) )
|
|
{
|
|
//drone will die between min-max seconds
|
|
self.dontDelete = true;
|
|
self thread drone_delayed_bulletdeath( point_start.script_death_min + randomfloat( point_start.script_death_max - point_start.script_death_min ) );
|
|
}
|
|
|
|
if( ( isdefined( point_start.script_delete ) ) &&( point_start.script_delete >= 0 ) )
|
|
{
|
|
self thread drone_delete( point_start.script_delete );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
if( !isdefined( point_start.targeted ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
point_end = point_start.targeted;
|
|
|
|
if( ( !isdefined( point_end ) ) ||( !isdefined( point_end[0] ) ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
index = randomint( point_end.size );
|
|
|
|
runPos = groundpos( point_end[index].origin );
|
|
|
|
//check for radius on node, since you can now make them run to a radius rather than an exact point
|
|
if( isdefined( point_end[index].radius ) )
|
|
{
|
|
assert( point_end[index].radius > 0 );
|
|
|
|
//offset for this drone( -1 to 1 )
|
|
if( !isdefined( self.droneRunOffset ) )
|
|
{
|
|
self.droneRunOffset = ( 0 - 1 +( randomfloat( 2 ) ) );
|
|
}
|
|
|
|
if( !isdefined( point_end[index].angles ) )
|
|
{
|
|
point_end[index].angles = ( 0, 0, 0 );
|
|
}
|
|
|
|
prof_begin( "drone_math" );
|
|
forwardVec = anglestoforward( point_end[index].angles );
|
|
rightVec = anglestoright( point_end[index].angles );
|
|
upVec = anglestoup( point_end[index].angles );
|
|
relativeOffset = ( 0, ( self.droneRunOffset * point_end[index].radius ) , 0 );
|
|
runPos += vector_multiply( forwardVec, relativeOffset[0] );
|
|
runPos += vector_multiply( rightVec, relativeOffset[1] );
|
|
runPos += vector_multiply( upVec, relativeOffset[2] );
|
|
prof_end( "drone_math" );
|
|
}
|
|
|
|
if( isdefined( point_start.script_noteworthy ) )
|
|
{
|
|
self ShooterRun( runPos, point_start.script_noteworthy );
|
|
}
|
|
else
|
|
{
|
|
self ShooterRun( runPos );
|
|
}
|
|
|
|
point_start = point_end[index];
|
|
}
|
|
|
|
if( isdefined( runPos ) )
|
|
{
|
|
if( isdefined( point_start.script_noteworthy ) )
|
|
{
|
|
self ShooterRun( runPos, point_start.script_noteworthy );
|
|
}
|
|
else
|
|
{
|
|
self ShooterRun( runPos );
|
|
}
|
|
}
|
|
|
|
if( ( isdefined( point_start.script_delete ) ) &&( point_start.script_delete >= 0 ) )
|
|
{
|
|
self thread drone_delete( point_start.script_delete );
|
|
}
|
|
}
|
|
|
|
drones_clear_variables()
|
|
{
|
|
if( isdefined( self.voice ) )
|
|
{
|
|
self.voice = undefined;
|
|
}
|
|
}
|
|
|
|
drone_delete( delayTime )
|
|
{
|
|
if( ( isdefined( delayTime ) ) &&( delayTime > 0 ) )
|
|
{
|
|
wait( delayTime );
|
|
}
|
|
|
|
if( !isdefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self notify( "drone_death" );
|
|
self notify( "drone_idle_anim" );
|
|
|
|
// guzzo 6-4-08 if the drones array doesn't contain the drone, don't remove it. this can happen because drone_delete() is called from both
|
|
// drone_doDeath() and drone_runChain()
|
|
if( !( is_in_array( level.drones[self.team].array, self ) ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
structarray_remove( level.drones[self.team], self );
|
|
if( !isdefined( self.dontDelete ) )
|
|
{
|
|
if( isdefined( self.turrettarget ) )
|
|
{
|
|
self.turrettarget delete();
|
|
}
|
|
|
|
if( isdefined( self.shootTarget ) )
|
|
{
|
|
self.shootTarget delete();
|
|
}
|
|
|
|
self detachall();
|
|
self delete();
|
|
}
|
|
}
|
|
|
|
#using_animtree( "fakeShooters" );
|
|
ShooterRun( destinationPoint, event )
|
|
{
|
|
if( !isdefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self notify( "Stop shooting" );
|
|
self UseAnimTree( #animtree );
|
|
|
|
prof_begin( "drone_math" );
|
|
|
|
//calculate the distance to the next run point and figure out how long it should take
|
|
//to get there based on distance and run speed
|
|
d = distance( self.origin, destinationPoint );
|
|
|
|
if( !isdefined( self.droneRunRate ) )
|
|
{
|
|
self.droneRunRate = 200;
|
|
}
|
|
|
|
speed = ( d / self.droneRunRate );
|
|
|
|
//set his trace height back to normal
|
|
self.lowheight = false;
|
|
//orient the drone to his run point
|
|
self turnToFacePoint( destinationPoint, speed );
|
|
|
|
//if I want the guy to do a jump first do that here before continuing the run
|
|
customFirstAnim = undefined;
|
|
if( IsDefined( event ) )
|
|
{
|
|
switch( event )
|
|
{
|
|
case "jump":
|
|
customFirstAnim = %jump_across_100;
|
|
break;
|
|
|
|
case "jumpdown":
|
|
customFirstAnim = %jump_down_56;
|
|
break;
|
|
|
|
case "wall_hop":
|
|
customFirstAnim = %traverse_wallhop;
|
|
break;
|
|
|
|
case "step_up":
|
|
customFirstAnim = %step_up_low_wall;
|
|
break;
|
|
|
|
case "trench_jump_out":
|
|
customFirstAnim = %trench_jump_out;
|
|
break;
|
|
|
|
case "low_height":
|
|
self.lowheight = true;
|
|
break;
|
|
|
|
case "mortardeath_up":
|
|
self thread drone_mortarDeath( "up" );
|
|
return;
|
|
|
|
case "mortardeath_forward":
|
|
self thread drone_mortarDeath( "forward" );
|
|
return;
|
|
|
|
case "mortardeath_back":
|
|
self thread drone_mortarDeath( "back" );
|
|
return;
|
|
|
|
case "mortardeath_left":
|
|
self thread drone_mortarDeath( "left" );
|
|
return;
|
|
|
|
case "mortardeath_right":
|
|
self thread drone_mortarDeath( "right" );
|
|
return;
|
|
|
|
case "shoot":
|
|
forwardVec = anglestoforward( self.angles );
|
|
rightVec = anglestoright( self.angles );
|
|
upVec = anglestoup( self.angles );
|
|
relativeOffset = ( 300, 0, 64 );
|
|
shootPos = self.origin;
|
|
shootPos += vector_multiply( forwardVec, relativeOffset[0] );
|
|
shootPos += vector_multiply( rightVec, relativeOffset[1] );
|
|
shootPos += vector_multiply( upVec, relativeOffset[2] );
|
|
self.shootTarget = spawn( "script_origin", shootPos );
|
|
|
|
self thread ShooterShoot( self.shootTarget );
|
|
// thread drone_debugLine( self.shootTarget.origin, self.origin, (1,1,1), 500000000 );
|
|
|
|
return;
|
|
|
|
case "shoot_then_run_after_notify":
|
|
forwardVec = anglestoforward( self.angles );
|
|
rightVec = anglestoright( self.angles );
|
|
upVec = anglestoup( self.angles );
|
|
relativeOffset = ( 300, 0, 64 );
|
|
shootPos = self.origin;
|
|
shootPos += vector_multiply( forwardVec, relativeOffset[0] );
|
|
shootPos += vector_multiply( rightVec, relativeOffset[1] );
|
|
shootPos += vector_multiply( upVec, relativeOffset[2] );
|
|
self.shootTarget = spawn( "script_origin", shootPos );
|
|
|
|
self thread ShooterShoot( self.shootTarget );
|
|
self waittill ("Stop shooting");
|
|
self clearanim(%combat_directions, 0);
|
|
self clearanim(%exposed_reload, 0);
|
|
break;
|
|
|
|
case "cover_stand":
|
|
self thread drone_cover( event );
|
|
|
|
// important waittill: will wait until drone gets this notify before continuing along the path
|
|
self waittill( "drone out of cover" );
|
|
|
|
self setFlaggedAnimKnob( "cover_exit", %coverstand_trans_OUT_M, 1, .1, 1 );
|
|
self waittillmatch( "cover_exit", "end" );
|
|
break;
|
|
|
|
case "cover_crouch":
|
|
self thread drone_cover( event );
|
|
|
|
// important waittill: will wait until drone gets this notify before continuing along the path
|
|
self waittill( "drone out of cover" );
|
|
|
|
self setFlaggedAnimKnob( "cover_exit", %covercrouch_run_out_M, 1, .1, 1 );
|
|
self waittillmatch( "cover_exit", "end" );
|
|
break;
|
|
|
|
// TFLAME - 3/14/08 - Added anims for drones walking in distance on sniper
|
|
case "sniper_distance_walk":
|
|
walkanims = [];
|
|
walkanims[0] = "weary_walka";
|
|
walkanims[1] = "weary_walkb";
|
|
walkanims[2] = "weary_walkc";
|
|
walkanims[3] = "weary_walkd";
|
|
rand = randomint( 3 );
|
|
self.droneRunRate = 50;
|
|
self.drone_run_cycle = level.drone_run_cycle[walkanims[rand]];
|
|
self.running = false;
|
|
self thread ShooterRun_doRunAnim();
|
|
break;
|
|
|
|
// TFLAME - 5/5/08 - Adding stuff for drones at end of sniper during officer sniping event
|
|
case "lowwalk":
|
|
walkanim = "sneaking_walk";
|
|
self.drone_run_cycle = level.drone_run_cycle[walkanim];
|
|
self.droneRunRate = 140;
|
|
self.running = false;
|
|
self thread ShooterRun_doRunAnim();
|
|
break;
|
|
|
|
case "water_deep":
|
|
rand = randomint( 2 );
|
|
|
|
if( rand == 1 )
|
|
{
|
|
self.droneRunRate = 100;
|
|
self.drone_run_cycle = level.drone_run_cycle["run_deep_a"];
|
|
self.running = false;
|
|
self thread ShooterRun_doRunAnim();
|
|
}
|
|
else
|
|
{
|
|
self.droneRunRate = 100;
|
|
self.drone_run_cycle = level.drone_run_cycle["run_deep_b"];
|
|
self.running = false;
|
|
self thread ShooterRun_doRunAnim();
|
|
}
|
|
|
|
randomAnimRate = undefined;
|
|
|
|
//recalculate the distance to the next point since it changed now
|
|
d = distance( self.origin, destinationPoint );
|
|
speed = ( d / self.droneRunRate );
|
|
break;
|
|
|
|
case "run_fast":
|
|
self.droneRunRate = 200;
|
|
self.drone_run_cycle = %combat_run_fast_3;
|
|
self.running = false;
|
|
self thread ShooterRun_doRunAnim();
|
|
|
|
randomAnimRate = undefined;
|
|
|
|
//recalculate the distance to the next point since it changed now
|
|
d = distance( self.origin, destinationPoint );
|
|
speed = ( d / self.droneRunRate );
|
|
break;
|
|
}
|
|
}
|
|
|
|
minRate = 0.5;
|
|
maxRate = 1.5;
|
|
randomAnimRate = minRate + randomfloat( maxRate - minRate );
|
|
|
|
if( isdefined( customFirstAnim ) )
|
|
{
|
|
self.customFirstAnim = true;
|
|
self.running = undefined;
|
|
randomAnimRate = undefined;
|
|
angles = VectorToAngles( destinationPoint - self.origin );
|
|
offset = getcycleoriginoffset( angles, customFirstAnim );
|
|
endPos = self.origin + offset;
|
|
endPos = physicstrace( ( endPos +( 0, 0, 64 ) ), ( endPos -( 0, 0, level.traceHeight ) ) );
|
|
|
|
t = getanimlength( customFirstAnim );
|
|
assert( t > 0 );
|
|
|
|
self clearanim( self.drone_run_cycle, 0 );
|
|
self notify( "stop_run_anim" );
|
|
|
|
self moveto( endPos, t, 0, 0 );
|
|
|
|
self setflaggedanimknobrestart( "drone_custom_anim" , customFirstAnim );
|
|
self waittillmatch( "drone_custom_anim", "end" );
|
|
|
|
self.origin = endPos;
|
|
self notify( "customFirstAnim done" );
|
|
|
|
//recalculate the distance to the next point since it changed now
|
|
d = distance( self.origin, destinationPoint );
|
|
speed = ( d / self.droneRunRate );
|
|
|
|
if( ( ( isdefined( event ) ) &&( event == "jumpdown" ) ) &&( level.script == "duhoc_assault" ) )
|
|
{
|
|
structarray_remove( level.drones[self.team], self );
|
|
if( isdefined( self.turrettarget ) )
|
|
{
|
|
self.turrettarget delete();
|
|
}
|
|
|
|
if( isdefined( self.shootTarget ) )
|
|
{
|
|
self.shootTarget delete();
|
|
}
|
|
|
|
self detachall();
|
|
self delete();
|
|
return;
|
|
}
|
|
}
|
|
|
|
self.customFirstAnim = undefined;
|
|
|
|
//drone loops run animation until he gets to his next point
|
|
self thread ShooterRun_doRunAnim( randomAnimRate );
|
|
|
|
//actually move the dummies now )
|
|
self drone_runto( destinationPoint, speed );
|
|
|
|
prof_end( "drone_math" );
|
|
}
|
|
|
|
drone_runto( destinationPoint, totalMoveTime )
|
|
{
|
|
//-- GLocke: Removed this assert after talking to MikeD since the
|
|
// function just returns if totalMoveTime is < 0.1
|
|
//assert( totalMoveTime > 0 );
|
|
if( totalMoveTime < 0.1 )
|
|
{
|
|
return;
|
|
}
|
|
//Make several moves to get there, each point tracing to the ground
|
|
//X = ( x2-x1 ) * p + x1
|
|
|
|
percentIncrement = 0.1;
|
|
percentage = 0.0;
|
|
incements = ( 1 / percentIncrement );
|
|
dividedMoveTime = ( totalMoveTime * percentIncrement );
|
|
startingPos = self.origin;
|
|
oldZ = startingPos[2];
|
|
for( i = 0; i < incements; i++ )
|
|
{
|
|
prof_begin( "drone_math" );
|
|
|
|
percentage += percentIncrement;
|
|
x = ( destinationPoint[0] - startingPos[0] ) * percentage + startingPos[0];
|
|
y = ( destinationPoint[1] - startingPos[1] ) * percentage + startingPos[1];
|
|
if( self.lowheight == true )
|
|
{
|
|
percentageMark = physicstrace( ( x, y, destinationPoint[2] + 64 ), ( x, y, destinationPoint[2] - level.traceHeight ) );
|
|
}
|
|
else
|
|
{
|
|
percentageMark = physicstrace( ( x, y, destinationPoint[2] + level.traceHeight ), ( x, y, destinationPoint[2] - level.traceHeight ) );
|
|
}
|
|
|
|
//if drone was told to go up more than level.droneStepHeight( 100 ) units, keep old height
|
|
if( ( percentageMark[2] - oldZ ) > level.droneStepHeight )
|
|
{
|
|
percentageMark = ( percentageMark[0], percentageMark[1], oldZ );
|
|
}
|
|
|
|
oldZ = percentageMark[2];
|
|
|
|
prof_end( "drone_math" );
|
|
|
|
//thread drone_debugLine( self.origin, percentageMark, ( 1, 1, 1 ), dividedMoveTime );
|
|
|
|
|
|
self moveTo( percentageMark, dividedMoveTime, 0, 0 );
|
|
wait( dividedMoveTime );
|
|
}
|
|
}
|
|
|
|
ShooterShoot( target )
|
|
{
|
|
self thread ShooterShootThread( target );
|
|
}
|
|
|
|
#using_animtree( "fakeShooters" );
|
|
ShooterShootThread( target )
|
|
{
|
|
self notify( "Stop shooting" );
|
|
|
|
// for special drones, dont make earlier threads die
|
|
if (!isdefined(self.script_noteworthy))
|
|
{
|
|
self notify( "drone_shooting" );
|
|
}
|
|
else if (isdefined(self.script_noteworthy) && self.script_noteworthy != "run_n_gun_drones")
|
|
{
|
|
self notify( "drone_shooting" );
|
|
}
|
|
|
|
self endon( "Stop shooting" );
|
|
self UseAnimTree( #animtree );
|
|
self.running = undefined;
|
|
self thread aimAtTargetThread( target, "Stop shooting" );
|
|
|
|
shootAnimLength = 0;
|
|
while( isdefined( self ) )
|
|
{
|
|
if( self.bulletsInClip <= 0 ) // Reload
|
|
{
|
|
weaponModel = getWeaponModel( self.weapon );
|
|
if( isdefined( self.weaponModel ) )
|
|
{
|
|
weaponModel = self.weaponModel;
|
|
}
|
|
|
|
//see if this model is actually attached to this character
|
|
numAttached = self getattachsize();
|
|
attachName = [];
|
|
for( i = 0; i < numAttached; i++ )
|
|
{
|
|
attachName[i] = self getattachmodelname( i );
|
|
}
|
|
|
|
// self detach( weaponModel, "tag_weapon_right" );
|
|
// self attach( weaponModel, "tag_weapon_left" );
|
|
self setflaggedanimknoballrestart( "reloadanim", %exposed_reload, %root, 1, 0.4 );
|
|
|
|
// SCRIPTER_MOD
|
|
// JesseS( 3/16/2007 ): took out clipsize call since it's gone now
|
|
//self.bulletsInClip = self animscripts\weaponList::ClipSize();
|
|
self.bulletsInClip = randomintrange (4, 8);
|
|
self waittillmatch( "reloadanim", "end" );
|
|
//self detach( weaponModel, "tag_weapon_left" );
|
|
//self attach( weaponModel, "tag_weapon_right" );
|
|
}
|
|
|
|
// Aim for a while
|
|
self Set3FlaggedAnimKnobs( "no flag", "aim", "stand", 1, 0.3, 1 );
|
|
wait( 1 + randomfloat( 2 ) );
|
|
|
|
if( !isdefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// And shoot a few times
|
|
numShots = randomint( 4 )+1;
|
|
if( numShots > self.bulletsInClip )
|
|
{
|
|
numShots = self.bulletsInClip;
|
|
}
|
|
|
|
for( i = 0; i < numShots; i++ )
|
|
{
|
|
if( !isdefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self Set3FlaggedAnimKnobsRestart( "shootinganim", "shoot", "stand", 1, 0.05, 1 );
|
|
|
|
playfxontag( level.drone_muzzleflash, self, "tag_flash" );
|
|
if( self.team == "axis" )
|
|
{
|
|
// slayback 10/21/07: updated weapon sounds
|
|
switch( level.campaign )
|
|
{
|
|
case "american":
|
|
//self playsound( "weap_type99_fire" ); // no Type 99 sounds yet
|
|
break;
|
|
case "russian":
|
|
self playsound( "weap_kar98k_fire" );
|
|
break;
|
|
case "british":
|
|
self playsound( "weap_kar98k_fire" );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// slayback 10/21/07: updated weapon sounds
|
|
switch( level.campaign )
|
|
{
|
|
case "american":
|
|
self playsound( "weap_m1garand_fire" );
|
|
break;
|
|
case "russian":
|
|
self playsound( "weap_nagant_fire" );
|
|
break;
|
|
case "british":
|
|
self playsound( "weap_enfield_fire" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
self.bulletsInClip--;
|
|
|
|
// Remember how long the shoot anim is so we can cut it short in the future.
|
|
if( shootAnimLength == 0 )
|
|
{
|
|
shootAnimLength = gettime();
|
|
self waittillmatch( "shootinganim", "end" );
|
|
shootAnimLength = ( gettime() - shootAnimLength ) / 1000;
|
|
}
|
|
else
|
|
{
|
|
wait( shootAnimLength - 0.1 + randomfloat( 0.3 ) );
|
|
if( !isdefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ShooterRun_doRunAnim( animRateMod )
|
|
{
|
|
if( isdefined( self.running ) && self.running )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self notify( "stop_shooterrun" );
|
|
self endon( "stop_shooterrun" );
|
|
|
|
self.running = true;
|
|
|
|
if( !isdefined( animRateMod ) )
|
|
{
|
|
animRateMod = 1.0;
|
|
}
|
|
|
|
self endon( "stop_run_anim" );
|
|
adjustAnimRate = true;
|
|
while( ( isdefined( self.running ) ) &&( self.running == true ) )
|
|
{
|
|
animRate = ( self.droneRunRate / 200 );
|
|
|
|
if( adjustAnimRate )
|
|
{
|
|
animRate = ( animRate * animRateMod );
|
|
adjustAnimRate = false;
|
|
}
|
|
|
|
self setflaggedanimknobrestart( "drone_run_anim" , self.drone_run_cycle, 1, .2, 1 );
|
|
self waittillmatch( "drone_run_anim", "end" );
|
|
|
|
if( !isdefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
drone_debugLine( fromPoint, toPoint, color, durationFrames )
|
|
{
|
|
/#
|
|
for( i = 0; i < durationFrames*20; i++ )
|
|
{
|
|
line( fromPoint, toPoint, color );
|
|
wait( 0.05 );
|
|
}
|
|
#/
|
|
}
|
|
|
|
turnToFacePoint( point, speed )
|
|
{
|
|
// TODO Make this turn gradually, not instantly.
|
|
desiredAngles = VectorToAngles( point - self.origin );
|
|
|
|
if( !isdefined( speed ) )
|
|
{
|
|
speed = 0.5;
|
|
}
|
|
else if( speed > 0.5 )
|
|
{
|
|
speed = 0.5;
|
|
}
|
|
|
|
if( speed < 0.1 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self rotateTo( ( 0, desiredAngles[1], 0 ), speed, 0, 0 );
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------
|
|
|
|
Set3FlaggedAnimKnobs( animFlag, animArray, pose, weight, blendTime, rate )
|
|
{
|
|
if( !isdefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self setAnimKnob( %combat_directions, weight, blendTime, rate );
|
|
self SetFlaggedAnimKnob( animFlag, level.drone_animArray[animArray][pose]["up"], 1, blendTime, 1 );
|
|
self SetAnimKnob( level.drone_animArray[animArray][pose]["straight"], 1, blendTime, 1 );
|
|
self SetAnimKnob( level.drone_animArray[animArray][pose]["down"], 1, blendTime, 1 );
|
|
}
|
|
|
|
Set3FlaggedAnimKnobsRestart( animFlag, animArray, pose, weight, blendTime, rate )
|
|
{
|
|
if( !isdefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self setAnimKnobRestart( %combat_directions, weight, blendTime, rate );
|
|
self SetFlaggedAnimKnobRestart( animFlag, level.drone_animArray[animArray][pose]["up"], 1, blendTime, 1 );
|
|
self SetAnimKnobRestart( level.drone_animArray[animArray][pose]["straight"], 1, blendTime, 1 );
|
|
self SetAnimKnobRestart( level.drone_animArray[animArray][pose]["down"], 1, blendTime, 1 );
|
|
}
|
|
|
|
applyBlend( offset )
|
|
{
|
|
if( offset < 0 )
|
|
{
|
|
unstraightAnim = %combat_down;
|
|
self setanim( %combat_up, 0.01, 0, 1 );
|
|
offset *= -1;
|
|
}
|
|
else
|
|
{
|
|
unstraightAnim = %combat_up;
|
|
self setanim( %combat_down, 0.01, 0, 1 );
|
|
}
|
|
|
|
if( offset > 1 )
|
|
{
|
|
offset = 1;
|
|
}
|
|
|
|
unstraight = offset;
|
|
|
|
if( unstraight >= 1.0 )
|
|
{
|
|
unstraight = 0.99;
|
|
}
|
|
|
|
if( unstraight <= 0 )
|
|
{
|
|
unstraight = 0.01;
|
|
}
|
|
straight = 1 - unstraight;
|
|
self setanim( unstraightAnim, unstraight, 0, 1 );
|
|
self setanim( %combat_straight, straight, 0, 1 );
|
|
}
|
|
|
|
aimAtTargetThread( target, stopString )
|
|
{
|
|
self endon( stopString );
|
|
while( isdefined( self ) )
|
|
{
|
|
targetPos = target.origin;
|
|
turnToFacePoint( targetPos );
|
|
offset = getTargetUpDownOffset( targetPos );
|
|
applyBlend( offset );
|
|
wait( 0.05 );
|
|
}
|
|
}
|
|
|
|
getTargetUpDownOffset( target )
|
|
{
|
|
pos = self.origin; // getEye();
|
|
dir = ( target[0] - pos[0], target[1] - pos[1], target[2] - pos[2] );
|
|
dir = VectorNormalize( dir );
|
|
return dir[2];
|
|
}
|
|
|
|
setAnimArray()
|
|
{
|
|
level.drone_animArray["aim"] ["stand"]["down"] = %stand_aim_down;
|
|
level.drone_animArray["aim"] ["stand"]["straight"] = %stand_aim_straight;
|
|
level.drone_animArray["aim"] ["stand"]["up"] = %stand_aim_up;
|
|
|
|
level.drone_animArray["aim"] ["crouch"]["down"] = %crouch_aim_down;
|
|
level.drone_animArray["aim"] ["crouch"]["straight"] = %crouch_aim_straight;
|
|
level.drone_animArray["aim"] ["crouch"]["up"] = %crouch_aim_up;
|
|
|
|
level.drone_animArray["auto"] ["stand"]["down"] = %stand_shoot_auto_down;
|
|
level.drone_animArray["auto"] ["stand"]["straight"] = %stand_shoot_auto_straight;
|
|
level.drone_animArray["auto"] ["stand"]["up"] = %stand_shoot_auto_up;
|
|
|
|
level.drone_animArray["auto"] ["crouch"]["down"] = %crouch_shoot_auto_down;
|
|
level.drone_animArray["auto"] ["crouch"]["straight"] = %crouch_shoot_auto_straight;
|
|
level.drone_animArray["auto"] ["crouch"]["up"] = %crouch_shoot_auto_up;
|
|
|
|
level.drone_animArray["shoot"] ["stand"]["down"] = %stand_shoot_down;
|
|
level.drone_animArray["shoot"] ["stand"]["straight"] = %stand_shoot_straight;
|
|
level.drone_animArray["shoot"] ["stand"]["up"] = %stand_shoot_up;
|
|
|
|
level.drone_animArray["shoot"] ["crouch"]["down"] = %crouch_shoot_down;
|
|
level.drone_animArray["shoot"] ["crouch"]["straight"] = %crouch_shoot_straight;
|
|
level.drone_animArray["shoot"] ["crouch"]["up"] = %crouch_shoot_up;
|
|
}
|
|
|
|
drone_cover( type )
|
|
{
|
|
self endon( "drone_stop_cover" );
|
|
|
|
if( !IsDefined( self.a ) )
|
|
{
|
|
self.a = SpawnStruct();
|
|
}
|
|
|
|
self.running = undefined;
|
|
|
|
anim_array = [];
|
|
|
|
if( type == "cover_stand" )
|
|
{
|
|
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
|
|
);
|
|
|
|
self.a.array = anim_array;
|
|
|
|
self setFlaggedAnimKnobRestart( "cover_approach", %coverstand_trans_IN_M, 1, .3, 1 );
|
|
self waittillmatch( "cover_approach", "end" );
|
|
|
|
self thread drone_cover_think();
|
|
}
|
|
else if( type == "cover_crouch" )
|
|
{
|
|
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
|
|
);
|
|
|
|
self.a.array = anim_array;
|
|
|
|
self setFlaggedAnimKnobRestart( "cover_approach", %covercrouch_run_in_M, 1, .3, 1 );
|
|
self waittillmatch( "cover_approach", "end" );
|
|
|
|
self thread drone_cover_think();
|
|
}
|
|
}
|
|
|
|
drone_cover_think()
|
|
{
|
|
self endon( "drone_stop_cover" );
|
|
|
|
while( 1 )
|
|
{
|
|
useTwitch = ( randomint( 2 ) == 0 );
|
|
if( useTwitch )
|
|
{
|
|
idleanim = animArrayPickRandom( "hide_idle_twitch" );
|
|
}
|
|
else
|
|
{
|
|
idleanim = animarray( "hide_idle" );
|
|
}
|
|
|
|
self drone_playIdleAnimation( idleAnim, useTwitch );
|
|
}
|
|
}
|
|
|
|
drone_playIdleAnimation( idleAnim, needsRestart )
|
|
{
|
|
self endon( "drone_stop_cover" );
|
|
|
|
if( needsRestart )
|
|
{
|
|
self setFlaggedAnimKnobRestart( "idle", idleAnim, 1, .1, 1 );
|
|
}
|
|
else
|
|
{
|
|
self setFlaggedAnimKnob ( "idle", idleAnim, 1, .1, 1 );
|
|
}
|
|
|
|
self.a.coverMode = "hide";
|
|
|
|
self waittillmatch( "idle", "end" );
|
|
}
|
|
|
|
// Find the direction the drone should fly towards from explosion
|
|
//( Alex Liu 4-8-08 )
|
|
//
|
|
// returns:
|
|
//
|
|
// "up" -> If the explosion is clos to the drone( set by up_distance )
|
|
// "left", "right", "forward", "back" -> Direction to throw the drone
|
|
//
|
|
// NOTE: up_distance must be a non-zero positive value
|
|
drone_get_explosion_death_dir( self_pos, self_angle, explosion_pos, up_distance )
|
|
{
|
|
if( Distance2D( self_pos, explosion_pos ) < up_distance )
|
|
{
|
|
return "up";
|
|
}
|
|
|
|
// we need the angle between the self forward angle and the angle to the explosion
|
|
// However to get this we need to draw a right triangle, find 2 sides, then ATan
|
|
p1 = self_pos - vectornormalize( AnglesToForward( self_angle ) ) * 10000;
|
|
p2 = self_pos + vectornormalize( AnglesToForward( self_angle ) ) * 10000;
|
|
p_intersect = PointOnSegmentNearestToPoint( p1, p2, explosion_pos );
|
|
|
|
side_away_dist = Distance2D( p_intersect, explosion_pos );
|
|
side_close_dist = Distance2D( p_intersect, self_pos );
|
|
|
|
if( side_close_dist != 0 )
|
|
{
|
|
angle = ATan( side_away_dist / side_close_dist );
|
|
|
|
// depending on if the explosion is in front or behind self, modify the angle
|
|
dot_product = vectordot( anglestoforward( self_angle ), vectornormalize( explosion_pos - self_pos ) );
|
|
if( dot_product < 0 )
|
|
{
|
|
angle = 180 - angle;
|
|
}
|
|
|
|
if( angle < 45 )
|
|
{
|
|
return "back";
|
|
}
|
|
else if( angle > 135 )
|
|
{
|
|
return "forward";
|
|
}
|
|
}
|
|
|
|
// now we need to know if this is to the left or right
|
|
// We can simply creat another point either to the left or right side of self( I choose right )
|
|
// and see if it's closer to the explosion. The new point must be closer than up_distance, or
|
|
// the result can be wrong.
|
|
self_right_angle = vectornormalize( AnglesToRight( self_angle ) );
|
|
right_point = self_pos + self_right_angle *( up_distance * 0.5 );
|
|
|
|
if( Distance2D( right_point, explosion_pos ) < Distance2D( self_pos, explosion_pos ) )
|
|
{
|
|
return "left";
|
|
}
|
|
else
|
|
{
|
|
return "right";
|
|
}
|
|
}
|