1022 lines
27 KiB
Plaintext
1022 lines
27 KiB
Plaintext
#include maps\mp\_utility;
|
|
#include common_scripts\utility;
|
|
#include maps\mp\gametypes\_hud_util;
|
|
|
|
// threatDetection style options are:
|
|
// glow -- glowy vfx blobs
|
|
// model -- script model of the threat that is posed
|
|
// vfx_model -- a vfx posed model
|
|
// attached_glow -- glowy vfx blobs that are attached to the players
|
|
// stencil_outline -- red dot/line things in screen space stenciled to the player's shape
|
|
|
|
init()
|
|
{
|
|
level._threatdetection = SpawnStruct();
|
|
level._threatdetection.default_style = "stencil_outline";
|
|
|
|
SetDevDvarIfUninitialized( "threat_detection_mark_time", 3 );
|
|
SetDevDvarIfUninitialized( "threat_detection_highlight_style", level._threatdetection.default_style );
|
|
|
|
level._threatdetection.activeStyle = GetDvar( "threat_detection_highlight_style", level._threatdetection.default_style );
|
|
level thread onPlayerConnect();
|
|
level thread watchAgentSpawn();
|
|
}
|
|
|
|
changeThreatStyle( threatStyle )
|
|
{
|
|
if( threatStyle == level._threatdetection.activeStyle )
|
|
return;
|
|
|
|
//turn everything off
|
|
foreach( p in level.players )
|
|
{
|
|
//model and vfx_model
|
|
if( IsDefined( p._threatdetection.mark_enemy_model ) )
|
|
p._threatdetection.mark_enemy_model Delete();
|
|
|
|
if( IsDefined( p._threatdetection.mark_friendly_model ) )
|
|
p._threatdetection.mark_friendly_model Delete();
|
|
|
|
//vfx
|
|
if( IsDefined( p.mark_fx ) && IsDefined( p.mark_fx.fx_ent ))
|
|
{
|
|
foreach( i, fx in p.mark_fx.fx_ent )
|
|
{
|
|
if( IsDefined( fx.enemyMarker ) )
|
|
fx.enemyMarker Delete();
|
|
|
|
if( IsDefined( fx.friendlyMarker ) )
|
|
fx.friendlyMarker Delete();
|
|
|
|
if( IsDefined( fx.enemyLosMarker ) )
|
|
fx.enemyLosMarker Delete();
|
|
|
|
if( IsDefined( fx.friendlyLosMarker ) )
|
|
fx.friendlyLosMarker Delete();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//turn on the new one
|
|
foreach( p in level.players )
|
|
p threat_init( threatStyle );
|
|
|
|
level._threatdetection.activeStyle = threatStyle;
|
|
}
|
|
|
|
GetThreatStyle()
|
|
{
|
|
threatStyle = GetDvar( "threat_detection_highlight_style", level._threatdetection.default_style );
|
|
if( threatStyle != level._threatdetection.activeStyle )
|
|
changeThreatStyle( threatStyle );
|
|
return threatStyle;
|
|
}
|
|
|
|
|
|
onPlayerConnect()
|
|
{
|
|
for(;;)
|
|
{
|
|
level waittill("connected", player);
|
|
player thread onPlayerSpawned();
|
|
}
|
|
}
|
|
|
|
watchAgentSpawn()
|
|
{
|
|
while (true)
|
|
{ // note that this could miss an agent if multiple agents are spawned the same frame.
|
|
level waittill( "spawned_agent", agent );
|
|
agent._threatdetection = SpawnStruct();
|
|
agent._threatdetection.showlist = [];
|
|
agent thread onAgentSpawned();
|
|
}
|
|
}
|
|
|
|
onAgentSpawned()
|
|
{
|
|
self endon("death");
|
|
self childthread monitorThreatHighlight();
|
|
self childthread cleanUpOnDeath();
|
|
}
|
|
|
|
//called from player connect
|
|
onPlayerSpawned()
|
|
{
|
|
self endon("disconnect");
|
|
|
|
self._threatdetection = SpawnStruct();
|
|
self._threatdetection.showlist = [];
|
|
self waittill( "spawned_player" );
|
|
|
|
childthread monitorThreatHighlight();
|
|
childthread cleanUpOnDeath();
|
|
|
|
//if( self != level.players[0] )
|
|
//{
|
|
//childthread debugHelper();
|
|
//}
|
|
|
|
// Monitors if/when threat overlay should be displayed.
|
|
childthread monitorThreatHighlightNotification();
|
|
|
|
//for respawns
|
|
while( 1 )
|
|
{
|
|
self waittill( "spawned_player" );
|
|
|
|
threatStyle = GetThreatStyle();
|
|
if( threatStyle == "attached_glow" )
|
|
visitFXEnt( ::visitorRelink, ::getHostileMarker, undefined );
|
|
}
|
|
}
|
|
|
|
|
|
// Monitors if/when threat overlay should be displayed.
|
|
monitorThreatHighlightNotification()
|
|
{
|
|
// Create a new hud element on client for the overlay. Set initially to have an alpha of 0.0 so it's not visible.
|
|
notification_overlay_element = NewClientHudElem( self );
|
|
notification_overlay_element.x = 0;
|
|
notification_overlay_element.y = 0;
|
|
notification_overlay_element.alignX = "left";
|
|
notification_overlay_element.alignY = "top";
|
|
notification_overlay_element.horzAlign = "fullscreen";
|
|
notification_overlay_element.vertAlign = "fullscreen";
|
|
notification_overlay_element SetShader( "paint_overlay", 640, 480 );
|
|
notification_overlay_element.alpha = 0.0;
|
|
notification_overlay_element.color = ( 0, 0, 0 );
|
|
notification_overlay_element.sort = -3;
|
|
|
|
// Make sure nothing is getting set unexpectedly elsewhere.
|
|
Assert( !IsDefined(notification_overlay_element.hidden));
|
|
|
|
notification_overlay_element.hidden = true;
|
|
|
|
FadeInTime = 0.5;
|
|
FadeOutTime = .3;
|
|
|
|
while(1)
|
|
{
|
|
|
|
AssertEx(IsDefined(self._threatdetection), "_threatdetection isn't defined");
|
|
|
|
// Check if the showlist isn't empty (value updated in monitorThreatHighlight())
|
|
if(self._threatdetection.showlist.size != 0)
|
|
{
|
|
// If hud element (overlay) is hidden, branch out a thread to fade the overlay in and out.
|
|
if( notification_overlay_element.hidden )
|
|
{
|
|
notification_overlay_element.hidden = false;
|
|
notification_overlay_element childthread threatNotificationOverlayFlash( FadeInTime, FadeOutTime );
|
|
}
|
|
}
|
|
else // If showlist is empty...
|
|
{
|
|
// ...and the hud element is visible, tell the looping thread to stop fading the overlay in and out.
|
|
if(!notification_overlay_element.hidden)
|
|
{
|
|
notification_overlay_element.hidden = true;
|
|
notification_overlay_element notify( "stop_overlay_flash" );
|
|
|
|
// If the overlay wasn't completely faded out, force it to fade out quickly.
|
|
if(notification_overlay_element.alpha > 0.0)
|
|
{
|
|
notification_overlay_element FadeOverTime( FadeOutTime );
|
|
notification_overlay_element.color = ( 0, 0, 0 );
|
|
notification_overlay_element.alpha = 0.0;
|
|
wait( FadeOutTime );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
wait(0.05);
|
|
}
|
|
}
|
|
|
|
// Called on the overlay hud element in monitorThreatHighlightNotification() to cause it to fade in and out until notified to stop.
|
|
threatNotificationOverlayFlash( FadeInTime, FadeOutTime )
|
|
{
|
|
self endon( "stop_overlay_flash" );
|
|
|
|
self FadeOverTime( FadeInTime );
|
|
self.color = ( 1, 1, 1 );
|
|
self.alpha = 1.0;
|
|
|
|
/*while(1)
|
|
{
|
|
self FadeOverTime( FadeInTime );
|
|
self.alpha = 1.0;
|
|
wait( FadeInTime );
|
|
self FadeOverTime( FadeOutTime );
|
|
self.alpha = 0.0;
|
|
wait( FadeOutTime );
|
|
}*/
|
|
}
|
|
|
|
debugHelper()
|
|
{
|
|
while( 1 )
|
|
{
|
|
dist = Distance( self.origin, level.players[0].origin );
|
|
Print3d( self.origin + (0,0,64), dist );
|
|
thread draw_line_for_time( level.players[0].origin, self.origin, 1,1,1, 0.3 );
|
|
if( isdefined( self._threatdetection.mark_enemy_model ) )
|
|
thread draw_line_for_time( level.players[0].origin, self._threatdetection.mark_enemy_model.origin, 1,1,1, 0.3 );
|
|
wait 0.3;
|
|
}
|
|
}
|
|
|
|
|
|
cleanUpOnDeath()
|
|
{
|
|
self endon("disconnect");
|
|
|
|
while( 1 )
|
|
{
|
|
self waittill("death");
|
|
self removeThreatEvents();
|
|
}
|
|
}
|
|
|
|
removeThreatEvents()
|
|
{
|
|
foreach(player in level.players)
|
|
{
|
|
foreach( obj in player._threatdetection.showlist )
|
|
{
|
|
if(obj.player == self)
|
|
{
|
|
obj.endTime = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
threatStyle = GetThreatStyle();
|
|
if( threatStyle == "attached_glow" )
|
|
{
|
|
visitFXEnt( ::visitorHideAll, ::getHostileMarker, undefined );
|
|
}
|
|
}
|
|
|
|
detection_highlight_hud_effect_on( player, duration, bLessIntense )
|
|
{
|
|
Assert( IsDefined( player ) );
|
|
|
|
radar_highlight = NewClientHudElem( player );
|
|
|
|
if( isDefined ( bLessIntense ) && bLessIntense )
|
|
radar_highlight.color = (0.1, 0.0015, 0.0015);
|
|
else
|
|
radar_highlight.color = (1.0, 0.015, 0.015);
|
|
|
|
radar_highlight.alpha = 1.0;
|
|
|
|
radar_highlight SetRadarHighlight( duration );
|
|
|
|
return radar_highlight;
|
|
}
|
|
|
|
detection_highlight_hud_effect_off( radar_highlight )
|
|
{
|
|
if(isDefined(radar_highlight))
|
|
{
|
|
radar_highlight Destroy();
|
|
}
|
|
}
|
|
|
|
detection_highlight_hud_effect( player, duration, bLessIntense, playerEndonString )
|
|
{
|
|
radar_highlight = detection_highlight_hud_effect_on( player, duration, bLessIntense );
|
|
|
|
if ( IsDefined( playerEndonString ) )
|
|
player waittill_notify_or_timeout( playerEndonString, duration );
|
|
else
|
|
wait duration;
|
|
|
|
detection_highlight_hud_effect_off( radar_highlight );
|
|
}
|
|
|
|
detection_grenade_hud_effect( player, position, duration, radius )
|
|
{
|
|
Assert( IsDefined( player ) );
|
|
|
|
radar_ping = NewHudElem();
|
|
|
|
radar_ping.x = position[0];
|
|
radar_ping.y = position[1];
|
|
radar_ping.z = position[2];
|
|
|
|
SetDevDvarIfUninitialized("scr_paintexplosionalpha",1.0);
|
|
SetDevDvarIfUninitialized("scr_paintexplosionred",1.0);
|
|
SetDevDvarIfUninitialized("scr_paintexplosiongreen",0.015);
|
|
SetDevDvarIfUninitialized("scr_paintexplosionblue",0.015);
|
|
SetDevDvarIfUninitialized("scr_paintexplosionwidth",500);
|
|
|
|
radar_ping.color = (GetDvarFloat("scr_paintexplosionred"), GetDvarFloat("scr_paintexplosiongreen"), GetDvarFloat("scr_paintexplosionblue"));
|
|
radar_ping.alpha = GetDvarFloat("scr_paintexplosionalpha"); // mp uses 5 bits to store alpha
|
|
|
|
width = GetDvarInt("paintexplosionwidth");
|
|
// doubling radius and duration so we have no chance of it cycling
|
|
radar_ping SetRadarPing(int(radius + width / 2), int(width), duration + .05);
|
|
// /# IPrintLn("PING"); #/
|
|
wait duration;
|
|
// /# IPrintLn("PONG"); #/
|
|
if(isDefined(radar_ping))
|
|
{
|
|
radar_ping Destroy();
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=============
|
|
///ScriptDocBegin
|
|
"Name: exo_ping_hud_effect( <position> , <duration> , <radius> , <player>, <bLessIntense> )"
|
|
"Summary: creates an effect for the Exo Ping tactical equipment."
|
|
"Module: Entity"
|
|
"CallOn: a player"
|
|
"MandatoryArg: <position>: the position of the effect"
|
|
"MandatoryArg: <duration>: the duraction of the effect"
|
|
"MandatoryArg: <radius>: the radius of the effect"
|
|
"OptionalArg: <player>: the client to show this effect to. If undefined, the effect shows to all clients."
|
|
"OptionalArg: <bLessIntense>: less intense version of the effect. If false or undefined, uses the default color."
|
|
"Example: thread maps\mp\_threatdetection::exo_ping_hud_effect( self.origin + ( 0, 0, 40 ), EXO_PING_DURATION, EXO_PING_RANGE, self, true );"
|
|
"SPMP: singleplayer"
|
|
///ScriptDocEnd
|
|
=============
|
|
*/
|
|
exo_ping_hud_effect( position, duration, radius, player, bLessIntense )
|
|
{
|
|
radar_ping = undefined;
|
|
if ( IsDefined( player ) )
|
|
radar_ping = NewClientHudElem( player );
|
|
else
|
|
radar_ping = NewHudElem();
|
|
|
|
radar_ping.x = position[0];
|
|
radar_ping.y = position[1];
|
|
radar_ping.z = position[2];
|
|
|
|
SetDevDvarIfUninitialized( "scr_exopingwidth", 100 );
|
|
|
|
if( isDefined( bLessIntense ) && bLessIntense )
|
|
radar_ping.color = ( 0.05, 0.05, 0.05 );
|
|
else
|
|
radar_ping.color = ( 0.8, 0.8, 0.8 );
|
|
|
|
radar_ping.alpha = 0.05; // mp uses 5 bits to store alpha
|
|
|
|
width = GetDvarInt( "scr_exopingwidth", 100 );
|
|
// doubling radius and duration so we have no chance of it cycling
|
|
radar_ping SetRadarPing( int( radius ), int( width ), duration + .05 );
|
|
wait duration;
|
|
if(isDefined(radar_ping))
|
|
{
|
|
radar_ping Destroy();
|
|
}
|
|
}
|
|
|
|
|
|
addThreatEvent( players_arr, event_duration_sec, event_type, updateHostile, updateFriendly, bPlaySound )
|
|
{
|
|
if( !IsAlive( self ) )
|
|
return;
|
|
|
|
currTime = GetTime();
|
|
endTime = currTime + ( event_duration_sec * 1000 );
|
|
losEndTime = endTime - ( 9 * ( event_duration_sec * 1000 ) / 10 );
|
|
|
|
threatStyle = GetThreatStyle();
|
|
|
|
|
|
if( endTime - losEndTime < 250 )
|
|
losEndTime = 250 + currTime;
|
|
|
|
if( threatStyle == "model" )
|
|
{
|
|
losEndTime = currTime;
|
|
}
|
|
else if( threatStyle == "vfx_model" )
|
|
{
|
|
losEndTime = currTime;
|
|
}
|
|
else if( threatStyle == "attached_glow" )
|
|
{
|
|
losEndTime = endTime; //attached glow stays glowy
|
|
}
|
|
else if( threatStyle == "stencil_outline" )
|
|
{
|
|
losEndTime = endTime;
|
|
}
|
|
|
|
foreach( p in players_arr )
|
|
{
|
|
//if( p == self )
|
|
// continue;
|
|
|
|
found = false;
|
|
foreach( obj in self._threatdetection.showlist )
|
|
{
|
|
if( obj.player == p )
|
|
{
|
|
//only update the time if it would last longer
|
|
if( endTime > obj.endTime )
|
|
{
|
|
obj.endTime = endTime;
|
|
obj.losEndTime = losEndTime;
|
|
obj.eventType = event_type;
|
|
}
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !found )
|
|
{
|
|
index = self._threatdetection.showlist.size;
|
|
|
|
self._threatdetection.showlist[ index ] = SpawnStruct();
|
|
self._threatdetection.showlist[ index ].player = p;
|
|
self._threatdetection.showlist[ index ].endTime = endTime;
|
|
self._threatdetection.showlist[ index ].losEndTime = losEndTime;
|
|
self._threatdetection.showlist[ index ].eventType = event_type;
|
|
|
|
if (IsPlayer(self))
|
|
{
|
|
if( !isDefined( bPlaySound ) || bPlaySound )
|
|
self PlayLocalSound( "flag_spawned" ); // Play the flag_spawned oneshot any time someone is added to the showlist.
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsPlayer(self))
|
|
{
|
|
if( updateFriendly )
|
|
visitFXEnt( ::visitorUpdateMarkerPos, ::getFriendlyMarker, undefined );
|
|
|
|
if( updateHostile )
|
|
visitFXEnt( ::visitorUpdateMarkerPos, ::getHostileMarker, undefined );
|
|
}
|
|
}
|
|
|
|
stopThreatEventType( eventType )
|
|
{
|
|
foreach( obj in self._threatdetection.showlist )
|
|
{
|
|
if ( obj.eventType == eventType )
|
|
{
|
|
obj.endTime = 0;
|
|
}
|
|
}
|
|
|
|
threatStyle = GetThreatStyle();
|
|
if( threatStyle == "attached_glow" )
|
|
{
|
|
visitFXEnt( ::visitorHideAll, ::getHostileMarker, undefined );
|
|
}
|
|
}
|
|
|
|
visitFXEnt( visitorFn, accessorFn, show_to )
|
|
{
|
|
threatStyle = GetThreatStyle();
|
|
if( threatStyle == "glow" )
|
|
{
|
|
assert( IsPlayer( self ) );
|
|
foreach( i, fx in self.mark_fx.fx_ent )
|
|
{
|
|
assert( IsDefined( [[accessorFn]]( fx ) ) );
|
|
[[visitorFn]]( [[accessorFn]]( fx ), show_to, level._threatdetection.fx_data[i][0] );
|
|
}
|
|
}
|
|
else if( threatStyle == "model" )
|
|
{
|
|
assert( IsPlayer( self ) );
|
|
assert( IsDefined( [[accessorFn]]( self._threatdetection ) ) );
|
|
[[visitorFn]]( [[accessorFn]]( self._threatdetection ), show_to, "tag_origin" );
|
|
}
|
|
else if( threatStyle == "vfx_model" )
|
|
{
|
|
assert( IsPlayer( self ) );
|
|
assert( IsDefined( [[accessorFn]]( self._threatdetection ) ) );
|
|
[[visitorFn]]( [[accessorFn]]( self._threatdetection ), show_to, "tag_origin" );
|
|
}
|
|
else if( threatStyle == "attached_glow" )
|
|
{
|
|
assert( IsPlayer( self ) );
|
|
foreach( i, fx in self.mark_fx.fx_ent )
|
|
{
|
|
assert( IsDefined( [[accessorFn]]( fx ) ) );
|
|
[[visitorFn]]( [[accessorFn]]( fx ), show_to, level._threatdetection.fx_data[i][0] );
|
|
}
|
|
}
|
|
else if( threatStyle == "stencil_outline" )
|
|
{
|
|
[[visitorFn]]( self, show_to, "tag_origin" );
|
|
}
|
|
else
|
|
{
|
|
AssertEx( 0, "unknown threat style " + threatStyle + ". i dont know how to set it up" );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
visitorRelink( member, player, bone )
|
|
{
|
|
member Unlink();
|
|
member.origin = self GetTagOrigin( bone );
|
|
member.angles = self GetTagAngles( bone );
|
|
member LinkTo( self, bone );
|
|
wait .05;
|
|
playFXOnTag( member.fx, member, "tag_origin" );
|
|
}
|
|
|
|
|
|
visitorHideAll( member, player, bone )
|
|
{
|
|
threatStyle = GetThreatStyle();
|
|
if( threatStyle == "attached_glow" )
|
|
{
|
|
StopFXOnTag( member.fx, member, "tag_origin" );
|
|
}
|
|
}
|
|
|
|
visitorUpdateMarkerPos( member, player, bone )
|
|
{
|
|
threatStyle = GetThreatStyle();
|
|
member.origin = self GetTagOrigin( bone );
|
|
member.angles = self GetTagAngles( bone );
|
|
if( threatStyle == "glow" )
|
|
{
|
|
triggerFx( member );
|
|
}
|
|
else if( threatStyle == "model" )
|
|
{
|
|
//update model pose now
|
|
desired_pose = "mp_hud_" + self GetStance() + "_char";
|
|
assert( isdefined( member ) );
|
|
is_hostile = ( member != self._threatDetection.mark_friendly_model );
|
|
|
|
if( is_hostile )
|
|
{
|
|
desired_pose += "_hostile";
|
|
}
|
|
|
|
current_pose = member.model;
|
|
|
|
if( desired_pose != current_pose )
|
|
member SetModel( desired_pose );
|
|
}
|
|
else if( threatStyle == "vfx_model" )
|
|
{
|
|
switch( self GetStance() )
|
|
{
|
|
case "prone":
|
|
desired_pose = "threat_detect_model_prone";
|
|
break;
|
|
case "crouch":
|
|
desired_pose = "threat_detect_model_crouch";
|
|
break;
|
|
case "stand":
|
|
//fallthrough
|
|
default:
|
|
desired_pose = "threat_detect_model_stand";//self.stance;
|
|
break;
|
|
}
|
|
|
|
assert( isdefined( member ) );
|
|
is_hostile = ( member != self._threatDetection.mark_friendly_model );
|
|
current_pose = self._threatdetection.friendly_pose;
|
|
|
|
if( is_hostile )
|
|
{
|
|
desired_pose += "_hostile";
|
|
current_pose = self._threatdetection.hostile_pose;
|
|
}
|
|
|
|
assert( IsDefined( current_pose ) );
|
|
if( current_pose != desired_pose )
|
|
{
|
|
forward = AnglesToForward( self.angles );
|
|
up = AnglesToUp( self.angles );
|
|
if( is_hostile )
|
|
{
|
|
self._threatdetection.mark_enemy_model delete();
|
|
self._threatdetection.mark_enemy_model = SpawnFx( GetFX( desired_pose ), self.origin, forward, up );
|
|
self._threatdetection.mark_enemy_model hide();
|
|
self._threatdetection.hostile_pose = desired_pose;
|
|
}
|
|
else
|
|
{
|
|
self._threatdetection.mark_friendly_model delete();
|
|
self._threatdetection.mark_friendly_model = SpawnFx( GetFX( desired_pose ), self.origin, forward, up );
|
|
self._threatdetection.mark_friendly_model hide();
|
|
self._threatdetection.friendly_pose = desired_pose;
|
|
}
|
|
}
|
|
|
|
if( is_hostile )
|
|
TriggerFX( self._threatdetection.mark_enemy_model );
|
|
else
|
|
TriggerFX( self._threatdetection.mark_friendly_model );
|
|
}
|
|
else if( threatStyle == "attached_glow" )
|
|
{
|
|
//do nothing on purpose
|
|
}
|
|
else if( threatStyle == "stencil_outline" )
|
|
{
|
|
//do nothing on purpose
|
|
}
|
|
else
|
|
{
|
|
AssertEx( 0, "unknown threat style " + threatStyle + ". i dont know how to set it up" );
|
|
}
|
|
}
|
|
|
|
|
|
getHostileMarker( obj )
|
|
{
|
|
threatStyle = GetThreatStyle();
|
|
if( threatStyle == "glow" )
|
|
return obj.enemyMarker;
|
|
else if( threatStyle == "model" )
|
|
return obj.mark_enemy_model;
|
|
else if( threatStyle == "vfx_model" )
|
|
return obj.mark_enemy_model;
|
|
else if( threatStyle == "attached_glow" )
|
|
return obj;
|
|
else if( threatStyle == "stencil_outline" )
|
|
return obj;
|
|
else
|
|
{
|
|
AssertEx( 0, "unknown threat style " + threatStyle + ". i dont know how to set it up" );
|
|
}
|
|
}
|
|
|
|
getFriendlyMarker( obj )
|
|
{
|
|
threatStyle = GetThreatStyle();
|
|
if( threatStyle == "glow" )
|
|
return obj.friendlyMarker;
|
|
else if( threatStyle == "model" )
|
|
return obj.mark_friendly_model;
|
|
else if( threatStyle == "vfx_model" )
|
|
return obj.mark_friendly_model;
|
|
else
|
|
{
|
|
AssertEx( 0, "unknown threat style " + threatStyle + ". i dont know how to set it up" );
|
|
}
|
|
}
|
|
|
|
getFriendlyLOSMarker( obj )
|
|
{
|
|
threatStyle = GetThreatStyle();
|
|
if( threatStyle == "glow" )
|
|
return obj.friendlyLOSMarker;
|
|
else if( threatStyle == "model" )
|
|
return obj.mark_friendly_model;
|
|
else if( threatStyle == "vfx_model" )
|
|
return obj.mark_friendly_model;
|
|
else
|
|
{
|
|
AssertEx( 0, "unknown threat style " + threatStyle + ". i dont know how to set it up" );
|
|
}
|
|
}
|
|
|
|
getHostileLOSMarker( obj )
|
|
{
|
|
threatStyle = GetThreatStyle();
|
|
if( threatStyle == "glow" )
|
|
return obj.enemyLOSMarker;
|
|
else if( threatStyle == "model" )
|
|
return obj.mark_enemy_model;
|
|
else if( threatStyle == "vfx_model" )
|
|
return obj.mark_enemy_model;
|
|
else if( threatStyle == "attached_glow" )
|
|
return obj;
|
|
else if( threatStyle == "stencil_outline" )
|
|
return obj;
|
|
else
|
|
{
|
|
AssertEx( 0, "unknown threat style " + threatStyle + ". i dont know how to set it up" );
|
|
}
|
|
}
|
|
|
|
//left for an exmple
|
|
visitHideAllMarkers( memberArr, player, bone )
|
|
{
|
|
assert( !isdefined( player ) );
|
|
foreach( m in memberArr )
|
|
{
|
|
m Hide();
|
|
}
|
|
}
|
|
|
|
accessAllMarkers( obj )
|
|
{
|
|
assert( isdefined( obj) );
|
|
return [obj.friendlyMarker, obj.enemyMarker, obj.friendlyLOSMarker, obj.enemyLOSMarker];
|
|
}
|
|
|
|
getNormalDirectionVec( raw_vec )
|
|
{
|
|
return VectorNormalize( flat_origin( raw_vec ) );
|
|
}
|
|
|
|
monitorThreatHighlight()
|
|
{
|
|
self threat_init( GetThreatStyle() );
|
|
|
|
height_offset = ( 0, 0, 32 );
|
|
all_hidden = false;
|
|
while( 1 )
|
|
{
|
|
wait .05;
|
|
currTime = GetTime();
|
|
|
|
anyoneNeedsDraw = false;
|
|
foreach( obj in self._threatdetection.showlist )
|
|
{
|
|
if( obj.endTime >= currTime )
|
|
{
|
|
if( !IsDefined( obj.player ) )
|
|
{
|
|
self._threatdetection.showlist = array_remove( self._threatdetection.showlist, obj );
|
|
continue;
|
|
}
|
|
|
|
obj.los = false;
|
|
|
|
//see if we're even in the view cone for the guy on the list
|
|
forward = getNormalDirectionVec( anglesToForward( obj.player.angles ) );
|
|
toTarget = getNormalDirectionVec( self.origin - obj.player.origin );
|
|
cos = VectorDot( toTarget, forward );
|
|
//we will cast against +/- 90
|
|
if( cos < 0 )
|
|
continue;
|
|
|
|
if( check_los( obj ) )
|
|
{
|
|
//use LOS vfx
|
|
obj.los = true;
|
|
|
|
//if we're in LOS we have a different end time
|
|
if( obj.losEndTime <= currTime )
|
|
{
|
|
self._threatdetection.showlist = array_remove( self._threatdetection.showlist, obj );
|
|
continue;
|
|
}
|
|
}
|
|
anyoneNeedsDraw = true;
|
|
}
|
|
else
|
|
{
|
|
self._threatdetection.showlist = array_remove( self._threatdetection.showlist, obj );
|
|
}
|
|
}
|
|
|
|
threatStyle = GetThreatStyle();
|
|
if( !all_hidden )
|
|
{
|
|
all_hidden = true;
|
|
if( threatStyle == "glow" )
|
|
{
|
|
foreach( i, fx in self.mark_fx.fx_ent )
|
|
{
|
|
fx.enemyMarker hide();
|
|
fx.friendlyMarker hide();
|
|
fx.enemyLosMarker hide();
|
|
fx.friendlyLosMarker hide();
|
|
}
|
|
}
|
|
else if( threatStyle == "model" )
|
|
{
|
|
self._threatdetection.mark_friendly_model hide();
|
|
self._threatdetection.mark_enemy_model hide();
|
|
}
|
|
else if( threatStyle == "vfx_model" )
|
|
{
|
|
self._threatdetection.mark_friendly_model hide();
|
|
self._threatdetection.mark_enemy_model hide();
|
|
}
|
|
else if( threatStyle == "attached_glow" )
|
|
{
|
|
foreach( i, obj in self.mark_fx.fx_ent )
|
|
{
|
|
StopFXOnTag( obj.fx, obj, "tag_origin" );
|
|
obj hide();
|
|
}
|
|
}
|
|
else if( threatStyle == "stencil_outline" )
|
|
{
|
|
self clearThreatDetected();
|
|
}
|
|
else
|
|
{
|
|
AssertEx( 0, "unknown threat style " + threatStyle + ". i dont know how to set it up" );
|
|
}
|
|
|
|
}
|
|
if( !anyoneNeedsDraw )
|
|
continue;
|
|
|
|
//walk the list of players and show to who we want
|
|
foreach( p in self._threatdetection.showlist )
|
|
{
|
|
assert( isdefined( p ) );
|
|
if( p.los )
|
|
{
|
|
assert( p.losEndTime >= currTime );
|
|
showThreat( p.player, ::getFriendlyLOSMarker, ::getHostileLOSMarker, ::visitorUpdateLOSMarker );
|
|
prepare_show_threat( all_hidden, threatStyle, p.player );//playfxontag needs to be after the show of the ent
|
|
all_hidden = false;
|
|
}
|
|
else
|
|
{
|
|
assert( p.endTime >= currTime );
|
|
//if we cant see our target make sure we cant see the marker object
|
|
result = BulletTrace( p.player.origin + height_offset, self.origin + height_offset, true, p.player );
|
|
|
|
if( result["fraction"] < 1 && !isplayer(result["entity"]) ) // we can't see the blob
|
|
{
|
|
showThreat( p.player, ::getFriendlyMarker, ::getHostileMarker, ::visitorShowToPlayer );
|
|
prepare_show_threat( all_hidden, threatStyle, p.player );//playfxontag needs to be after the show of the ent
|
|
all_hidden = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
prepare_show_threat( already_drawn, threatStyle, player )
|
|
{
|
|
if( already_drawn ) //meaning we have not shown to anyone yet this frame
|
|
{
|
|
if( threatStyle == "attached_glow" )
|
|
{
|
|
assert( IsPlayer( self ) );
|
|
showThreat( player, ::getFriendlyLOSMarker, ::getHostileLOSMarker, ::visitorRetriggerFX );
|
|
}
|
|
}
|
|
}
|
|
|
|
visitorRetriggerFX( member, player, bone )
|
|
{
|
|
/#
|
|
threatStyle = GetThreatStyle();
|
|
assert(threatStyle == "attached_glow" );
|
|
#/
|
|
//StopFXOnTag( member.fx, member, "tag_origin" );//stop is happening in the hide of monitorThreatHighlight
|
|
PlayFXOnTag( member.fx, member, "tag_origin" );
|
|
}
|
|
|
|
check_los( obj )
|
|
{
|
|
//temp to solve problem if player is behind partial cover.
|
|
if( BulletTracePassed( obj.player GetEye(), self GetEye(), false, obj.player ) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
threat_init( threatStyle )
|
|
{
|
|
mark_fx_struct = SpawnStruct();
|
|
mark_fx_struct.fx_ent = [];
|
|
|
|
if( threatStyle == "glow" )
|
|
{
|
|
foreach ( i,fx in level._threatdetection.fx_data )
|
|
{
|
|
mark_fx_ent = SpawnStruct();
|
|
mark_fx_ent.origin = self GetTagOrigin( fx[0] );
|
|
mark_fx_ent.angles = self GetTagAngles( fx[0] );
|
|
|
|
mark_fx_ent.enemyMarker = SpawnFx( fx[1], mark_fx_ent.origin );
|
|
triggerFx( mark_fx_ent.enemyMarker );
|
|
mark_fx_ent.enemyMarker hide();
|
|
|
|
mark_fx_ent.enemyLosMarker = SpawnFx( fx[3], mark_fx_ent.origin );
|
|
triggerFx( mark_fx_ent.enemyLosMarker );
|
|
mark_fx_ent.enemyLosMarker hide();
|
|
|
|
mark_fx_ent.friendlyMarker = SpawnFx( fx[2], mark_fx_ent.origin );
|
|
triggerFx( mark_fx_ent.friendlyMarker );
|
|
mark_fx_ent.friendlyMarker hide();
|
|
|
|
mark_fx_ent.friendlyLosMarker = SpawnFx( fx[4], mark_fx_ent.origin );
|
|
triggerFx( mark_fx_ent.friendlyLosMarker );
|
|
mark_fx_ent.friendlyLosMarker hide();
|
|
|
|
mark_fx_struct.fx_ent[ i ] = mark_fx_ent;
|
|
}
|
|
|
|
self.mark_fx = mark_fx_struct;
|
|
}
|
|
else if( threatStyle == "model" )
|
|
{
|
|
model = spawn( "script_model", self.origin );
|
|
model.origin = self.origin;
|
|
model.angles = self.angles;
|
|
//print( "we would like to use " + self.model );
|
|
model setmodel( level._threatdetection.friendlyModel );
|
|
model SetContents( 0 );
|
|
//model codescripts\character::attachHead( "alias_africa_militia_heads_mp", xmodelalias\alias_africa_militia_heads_mp::main() );
|
|
self._threatDetection.mark_friendly_model = model;
|
|
|
|
model = spawn( "script_model", self.origin );
|
|
model.origin = self.origin;
|
|
model.angles = self.angles;
|
|
//print( "we would like to use " + self.model );
|
|
model setmodel( level._threatdetection.hostileModel );
|
|
model SetContents( 0 );
|
|
//model codescripts\character::attachHead( "alias_africa_militia_heads_mp", xmodelalias\alias_africa_militia_heads_mp::main() );
|
|
self._threatDetection.mark_enemy_model = model;
|
|
}
|
|
else if( threatStyle == "vfx_model")
|
|
{
|
|
self._threatDetection.mark_friendly_model = SpawnStruct();
|
|
self._threatDetection.mark_friendly_model = SpawnFx( GetFX( "threat_detect_model_stand" ), self.origin, AnglesToForward( self.angles ), AnglesToUp( self.angles ) );
|
|
self._threatDetection.friendly_pose = "threat_detect_model_stand";
|
|
|
|
self._threatDetection.mark_enemy_model = SpawnStruct();
|
|
self._threatDetection.mark_enemy_model = SpawnFx( GetFX( "threat_detect_model_stand_hostile" ), self.origin, AnglesToForward( self.angles ), AnglesToUp( self.angles ) );
|
|
self._threatDetection.hostile_pose = "threat_detect_model_stand_hostile";
|
|
}
|
|
else if( threatStyle == "attached_glow" )
|
|
{
|
|
|
|
foreach ( i,fx in level._threatdetection.fx_data )
|
|
{
|
|
tag_org = spawn_tag_origin();
|
|
tag_org show(); //spawn_tag_origin calls hide and if we dont show it, it will not be sent to any clients
|
|
tag_org.origin = self GetTagOrigin( fx[0] );
|
|
tag_org.angles = self GetTagAngles( fx[0] );
|
|
tag_org LinkTo( self, fx[0] );
|
|
tag_org.fx = fx[1];
|
|
//wait .05;
|
|
//PlayFXOnTag( tag_org.fx, tag_org, "tag_origin" );
|
|
mark_fx_struct.fx_ent[ i ] = tag_org;
|
|
}
|
|
|
|
self.mark_fx = mark_fx_struct;
|
|
}
|
|
else if( threatStyle == "stencil_outline" )
|
|
{
|
|
// does nothing on purpose
|
|
}
|
|
else
|
|
{
|
|
AssertEx( 0, "unknown threat style " + threatStyle + ". i dont know how to set it up" );
|
|
}
|
|
}
|
|
|
|
|
|
visitorUpdateLOSMarker( member, player, bone )
|
|
{
|
|
visitorUpdateMarkerPos( member, player, bone );
|
|
visitorShowToPlayer( member, player, bone );
|
|
}
|
|
|
|
visitorShowToPlayer( member, player, bone )
|
|
{
|
|
assert( IsDefined( player ) && isplayer( player ) );
|
|
assert( IsDefined( member ) );
|
|
|
|
threatStyle = GetThreatStyle();
|
|
|
|
if (threatStyle == "stencil_outline")
|
|
{
|
|
member threatDetectedToPlayer( player );
|
|
}
|
|
else
|
|
{
|
|
member showToPlayer( player );
|
|
}
|
|
}
|
|
|
|
showThreat( player, friendlyFn, hostileFn, visitorFn )
|
|
{
|
|
if ( player == self )
|
|
return;
|
|
|
|
memberFunc = hostileFn;
|
|
|
|
if( ( level.teamBased || level.multiteambased ) && player.team == self.team )
|
|
{
|
|
memberFunc = friendlyFn;
|
|
}
|
|
|
|
//for FFA
|
|
else if( player == self )
|
|
{
|
|
memberFunc = friendlyFn;
|
|
}
|
|
|
|
visitFXEnt( visitorFn, memberFunc, player );
|
|
} |