s1-scripts-dev/raw/maps/mp/_microdronelauncher.gsc
2025-05-21 16:23:17 +02:00

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);
}
}