356 lines
9.1 KiB
Plaintext
356 lines
9.1 KiB
Plaintext
#include common_scripts\utility;
|
|
|
|
CONST_microdrone_weaponname = "iw5_microdronelauncher_mp";
|
|
CONST_max_homing_angle_from_grenade = 15;
|
|
CONST_begin_homing_time = .35;
|
|
CONST_drop_accel = 800; // inches/s^2
|
|
|
|
CONST_explosion_delay_time = 3;
|
|
|
|
|
|
monitor_microdrone_launch()
|
|
{
|
|
level._effect[ "mdl_sticky_explosion" ] = LoadFx( "vfx/explosion/frag_grenade_default" );
|
|
level._effect[ "mdl_sticky_blinking" ] = LoadFx( "vfx/lights/light_semtex_blinking" );
|
|
|
|
Assert(IsPlayer(self) || IsAgent(self));
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
self endon( "faux_spawn" );
|
|
|
|
while(true)
|
|
{
|
|
self waittill("missile_fire", projectile, weaponName);
|
|
if( IsSubStr( weaponName, CONST_microdrone_weaponname ) )
|
|
{
|
|
projectile setOtherEnt( self );
|
|
// //projectile thread microdrone_think(self); //tracking functionality, disabling to test new delayed sticky explosives
|
|
// projectile thread determine_projectile_position( self );
|
|
// projectile waittill( "death" );
|
|
// projectile thread determine_sticky_position( self );
|
|
}
|
|
}
|
|
}
|
|
|
|
determine_projectile_position( firing_player )
|
|
{
|
|
//keep track of where it was the frame before
|
|
//when it impacts, do a trace from the frame prior to the impact location to get all your info
|
|
|
|
self endon( "death" );
|
|
|
|
while( true )
|
|
{
|
|
if( !IsDefined( self.previous_position ) )
|
|
{
|
|
self.previous_position = self.origin;
|
|
}
|
|
|
|
wait( 0.05 );
|
|
|
|
self.previous_position = self.origin;
|
|
}
|
|
}
|
|
|
|
determine_sticky_position( firing_player )
|
|
{
|
|
firing_player endon( "spawned_player" );
|
|
|
|
if( !IsDefined( self.previous_position ) )
|
|
return;
|
|
|
|
if( !isDefined( self ) ) //timed out
|
|
return;
|
|
|
|
previous_to_current = self.origin - self.previous_position;
|
|
trajectory = VectorToAngles( previous_to_current );
|
|
forward = AnglesToForward( trajectory ) * 8000;
|
|
end = self.origin + forward;
|
|
|
|
trace = BulletTrace( self.previous_position, end, true, firing_player, true, true );
|
|
|
|
if( trace[ "fraction" ] < 1 && isDefined( trace[ "position" ] ) )
|
|
{
|
|
sticky_grenade = Spawn( "script_model", trace[ "position" ] );
|
|
sticky_grenade SetModel( "projectile_semtex_grenade" );
|
|
|
|
if( isDefined( trace[ "entity" ] ) )
|
|
{
|
|
if( IsPlayer( trace[ "entity" ] ) )
|
|
{
|
|
firing_player thread show_stuck_fanfare();
|
|
trace[ "entity" ] thread show_stuck_fanfare();
|
|
}
|
|
|
|
sticky_grenade LinkTo( trace[ "entity" ] );
|
|
}
|
|
|
|
sticky_grenade thread sticky_timer( firing_player );
|
|
sticky_grenade thread sticky_fx( firing_player );
|
|
sticky_grenade thread remove_sticky( firing_player );
|
|
}
|
|
}
|
|
|
|
microdronelauncher_cleanup()
|
|
{
|
|
self waittill_any( "death", "disconnect", "faux_spawn" );
|
|
|
|
if ( IsDefined( self.HUDItem ) )
|
|
{
|
|
foreach ( hudItem in self.HUDItem)
|
|
hudItem Destroy();
|
|
self.HUDItem = undefined;
|
|
}
|
|
}
|
|
|
|
|
|
show_stuck_fanfare()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
self endon( "faux_spawn" );
|
|
|
|
if( !IsDefined( self.HUDItem ) )
|
|
{
|
|
self.HUDItem = [];
|
|
}
|
|
|
|
if( IsDefined( self.HUDItem ) && !IsDefined( self.HUDItem[ "mdlStuckText" ] ) )
|
|
{
|
|
self.HUDItem[ "mdlStuckText" ] = NewClientHudElem( self );
|
|
self.HUDItem[ "mdlStuckText" ].x = 0;
|
|
self.HUDItem[ "mdlStuckText" ].y = -170;
|
|
self.HUDItem[ "mdlStuckText" ].alignX = "center";
|
|
self.HUDItem[ "mdlStuckText" ].alignY = "middle";
|
|
self.HUDItem[ "mdlStuckText" ].horzAlign = "center";
|
|
self.HUDItem[ "mdlStuckText" ].vertAlign = "middle";
|
|
self.HUDItem[ "mdlStuckText" ].fontScale = 3.0;
|
|
self.HUDItem[ "mdlStuckText" ].alpha = 0.0;
|
|
self.HUDItem[ "mdlStuckText" ] SetText( "STUCK!" );
|
|
self thread microdronelauncher_cleanup();
|
|
}
|
|
|
|
if( IsDefined( self.HUDItem[ "mdlStuckText" ] ) )
|
|
{
|
|
self.HUDItem[ "mdlStuckText" ].alpha = 1.0;
|
|
wait( 2.0 );
|
|
self.HUDItem[ "mdlStuckText" ].alpha = 0.0;
|
|
}
|
|
}
|
|
|
|
sticky_timer( firing_player )
|
|
{
|
|
firing_player endon( "spawned_player" );
|
|
|
|
wait( CONST_explosion_delay_time );
|
|
|
|
PlayFx( getfx( "mdl_sticky_explosion" ), self.origin );
|
|
PhysicsExplosionSphere( self.origin, 256, 32, 1.0 );
|
|
RadiusDamage( self.origin, 256, 130, 15, firing_player, "MOD_EXPLOSIVE", "iw5_microdronelauncher_mp" );
|
|
|
|
self notify( "exploded" );
|
|
}
|
|
|
|
sticky_fx( firing_player )
|
|
{
|
|
firing_player endon( "spawned_player" );
|
|
self endon( "exploded" );
|
|
|
|
self.fx_origin = spawn_tag_origin();
|
|
self.fx_origin.origin = self.origin;
|
|
self.fx_origin Show();
|
|
|
|
wait( 0.1 );
|
|
|
|
PlayFXOnTag( getfx( "mdl_sticky_blinking" ), self.fx_origin, "tag_origin" );
|
|
}
|
|
|
|
remove_sticky( firing_player )
|
|
{
|
|
self thread remove_sticky_on_explosion( firing_player );
|
|
self thread remove_sticky_on_respawn( firing_player );
|
|
}
|
|
|
|
remove_sticky_on_explosion( firing_player )
|
|
{
|
|
firing_player endon( "spawned_player" );
|
|
|
|
self waittill( "exploded" );
|
|
|
|
if( isDefined( self ) )
|
|
{
|
|
self cleanup_sticky();
|
|
}
|
|
}
|
|
|
|
remove_sticky_on_respawn( firing_player )
|
|
{
|
|
self endon( "exploded" );
|
|
|
|
firing_player waittill( "spawned_player" );
|
|
|
|
if( isDefined( self ) )
|
|
{
|
|
self cleanup_sticky();
|
|
}
|
|
}
|
|
|
|
cleanup_sticky()
|
|
{
|
|
StopFXOnTag( getfx( "mdl_sticky_blinking" ), self.fx_origin, "tag_origin" );
|
|
self Delete();
|
|
}
|
|
|
|
microdrone_think(firing_player)
|
|
{
|
|
self endon( "death" );
|
|
|
|
firing_player endon( "death" );
|
|
firing_player endon( "disconnect" );
|
|
firing_player endon( "faux_spawn" );
|
|
|
|
start_origin = self.origin;
|
|
|
|
// seems missiles don't move on the first frame, so need to wait 2 frames to get the velocity
|
|
self get_differentiated_velocity();
|
|
wait .05;
|
|
self get_differentiated_velocity();
|
|
wait .05;
|
|
elapsed_time = .1;
|
|
|
|
init_vel = self get_differentiated_velocity();
|
|
while(true)
|
|
{
|
|
// must call every frame to get accurate results
|
|
cur_vel = self get_differentiated_velocity();
|
|
|
|
set_target = false;
|
|
if(elapsed_time >= CONST_begin_homing_time)
|
|
{
|
|
best_target = microdrone_get_best_target(start_origin, VectorNormalize(init_vel), cur_vel, firing_player);
|
|
if(IsDefined(best_target))
|
|
{
|
|
self Missile_SetTargetEnt(best_target, microdrone_get_target_offset(best_target));
|
|
set_target = true;
|
|
|
|
// so that if we lose the lock, we will start dropping from our current velocity
|
|
init_vel = cur_vel;
|
|
|
|
/#
|
|
//Line(self.origin, best_target.origin + microdrone_get_target_offset(best_target), (0, 1, 0));
|
|
#/
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/#
|
|
//Line(self.origin, self.origin + (0, 0, 100), (0, 1, 0));
|
|
#/
|
|
}
|
|
|
|
if(!set_target)
|
|
{
|
|
// simulate drop. We could do this in projectile steering code (and multiplayer would want to do that), but this is simpler.
|
|
desired_dir = VectorNormalize(init_vel + (0, 0, -.5 * CONST_drop_accel * Squared(elapsed_time)));
|
|
self Missile_SetTargetPos(self.origin + desired_dir * 10000);
|
|
}
|
|
|
|
wait .05;
|
|
elapsed_time += .05;
|
|
}
|
|
}
|
|
|
|
microdrone_get_best_target(start_origin, dir, cur_vel, firing_player)
|
|
{
|
|
min_dot_from_grenade = Cos(CONST_max_homing_angle_from_grenade);
|
|
|
|
best_target = undefined;
|
|
best_target_dot = Cos(CONST_max_homing_angle_from_grenade);
|
|
foreach( target in level.players )
|
|
{
|
|
if( target == firing_player )
|
|
continue;
|
|
|
|
if( target.team == firing_player.team )
|
|
continue;
|
|
|
|
target_pos = microdrone_get_target_pos(target);
|
|
dot = VectorDot(VectorNormalize(cur_vel), VectorNormalize(target_pos - self.origin));
|
|
if(dot > best_target_dot)
|
|
{
|
|
|
|
if(BulletTracePassed(self.origin, target_pos, false, target))
|
|
{
|
|
best_target = target;
|
|
best_target_dot = dot;
|
|
}
|
|
else
|
|
{
|
|
/#
|
|
//result = BulletTrace(self.origin, target_pos, false, target);
|
|
//Assert(!IsDefined(result["entity"]) || result["entity"] != target);
|
|
//line(self.origin, result["position"], (1, 0, 0));
|
|
#/
|
|
}
|
|
}
|
|
}
|
|
|
|
return best_target;
|
|
}
|
|
|
|
is_enemy_target(target, firing_player)
|
|
{
|
|
team = undefined;
|
|
|
|
if(IsAi(target))
|
|
team = target.team;
|
|
else if(IsDefined(target.script_team))
|
|
team = target.script_team;
|
|
|
|
return IsEnemyTeam(team, firing_player.team);
|
|
}
|
|
|
|
microdrone_get_target_pos(target)
|
|
{
|
|
return target GetPointInBounds(0, 0, 0);
|
|
}
|
|
|
|
microdrone_get_target_offset(target)
|
|
{
|
|
return microdrone_get_target_pos(target) - target.origin;
|
|
}
|
|
|
|
get_differentiated_velocity()
|
|
{
|
|
self differentiate_motion();
|
|
return self.differentiated_velocity;
|
|
}
|
|
|
|
differentiate_motion()
|
|
{
|
|
time = GetTime() * .001;
|
|
|
|
if(!IsDefined(self.differentiated_last_update))
|
|
{
|
|
self.differentiated_last_update = time;
|
|
self.differentiated_last_origin = self.origin;
|
|
self.differentiated_last_velocity = (0, 0, 0);
|
|
self.differentiated_last_acceleration = (0, 0, 0);
|
|
self.differentiated_jerk = (0, 0, 0);
|
|
self.differentiated_acceleration = (0, 0, 0);
|
|
self.differentiated_velocity = (0, 0, 0);
|
|
self.differentiated_speed = 0;
|
|
}
|
|
else if(self.differentiated_last_update != time)
|
|
{
|
|
dt = time - self.differentiated_last_update;
|
|
self.differentiated_last_update = time;
|
|
self.differentiated_jerk = (self.differentiated_acceleration - self.differentiated_last_acceleration) / dt;
|
|
self.differentiated_last_acceleration = self.differentiated_acceleration;
|
|
self.differentiated_acceleration = (self.differentiated_velocity - self.differentiated_last_velocity) / dt;
|
|
self.differentiated_last_velocity = self.differentiated_velocity;
|
|
self.differentiated_velocity = (self.origin - self.differentiated_last_origin) / dt;
|
|
self.differentiated_last_origin = self.origin;
|
|
self.differentiated_speed = Length(self.differentiated_velocity);
|
|
}
|
|
} |