init
This commit is contained in:
921 files changed
+337975
No files matched your search
@@ -0,0 +1,197 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#using scripts\shared\visionset_mgr_shared;
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\_vehicle;
|
||||
|
||||
#precache( "client_fx", "killstreaks/fx_agr_emp_stun" );
|
||||
|
||||
#using_animtree ( "mp_vehicles" );
|
||||
|
||||
#namespace ai_tank;
|
||||
|
||||
function autoexec __init__sytem__() { system::register("ai_tank",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
bundle = struct::get_script_bundle( "killstreak", "killstreak_ai_tank_drop" );
|
||||
level.aiTankKillstreakBundle = bundle;
|
||||
|
||||
level._ai_tank_fx = [];
|
||||
level._ai_tank_fx[ "light_green" ] = "killstreaks/fx_agr_vlight_eye_grn";
|
||||
level._ai_tank_fx[ "light_red" ] = "killstreaks/fx_agr_vlight_eye_red";
|
||||
level._ai_tank_fx[ "stun" ] = "killstreaks/fx_agr_emp_stun";
|
||||
|
||||
clientfield::register( "vehicle", "ai_tank_death", 1, 1, "int",&death, !true, !true );
|
||||
clientfield::register( "vehicle", "ai_tank_missile_fire", 1, 2, "int",&missile_fire, !true, !true );
|
||||
clientfield::register( "vehicle", "ai_tank_stun", 1, 1, "int", &tank_stun, !true, !true );
|
||||
clientfield::register( "toplayer", "ai_tank_update_hud", 1, 1, "counter", &update_hud, !true, !true );
|
||||
|
||||
vehicle::add_vehicletype_callback( "ai_tank_drone_mp", &spawned );
|
||||
vehicle::add_vehicletype_callback( "spawner_bo3_ai_tank_mp", &spawned );
|
||||
vehicle::add_vehicletype_callback( "spawner_bo3_ai_tank_mp_player", &spawned );
|
||||
|
||||
visionset_mgr::register_visionset_info( "agr_visionset", 1, 16, undefined, "mp_vehicles_agr" );
|
||||
}
|
||||
|
||||
function spawned( localClientNum, killstreak_duration )
|
||||
{
|
||||
self thread play_driving_rumble( localClientNum );
|
||||
self.killstreakBundle = level.aiTankKillstreakBundle;
|
||||
}
|
||||
|
||||
function missile_fire( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
self util::waittill_dobj( localClientNum );
|
||||
|
||||
if ( self HasAnimTree() == false )
|
||||
self UseAnimTree( #animtree );
|
||||
|
||||
missiles_loaded = newVal;
|
||||
|
||||
if ( newVal == 2 )
|
||||
{
|
||||
self SetAnimRestart( %o_drone_tank_missile1_fire, 1.0, 0.0, 0.5 );
|
||||
}
|
||||
else if ( newVal == 1 )
|
||||
{
|
||||
self SetAnimRestart( %o_drone_tank_missile2_fire, 1.0, 0.0, 0.5 );
|
||||
}
|
||||
else if ( newVal == 0 )
|
||||
{
|
||||
self SetAnimRestart( %o_drone_tank_missile3_fire, 1.0, 0.0, 0.5 );
|
||||
}
|
||||
else if ( newVal == 3 )
|
||||
{
|
||||
self SetAnimRestart( %o_drone_tank_missile_full_reload, 1.0, 0.0, 1.0 );
|
||||
}
|
||||
|
||||
if ( missiles_loaded <= ( 3 ) )
|
||||
update_ui_ammo_count( localClientNum, missiles_loaded );
|
||||
}
|
||||
|
||||
function update_hud( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump ) // self == player
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
|
||||
{wait(.016);};
|
||||
|
||||
vehicle = GetPlayerVehicle( self );
|
||||
if ( isdefined( vehicle ) )
|
||||
{
|
||||
self update_ui_model_ammo_count( localClientNum, vehicle clientfield::get( "ai_tank_missile_fire" ) );
|
||||
}
|
||||
}
|
||||
|
||||
function update_ui_ammo_count( localClientNum, missiles_loaded ) // self == vehicle
|
||||
{
|
||||
if ( self isLocalClientDriver( localClientNum ) || IsSpectating( localClientNum ) )
|
||||
{
|
||||
update_ui_model_ammo_count( localclientnum, missiles_loaded );
|
||||
}
|
||||
}
|
||||
|
||||
function update_ui_model_ammo_count( localClientNum, missiles_loaded )
|
||||
{
|
||||
ammo_ui_data_model = GetUIModel( GetUIModelForController( localClientNum ), "vehicle.ammo" );
|
||||
|
||||
if ( isdefined( ammo_ui_data_model ) )
|
||||
SetUIModelValue( ammo_ui_data_model, missiles_loaded );
|
||||
|
||||
// /# IPrintLnBold( "Missile Count: " + missiles_loaded ); #/
|
||||
}
|
||||
|
||||
|
||||
function tank_stun( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
self endon( "death" );
|
||||
|
||||
if ( newVal )
|
||||
{
|
||||
self notify( "light_disable" );
|
||||
|
||||
self stop_stun_fx( localClientNum );
|
||||
self start_stun_fx( localClientNum );
|
||||
}
|
||||
else
|
||||
{
|
||||
self stop_stun_fx( localClientNum );
|
||||
}
|
||||
}
|
||||
|
||||
function death( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
player = GetLocalPlayer( localClientNum );
|
||||
|
||||
if ( !isdefined( player ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( player GetInKillcam( localClientNum ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( newVal )
|
||||
{
|
||||
self stop_stun_fx( localClientNum );
|
||||
self notify( "light_disable" );
|
||||
}
|
||||
}
|
||||
|
||||
function start_stun_fx( localClientNum )
|
||||
{
|
||||
self.stun_fx = PlayFxOnTag( localClientNum, level._ai_tank_fx[ "stun" ], self, "tag_origin" );
|
||||
PlaySound( localClientNum, "veh_talon_shutdown", self.origin );
|
||||
}
|
||||
|
||||
function stop_stun_fx( localClientNum )
|
||||
{
|
||||
if ( isdefined( self.stun_fx ) )
|
||||
{
|
||||
StopFx( localClientNum, self.stun_fx );
|
||||
self.stun_fx = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function play_driving_rumble( localClientNum )
|
||||
{
|
||||
self notify( "driving_rumble" );
|
||||
|
||||
self endon( "entityshutdown" );
|
||||
self endon( "death" );
|
||||
self endon( "driving_rumble" );
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
if ( IsInVehicle( localClientNum, self ) )
|
||||
{
|
||||
speed = self GetSpeed();
|
||||
|
||||
if ( speed >= 40 || speed <= -40 )
|
||||
{
|
||||
player = GetLocalPlayer( localClientNum );
|
||||
|
||||
if ( isdefined( player ) )
|
||||
{
|
||||
player Earthquake( 0.1, 0.1, self.origin, 200 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
util::server_wait( localClientNum, 0.05 );
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,230 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\util_shared;
|
||||
|
||||
Line truncated
|
||||
|
||||
#using scripts\mp\_rewindobjects;
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\_vehicle;
|
||||
|
||||
#namespace airsupport;
|
||||
|
||||
function planeSounds( localClientNum, spawnSound, flybySound, flybySoundLoop )
|
||||
{
|
||||
self endon("delete");
|
||||
|
||||
playsound (0, spawnSound, (0,0,0));
|
||||
if ( isdefined ( flybySound ) )
|
||||
self playsound (0, flybySound);
|
||||
self playloopsound( flybySoundLoop, 0 );
|
||||
}
|
||||
|
||||
|
||||
function getPlaneModel( teamFaction )
|
||||
{
|
||||
planemodel = "t5_veh_jet_f4_gearup";
|
||||
return planeModel;
|
||||
}
|
||||
|
||||
|
||||
function planeTurnRight( localClientNum, plane, yaw, halfLife, startTime)
|
||||
{
|
||||
planeTurn( localClientNum, plane, yaw, halfLife, startTime, true );
|
||||
}
|
||||
|
||||
function planeTurnLeft( localClientNum, plane, yaw, halfLife, startTime )
|
||||
{
|
||||
planeTurn( localClientNum, plane, yaw, halfLife, startTime, false );
|
||||
}
|
||||
|
||||
function planeTurn( localClientNum, plane, yaw, halfLife, startTime, isTurningRight )
|
||||
{
|
||||
plane endon( "delete" );
|
||||
plane endon( "entityshutdown" );
|
||||
level endon( "demo_jump" + localClientNum );
|
||||
|
||||
leftTurn = -1;
|
||||
rightTurn = 1;
|
||||
|
||||
if( isTurningRight )
|
||||
turnDirection = rightTurn;
|
||||
else
|
||||
turnDirection = leftTurn;
|
||||
|
||||
yawY = GetDvarFloat( "scr_planeyaw", -1.5 * turnDirection );
|
||||
rollZ = GetDvarFloat( "scr_planeroll", 1.5 * turnDirection );
|
||||
|
||||
maxYaw = GetDvarFloat( "scr_max_planeyaw", -45.0 * turnDirection );
|
||||
minRoll = GetDvarFloat( "scr_min_planeroll", 60.0 * turnDirection );
|
||||
|
||||
ox = GetDvarFloat( "scr_planeox", 30000.0 );
|
||||
oy = GetDvarFloat( "scr_planeoy", -30000.0 * turnDirection );
|
||||
maxoX = GetDvarFloat( "scr_maxo_planex", -1.0 );
|
||||
maxoY = GetDvarFloat( "scr_maxo_planey", -1.0 );
|
||||
|
||||
if (plane.angles[1] == 360)
|
||||
plane.angles = ( plane.angles[0], 0, plane.angles[2] );
|
||||
|
||||
origX = plane.origin[0];
|
||||
origY = plane.origin[1];
|
||||
|
||||
accumTurn = 0;
|
||||
looptime = 0.1;
|
||||
waitAmount = 0.1;
|
||||
waitForMoveDone = false;
|
||||
while( loopTime <= halflife )
|
||||
{
|
||||
if (plane.angles[1] == 360)
|
||||
plane.angles = ( plane.angles[0], 0, plane.angles[2] );
|
||||
|
||||
if ( minRoll != -1 && plane.angles[2] >= minRoll * turnDirection )
|
||||
rollZ = 0.0;
|
||||
|
||||
accumTurn += yawY;
|
||||
|
||||
if ( accumTurn <= maxYaw * turnDirection )
|
||||
{
|
||||
yawY = 0.0;
|
||||
}
|
||||
angles = ( plane.angles[0], plane.angles[1] + yawY, plane.angles[2] + rollZ);
|
||||
|
||||
mathX = ( sin ( 45 * looptime / halflife ) ) * ox ;
|
||||
mathY = ( cos ( 45 * looptime / halflife ) ) * oy ;
|
||||
|
||||
oldX = mathX;
|
||||
oldY = oy - mathY;
|
||||
|
||||
rotatedX = Cos(yaw) * oldX - Sin(yaw) * oldY;
|
||||
rotatedY = Sin(yaw) * oldX + Cos(yaw) * oldY;
|
||||
|
||||
endPoint = ( origX + rotatedX, origY + rotatedY, plane.origin[2]);
|
||||
if ( waitForMoveDone )
|
||||
plane waittill( "movedone" );
|
||||
waitForMoveDone = plane rewindobjects::serverTimedMoveTo( localClientNum, plane.origin, endPoint, startTime, waitAmount );
|
||||
plane rewindobjects::serverTimedRotateTo( localClientNum, angles, startTime, waitAmount );
|
||||
loopTime += waitAmount;
|
||||
startTime += waitAmount * 1000;
|
||||
}
|
||||
|
||||
yawY = GetDvarFloat( "scr_planeyaw2", 1.5 );
|
||||
rollZ = GetDvarFloat( "scr_planeroll2", -0.9 );
|
||||
|
||||
ox = GetDvarFloat( "scr_planeox", 30000.0 );
|
||||
oy = GetDvarFloat( "scr_planeoy", -30000.0 * turnDirection );
|
||||
maxoX = GetDvarFloat( "scr_maxo_planex", -1.0 );
|
||||
maxoY = GetDvarFloat( "scr_maxo_planey", -1.0 );
|
||||
|
||||
y = GetDvarFloat( "scr_planey2", 0.6 );
|
||||
z = GetDvarFloat( "scr_planez2", -1.5 );
|
||||
maxy = GetDvarFloat( "scr_max_planey2", 90);
|
||||
|
||||
accumTurn = 0;
|
||||
|
||||
while( loopTime < halflife + halflife )
|
||||
{
|
||||
if (plane.angles[1] == 360)
|
||||
plane.angles = ( plane.angles[0], 0, plane.angles[2] );
|
||||
|
||||
if ( minRoll != -1 && plane.angles[2] >= 0 )
|
||||
rollZ = 0.0;
|
||||
|
||||
accumTurn += yawY;
|
||||
|
||||
if ( accumTurn >= maxYaw )
|
||||
{
|
||||
yawY = 0.0;
|
||||
}
|
||||
|
||||
angles = ( plane.angles[0], plane.angles[1] + yawY, plane.angles[2] - rollZ);
|
||||
|
||||
mathX = ( sin ( 45 * looptime / halflife ) ) * ox ;
|
||||
mathY = ( cos ( 45 * looptime / halflife ) ) * oy ;
|
||||
|
||||
oldX = mathX;
|
||||
oldY = oy - mathY;
|
||||
|
||||
rotatedX = Cos(yaw) * oldX - Sin(yaw) * oldY;
|
||||
rotatedY = Sin(yaw) * oldX + Cos(yaw) * oldY;
|
||||
|
||||
endPoint = ( origX + rotatedX, origY + rotatedY, plane.origin[2]);
|
||||
|
||||
if ( waitForMoveDone )
|
||||
plane waittill( "movedone" );
|
||||
waitForMoveDone = plane rewindobjects::serverTimedMoveTo( localClientNum, plane.origin, endPoint, startTime, waitAmount );
|
||||
plane rewindobjects::serverTimedRotateTo( localClientNum, angles, startTime, waitAmount );
|
||||
loopTime += waitAmount;
|
||||
startTime += waitAmount * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
function doABarrelRoll( localClientNum, plane, endPoint, flytime, startTime )
|
||||
{
|
||||
plane endon( "entityshutdown" );
|
||||
plane endon("delete");
|
||||
level endon("demo_jump");
|
||||
|
||||
origin = plane.origin;
|
||||
originalHeight = origin[2];
|
||||
|
||||
loopWaitTime = GetDvarFloat( "scr_loopwaittime", 0.5 );
|
||||
loopHeightRand = GetDvarFloat( "scr_loopheightrand", 500 );
|
||||
loopHeight = GetDvarFloat( "scr_loopheight", 1200 );
|
||||
rollZ = GetDvarFloat( "scr_barrelroll", 10 );
|
||||
degreesToRoll = GetDvarFloat( "scr_degreesToRoll", 360 );
|
||||
unitsFromCentrePoint = 100;
|
||||
|
||||
timeElapsed = 0;
|
||||
degreesRolled = 0;
|
||||
waitAmount = 0.1;
|
||||
|
||||
loopHeight += randomFloatRange( 0-loopHeightRand, loopHeightRand );
|
||||
waitForMoveDone = false;
|
||||
angles = plane.angles;
|
||||
originalRoll = plane.angles[2];
|
||||
while ( timeElapsed < flytime )
|
||||
{
|
||||
timeElapsed += waitAmount;
|
||||
if ( ( timeElapsed > loopWaitTime ) && ( degreesRolled < degreesToRoll ) )
|
||||
{
|
||||
pitch = degreesRolled / 8;
|
||||
if ( pitch > 22.5 )
|
||||
pitch = 45 - pitch;
|
||||
|
||||
originalAngle = plane.angles[2];
|
||||
|
||||
scr_degreesToRoll = GetDvarInt( "scr_degreesToRoll", 0 );
|
||||
if ( scr_degreesToRoll )
|
||||
plane.angles[1] = 0;
|
||||
angles = ( 0 - pitch, plane.angles[1], originalRoll + degreesRolled );
|
||||
degreesRolled += rollZ;
|
||||
}
|
||||
|
||||
ratio = timeElapsed / ( flytime / 2 );
|
||||
|
||||
nextPoint = rewindobjects::getPointOnLine( origin, endPoint, ratio );
|
||||
|
||||
nextHeight = originalHeight + ( loopHeight - ( cos(degreesRolled/2) * loopHeight ) );
|
||||
nextPoint = ( nextPoint[0], nextPoint[1], nextHeight );
|
||||
|
||||
if ( waitForMoveDone )
|
||||
plane waittill( "movedone" );
|
||||
waitForMoveDone = plane rewindobjects::serverTimedMoveTo( localClientNum, plane.origin, nextPoint, startTime, waitAmount );
|
||||
plane rewindobjects::serverTimedRotateTo( localClientNum, angles, startTime, waitAmount );
|
||||
startTime += waitAmount * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function planeGoStraight( localClientNum, plane, startPoint, endPoint, moveTime, startTime )
|
||||
{
|
||||
plane endon("delete");
|
||||
level endon("demo_jump");
|
||||
|
||||
distanceIncreaseRatio = 2;
|
||||
|
||||
destPoint = rewindobjects::getPointOnLine( startPoint, endPoint, distanceIncreaseRatio );
|
||||
if ( plane rewindobjects::serverTimedMoveTo( localClientNum, startPoint, destPoint, startTime, moveTime ) )
|
||||
plane waittill( "movedone" );
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,954 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\ai_shared;
|
||||
#using scripts\shared\ai_puppeteer_shared;
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\challenges_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\flagsys_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\objpoints_shared;
|
||||
#using scripts\shared\scoreevents_shared;
|
||||
#using scripts\shared\ai\archetype_utility;
|
||||
#using scripts\shared\ai\systems\gib;
|
||||
#using scripts\shared\entityheadicons_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicleriders_shared;
|
||||
#using scripts\shared\weapons\_heatseekingmissile;
|
||||
#using scripts\shared\ai\systems\blackboard;
|
||||
|
||||
#using scripts\mp\_challenges;
|
||||
#using scripts\mp\gametypes\_globallogic_audio;
|
||||
#using scripts\mp\killstreaks\_killstreak_bundles;
|
||||
#using scripts\mp\killstreaks\_killstreak_detect;
|
||||
#using scripts\mp\killstreaks\_killstreak_hacking;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_supplydrop;
|
||||
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#namespace combat_robot;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Tweaks to how the combat robot's body is thrown after exploding
|
||||
// Scales the initial velocity
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Time in seconds the combat robot will shutdown before exploding.
|
||||
|
||||
|
||||
|
||||
// The combat robot will give up chasing an enemy if they haven't attacked them for this long.
|
||||
|
||||
|
||||
// The combat robot will ignore unattackable enemies for this long.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#precache( "string", "KILLSTREAK_COMBAT_ROBOT_ESCORT_HINT" );
|
||||
#precache( "string", "KILLSTREAK_COMBAT_ROBOT_GUARD_HINT" );
|
||||
#precache( "string", "KILLSTREAK_COMBAT_ROBOT_INBOUND" );
|
||||
#precache( "string", "KILLSTREAK_COMBAT_ROBOT_NOT_AVAILABLE" );
|
||||
#precache( "string", "KILLSTREAK_COMBAT_ROBOT_HACKED" );
|
||||
#precache( "string", "KILLSTREAK_COMBAT_ROBOT_PATROL_FAIL" );
|
||||
#precache( "string", "KILLSTREAK_DESTROYED_COMBAT_ROBOT" );
|
||||
#precache( "triggerstring", "KILLSTREAK_COMBAT_ROBOT_ESCORT_HINT" );
|
||||
#precache( "triggerstring", "KILLSTREAK_COMBAT_ROBOT_GUARD_HINT" );
|
||||
|
||||
#precache( "material", "t7_hud_ks_c54i_drop" );
|
||||
|
||||
function init()
|
||||
{
|
||||
killstreaks::register( "combat_robot", "combat_robot_marker", "killstreak_" + "combat_robot", "combat_robot" + "_used", &ActivateCombatRobot, undefined, true );
|
||||
killstreaks::register_alt_weapon( "combat_robot", "lmg_light_robot" );
|
||||
killstreaks::register_strings( "combat_robot", &"KILLSTREAK_COMBAT_ROBOT_EARNED", &"KILLSTREAK_COMBAT_ROBOT_NOT_AVAILABLE", &"KILLSTREAK_COMBAT_ROBOT_INBOUND", undefined, &"KILLSTREAK_COMBAT_ROBOT_HACKED" );
|
||||
killstreaks::register_dialog( "combat_robot", "mpl_killstreak_combat_robot", "combatRobotDialogBundle", "combatRobotPilotDialogBundle", "friendlyCombatRobot", "enemyCombatRobot", "enemyCombatRobotMultiple", "friendlyCombatRobotHacked", "enemyCombatRobotHacked", "requestCombatRobot", "threatCombatRobot" );
|
||||
|
||||
// TODO: Move to killstreak data
|
||||
level.killstreaks["inventory_combat_robot"].threatOnKill = true;
|
||||
level.killstreaks["combat_robot"].threatOnKill = true;
|
||||
|
||||
level thread _CleanupRobotCorpses();
|
||||
}
|
||||
|
||||
function private _CalculateProjectedGuardPosition( player )
|
||||
{
|
||||
// Find the closest navmesh position projected out from the reticle.
|
||||
//forwardVector = VectorScale( AnglesToForward( player GetPlayerAngles() ), 4000 );
|
||||
//guardPoint = BulletTrace( player GetEye(), player GetEye() + forwardVector, true, player );
|
||||
//return GetClosestPointOnNavMesh( guardPoint["position"], 48 );
|
||||
return GetClosestPointOnNavMesh( player.origin, 48 );
|
||||
}
|
||||
|
||||
function private _CalculateRobotSpawnPosition( player )
|
||||
{
|
||||
desiredSpawnPosition = AnglesToForward( player.angles ) *
|
||||
72 + player.origin;
|
||||
|
||||
return GetClosestPointOnNavMesh( desiredSpawnPosition, 48 );
|
||||
}
|
||||
|
||||
function private _CleanupRobotCorpses()
|
||||
{
|
||||
corpseDeleteTime = 15000;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
deleteCorpses = [];
|
||||
|
||||
foreach ( corpse in GetCorpseArray() )
|
||||
{
|
||||
if ( IsDefined( corpse.birthtime ) &&
|
||||
IsDefined( corpse.archetype ) &&
|
||||
corpse.archetype == "robot" &&
|
||||
( corpse.birthtime + corpseDeleteTime ) < GetTime() )
|
||||
{
|
||||
deleteCorpses[ deleteCorpses.size ] = corpse;
|
||||
}
|
||||
}
|
||||
|
||||
for ( index = 0; index < deleteCorpses.size; index++ )
|
||||
{
|
||||
deleteCorpses[ index ] Delete();
|
||||
}
|
||||
|
||||
wait ( corpseDeleteTime / 1000 ) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
function ConfigureTeamPost( player, isHacked )
|
||||
{
|
||||
robot = self;
|
||||
robot.properName = "";
|
||||
// Prevent the robot from being damaged based on a hurt trigger when being called in.
|
||||
robot.ignoreTriggerDamage = true;
|
||||
|
||||
robot.empShutdownTime = ( 750 );
|
||||
robot.minWalkDistance = 60;
|
||||
robot.superSprintDistance = 180;
|
||||
robot.robotRusherMinRadius = 64;
|
||||
robot.robotRusherMaxRadius = 120;
|
||||
robot.allowPushActors = false;
|
||||
robot.chargeMeleeDistance = 0; // Disable charge melee, more effective to shoot.
|
||||
robot.fovcosine = 0; // 360 degree field of view
|
||||
robot.fovcosinebusy = 0; // 360 degree field of view even when busy
|
||||
robot.MaxSightDistSqrd = ( (2000) * (2000) );
|
||||
|
||||
Blackboard::SetBlackBoardAttribute( robot, "_robot_mode", "combat" );
|
||||
|
||||
// Disable head gibbing.
|
||||
robot.gib_state = (0 | ( 8 & ( ( 1 << 9 ) - 1 ) ));
|
||||
robot clientfield::set( "gib_state", robot.gib_state );
|
||||
|
||||
_ConfigureRobotTeam( robot, player, isHacked );
|
||||
|
||||
robot ai::set_behavior_attribute( "can_become_crawler", false );
|
||||
robot ai::set_behavior_attribute( "can_be_meleed", false );
|
||||
robot ai::set_behavior_attribute( "can_initiateaivsaimelee", false );
|
||||
robot ai::set_behavior_attribute( "supports_super_sprint", true );
|
||||
}
|
||||
|
||||
function private _ConfigureRobotTeam( robot, player, isHacked )
|
||||
{
|
||||
if ( isHacked )
|
||||
{
|
||||
lightsState = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
lightsState = 0;
|
||||
}
|
||||
robot ai::set_behavior_attribute( "robot_lights", lightsState );
|
||||
robot thread WatchCombatRobotOwnerDisconnect( player );
|
||||
|
||||
if ( !isdefined( robot.objective ) )
|
||||
{
|
||||
robot.objective = GetEquipmentHeadObjective( GetWeapon( "combat_robot_marker" ) );
|
||||
}
|
||||
|
||||
robot thread _WatchModeSwap( robot, player );
|
||||
robot thread _Underwater( robot );
|
||||
}
|
||||
|
||||
|
||||
function private _CreateGuardMarker( robot, position )
|
||||
{
|
||||
owner = robot.owner;
|
||||
guardMarker = spawn( "script_model", ( 0, 0, 0 ) );
|
||||
guardMarker.origin = position;
|
||||
guardMarker entityheadicons::setEntityHeadIcon( owner.pers["team"], owner, undefined, &"airdrop_combatrobot" );
|
||||
|
||||
return guardMarker;
|
||||
}
|
||||
|
||||
function private _DestroyGuardMarker( robot )
|
||||
{
|
||||
if ( isdefined( robot.guardMarker ) )
|
||||
{
|
||||
robot.guardMarker delete();
|
||||
}
|
||||
}
|
||||
|
||||
function private _Underwater( robot )
|
||||
{
|
||||
robot endon( "death" );
|
||||
|
||||
while ( true )
|
||||
{
|
||||
if ( ( robot.origin[2] + 72 / 2.0 ) <= GetWaterHeight( robot.origin ) )
|
||||
{
|
||||
robot ASMSetAnimationRate( 0.85 );
|
||||
}
|
||||
else
|
||||
{
|
||||
robot ASMSetAnimationRate( 1.0 );
|
||||
}
|
||||
|
||||
wait 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
function private _Escort( robot )
|
||||
{
|
||||
robot endon( "death" );
|
||||
|
||||
robot.escorting = true;
|
||||
robot.guarding = false;
|
||||
|
||||
_DestroyGuardMarker( robot );
|
||||
|
||||
while ( robot.escorting )
|
||||
{
|
||||
attackingEnemy = false;
|
||||
|
||||
if ( IsDefined( robot.enemy ) && IsAlive( robot.enemy ) )
|
||||
{
|
||||
if ( ( robot LastKnownTime( robot.enemy ) + 10000 ) >= GetTime() )
|
||||
{
|
||||
robot ai::set_behavior_attribute( "move_mode", "rusher" );
|
||||
|
||||
attackingEnemy = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
robot ClearEnemy();
|
||||
}
|
||||
}
|
||||
|
||||
if ( !attackingEnemy && IsDefined( robot.owner ) && IsAlive( robot.owner ) )
|
||||
{
|
||||
lookAheadTime = 1.0;
|
||||
predicitedPosition =
|
||||
robot.owner.origin + VectorScale( robot.owner GetVelocity(), lookAheadTime );
|
||||
|
||||
robot ai::set_behavior_attribute( "escort_position", predicitedPosition );
|
||||
robot ai::set_behavior_attribute( "move_mode", "escort" );
|
||||
}
|
||||
|
||||
wait 1;
|
||||
}
|
||||
}
|
||||
|
||||
function private _IgnoreUnattackableEnemy( robot, enemy )
|
||||
{
|
||||
robot endon( "death" );
|
||||
|
||||
robot SetIgnoreEnt( enemy, true );
|
||||
|
||||
wait 5000 / 1000;
|
||||
|
||||
robot SetIgnoreEnt( enemy, false );
|
||||
}
|
||||
|
||||
function private _GuardPosition( robot, position )
|
||||
{
|
||||
robot endon( "death" );
|
||||
|
||||
robot.goalradius = 1000;
|
||||
robot SetGoal( position );
|
||||
|
||||
robot.escorting = false;
|
||||
robot.guarding = true;
|
||||
|
||||
_DestroyGuardMarker( robot );
|
||||
|
||||
robot.guardMarker = _CreateGuardMarker( robot, position );
|
||||
|
||||
while ( robot.guarding )
|
||||
{
|
||||
attackingEnemy = false;
|
||||
|
||||
if ( IsDefined( robot.enemy ) && IsAlive( robot.enemy ) )
|
||||
{
|
||||
if ( ( robot LastKnownTime( robot.enemy ) + 10000 ) >= GetTime() )
|
||||
{
|
||||
// Robot still within goalradius, continue pursuit.
|
||||
robot ai::set_behavior_attribute( "move_mode", "rusher" );
|
||||
|
||||
attackingEnemy = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
robot ClearEnemy();
|
||||
}
|
||||
}
|
||||
|
||||
if ( !attackingEnemy )
|
||||
{
|
||||
robot ai::set_behavior_attribute( "move_mode", "guard" );
|
||||
}
|
||||
|
||||
wait 1;
|
||||
}
|
||||
}
|
||||
|
||||
function _WatchModeSwap( robot, player )
|
||||
{
|
||||
robot endon( "death" );
|
||||
|
||||
nextSwitchTime = GetTime();
|
||||
|
||||
while ( true )
|
||||
{
|
||||
{wait(.05);};
|
||||
|
||||
if( !isdefined( robot.useTrigger ) )
|
||||
continue;
|
||||
|
||||
robot.useTrigger waittill( "trigger" );
|
||||
|
||||
if ( nextSwitchTime <= GetTime() && IsAlive( player ) )
|
||||
{
|
||||
if ( ( isdefined( robot.guarding ) && robot.guarding ) )
|
||||
{
|
||||
robot.guarding = false;
|
||||
robot.escorting = true;
|
||||
|
||||
player playsoundtoplayer( "uin_mp_combat_bot_escort", player );
|
||||
robot thread _Escort( robot );
|
||||
if( isdefined( robot.useTrigger ) )
|
||||
robot.useTrigger SetHintString( &"KILLSTREAK_COMBAT_ROBOT_GUARD_HINT" );
|
||||
|
||||
if( isdefined( robot.markerFXHandle ) )
|
||||
robot.markerFXHandle delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
navGuardPosition = _CalculateProjectedGuardPosition( player );
|
||||
|
||||
if ( IsDefined( navGuardPosition ) )
|
||||
{
|
||||
robot.guarding = true;
|
||||
robot.escorting = false;
|
||||
|
||||
player playsoundtoplayer( "uin_mp_combat_bot_guard", player );
|
||||
robot thread _GuardPosition( robot, navGuardPosition );
|
||||
if( isdefined( robot.useTrigger ) )
|
||||
robot.useTrigger SetHintString( &"KILLSTREAK_COMBAT_ROBOT_ESCORT_HINT" );
|
||||
|
||||
if( isdefined( robot.markerFXHandle ) )
|
||||
robot.markerFXHandle delete();
|
||||
|
||||
params = level.killstreakBundle["combat_robot"];
|
||||
if( isdefined( params.ksCombatRobotPatrolFX ) )
|
||||
{
|
||||
point = player.origin;
|
||||
if( !isdefined( point ) )
|
||||
point = navGuardPosition;
|
||||
|
||||
robot.markerFXHandle = SpawnFx( params.ksCombatRobotPatrolFX, point + ( 0, 0, 3 ), ( 0, 0, 1 ), ( 1, 0, 0 ) );
|
||||
robot.markerFXHandle.team = player.team;
|
||||
TriggerFX( robot.markerFXHandle );
|
||||
|
||||
robot.markerFXHandle SetInvisibleToAll();
|
||||
robot.markerFXHandle SetVisibleToPlayer( player );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player iPrintLnBold( &"KILLSTREAK_COMBAT_ROBOT_PATROL_FAIL" );
|
||||
}
|
||||
}
|
||||
|
||||
robot notify("bhtn_action_notify", "modeSwap");
|
||||
|
||||
nextSwitchTime = GetTime() + 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ActivateCombatRobot( killstreak )
|
||||
{
|
||||
player = self;
|
||||
team = self.team;
|
||||
|
||||
if( !self supplydrop::isSupplyDropGrenadeAllowed( killstreak ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
killstreak_id = self killstreakrules::killstreakStart( killstreak, team, false, false );
|
||||
if ( killstreak_id == -1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
context = SpawnStruct();
|
||||
context.prolog = &Prolog;
|
||||
context.epilog = &Epilog;
|
||||
|
||||
context.hasFlares = 1;
|
||||
context.radius = level.killstreakCoreBundle.ksAirdropRobotRadius;
|
||||
context.dist_from_boundary = 18;
|
||||
context.max_dist_from_location = 4;
|
||||
context.perform_physics_trace = true;
|
||||
context.drop_from_goal_distance2d = 96; // combat robot doesn't need this value to be strict (note: drop ship related)
|
||||
context.isLocationGood = &supplydrop::IsLocationGood;
|
||||
context.objective = &"airdrop_combatrobot";
|
||||
context.killstreakRef = killstreak;
|
||||
context.validLocationSound = level.killstreakCoreBundle.ksValidCombatRobotLocationSound;
|
||||
context.vehiclename = "combat_robot_dropship";
|
||||
context.killstreak_id = killstreak_id;
|
||||
context.tracemask = (1 << 0) | (1 << 2);
|
||||
|
||||
// This offset is specific to the exit vtol animation of the combat rider.
|
||||
context.dropOffset = (0, -120, 0);
|
||||
|
||||
result = self supplydrop::useSupplyDropMarker( killstreak_id, context );
|
||||
|
||||
if ( !isdefined(result) || !result )
|
||||
{
|
||||
killstreakrules::killstreakStop( killstreak, team, killstreak_id );
|
||||
return false;
|
||||
}
|
||||
|
||||
self killstreaks::play_killstreak_start_dialog( "combat_robot", self.team, killstreak_id );
|
||||
self killstreakrules::displayKillstreakStartTeamMessageToAll( "combat_robot" );
|
||||
|
||||
self AddWeaponStat( GetWeapon( "combat_robot_marker" ), "used", 1 );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
function DropKillThread()
|
||||
{
|
||||
robot = self;
|
||||
robot endon( "death" );
|
||||
robot endon( "combat_robot_land" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
robot supplydrop::is_touching_crate();
|
||||
robot supplydrop::is_clone_touching_crate();
|
||||
{wait(.05);};
|
||||
}
|
||||
}
|
||||
|
||||
function WatchHelicopterDeath( context )
|
||||
{
|
||||
helicopter = self;
|
||||
helicopter waittill( "death" );
|
||||
|
||||
callback::callback( #"on_vehicle_killed" );
|
||||
|
||||
if( isdefined( context.marker ) )
|
||||
{
|
||||
context.marker delete();
|
||||
context.marker = undefined;
|
||||
|
||||
if( isdefined( context.markerFXHandle ) )
|
||||
{
|
||||
context.markerFXHandle delete();
|
||||
context.markerFXHandle = undefined;
|
||||
}
|
||||
supplydrop::DelDropLocation( context.killstreak_id );
|
||||
}
|
||||
}
|
||||
|
||||
function Prolog( context )
|
||||
{
|
||||
helicopter = self;
|
||||
player = helicopter.owner;
|
||||
|
||||
spawnPosition = ( 0,0,0 );
|
||||
spawnAngles = ( 0,0,0 );
|
||||
|
||||
combatRobot = SpawnActor(
|
||||
"spawner_bo3_robot_grunt_assault_mp",
|
||||
spawnPosition,
|
||||
spawnAngles,
|
||||
"",
|
||||
true );
|
||||
combatRobot.missileTrackDamage = 0;
|
||||
combatRobot killstreaks::configure_team( "combat_robot", context.killstreak_id, player, "small_vehicle", undefined, &ConfigureTeamPost );
|
||||
combatRobot killstreak_hacking::enable_hacking( "combat_robot", undefined, &HackedCallbackPost );
|
||||
combatRobot thread _Escort( combatRobot );
|
||||
|
||||
combatRobot thread WatchCombatRobotHelicopterHacked( helicopter );
|
||||
combatRobot thread WatchCombatRobotShutdown();
|
||||
combatRobot thread WatchCombatRobotDeath();
|
||||
combatRobot thread killstreaks::WaitForTimeout( "combat_robot", ( 90000 ), &OnCombatRobotTimeout, "combat_robot_shutdown" );
|
||||
combatRobot thread sndWatchCombatRobotVoxNotifies();
|
||||
//combatRobot thread debugThread();
|
||||
|
||||
helicopter thread WatchHelicopterDeath( context );
|
||||
helicopter.unloadTimeout = 6;
|
||||
|
||||
killstreak_detect::killstreakTargetSet( combatRobot, ( 0, 0, 50 ) );
|
||||
|
||||
combatRobot.maxhealth = combatRobot.health;
|
||||
|
||||
tableHealth = killstreak_bundles::get_max_health( "combat_robot" );
|
||||
|
||||
if ( isdefined( tableHealth ) )
|
||||
{
|
||||
combatRobot.maxhealth = tableHealth;
|
||||
}
|
||||
|
||||
combatRobot.health = combatRobot.maxhealth;
|
||||
combatRobot.treat_owner_damage_as_friendly_fire = true;
|
||||
combatRobot.ignore_team_kills = true;
|
||||
combatRobot.remoteMissileDamage = combatRobot.maxhealth + 1;
|
||||
combatRobot.rocketDamage = combatRobot.maxhealth / 2 + 1;
|
||||
combatRobot thread heatseekingmissile::MissileTarget_ProximityDetonateIncomingMissile("death");
|
||||
combatRobot clientfield::set( "enemyvehicle", 1 );
|
||||
combatRobot.soundmod = "drone_land";
|
||||
|
||||
AiUtility::AddAIOverrideDamageCallback( combatRobot, &combatRobotDamageOverride );
|
||||
|
||||
combatRobot.vehicle = helicopter;
|
||||
combatRobot.vehicle.ignore_seat_check = true;
|
||||
combatRobot vehicle::get_in( helicopter , "driver", true );
|
||||
|
||||
combatRobot.overrideDropPosition = player.markerPosition;
|
||||
|
||||
combatRobot thread WatchCombatRobotLanding();
|
||||
combatRobot thread sndWatchExit();
|
||||
combatRobot thread sndWatchLanding();
|
||||
combatRobot thread sndWatchActivate();
|
||||
|
||||
foreach( player in level.players )
|
||||
{
|
||||
combatRobot respectNotTargetedByRobotPerk( player );
|
||||
}
|
||||
|
||||
callback::on_spawned( &respectNotTargetedByRobotPerk, combatRobot );
|
||||
context.robot = combatRobot;
|
||||
}
|
||||
|
||||
function respectNotTargetedByRobotPerk( player )
|
||||
{
|
||||
combatRobot = self;
|
||||
combatRobot setignoreent( player, player hasperk( "specialty_nottargetedbyrobot" ) );
|
||||
}
|
||||
|
||||
function Epilog( context )
|
||||
{
|
||||
helicopter = self;
|
||||
|
||||
context.robot thread DropKillThread();
|
||||
context.robot.startTime = GetTime() + ( 750 ); // set killcam to start a time offset from when drop ship arrives
|
||||
thread CleanupThread( context );
|
||||
|
||||
/# debug_delay_robot_deploy(); #/
|
||||
|
||||
helicopter WaitThenSetDeleteAfterDestructionWaitTime( 0.8, (isdefined(self.unloadTimeout)?self.unloadTimeout:0) + 0.1 );
|
||||
|
||||
helicopter vehicle::unload( "all", undefined, true, 0.8 ); // removes robot as rider so that it doesn't
|
||||
}
|
||||
|
||||
/#
|
||||
function debug_delay_robot_deploy()
|
||||
{
|
||||
seconds_to_wait = GetDvarInt( "scr_combat_robot_wait_to_deploy", 0 ); // 14 seconds is good to shoot down deploy ship given 3 flares and 2 rockets to kill and sustained ammo
|
||||
while ( seconds_to_wait > 0 )
|
||||
{
|
||||
IPrintLnBold( "Remaining time: " + seconds_to_wait );
|
||||
wait 1;
|
||||
seconds_to_wait--;
|
||||
|
||||
if ( seconds_to_wait == 0 )
|
||||
IPrintLnBold( "Jump!!" );
|
||||
}
|
||||
}
|
||||
#/
|
||||
|
||||
function WaitThenSetDeleteAfterDestructionWaitTime( set_wait_time, delete_after_destruction_wait_time )
|
||||
{
|
||||
wait set_wait_time;
|
||||
|
||||
if ( isdefined( self ) )
|
||||
{
|
||||
self.delete_after_destruction_wait_time = delete_after_destruction_wait_time;
|
||||
}
|
||||
}
|
||||
|
||||
function HackedCallbackPost( hacker )
|
||||
{
|
||||
robot = self;
|
||||
robot ClearEnemy();
|
||||
robot SetupCombatRobotHintTrigger( hacker );
|
||||
}
|
||||
|
||||
|
||||
function WatchCombatRobotHelicopterHacked( helicopter )
|
||||
{
|
||||
robot = self;
|
||||
robot endon( "death" );
|
||||
robot endon( "killstreak_hacked" );
|
||||
robot endon( "combat_robot_land" );
|
||||
|
||||
helicopter endon( "death" );
|
||||
|
||||
helicopter waittill( "killstreak_hacked", hacker );
|
||||
|
||||
if( robot flagsys::get( "in_vehicle" ) == false )
|
||||
return;
|
||||
|
||||
robot [[ robot.killstreak_hackedCallback ]]( hacker );
|
||||
}
|
||||
|
||||
function CleanupThread( context )
|
||||
{
|
||||
robot = context.robot;
|
||||
while( isdefined( robot ) && isdefined( context.marker ) && ( robot flagsys::get( "in_vehicle" ) ) )
|
||||
{
|
||||
wait 1;
|
||||
}
|
||||
if( isdefined( context.marker ) )
|
||||
{
|
||||
context.marker delete();
|
||||
context.marker = undefined;
|
||||
|
||||
if( isdefined( context.markerFXHandle ) )
|
||||
{
|
||||
context.markerFXHandle delete();
|
||||
context.markerFXHandle = undefined;
|
||||
}
|
||||
supplydrop::DelDropLocation( context.killstreak_id );
|
||||
}
|
||||
}
|
||||
|
||||
function WatchCombatRobotDeath()
|
||||
{
|
||||
combatRobot = self;
|
||||
combatRobot endon( "combat_robot_shutdown" );
|
||||
callback::remove_on_spawned( &respectNotTargetedByRobotPerk, combatRobot );
|
||||
combatRobot waittill( "death", attacker, damageFromUnderneath, weapon );
|
||||
// combatRobot waittill( "death", attacker, damageFromUnderneath, weapon, point, dir, modType );
|
||||
|
||||
attacker = self [[ level.figure_out_attacker ]]( attacker );
|
||||
|
||||
if ( isdefined( attacker ) && IsPlayer( attacker ) && ( !isdefined( combatRobot.owner ) || combatRobot.owner util::IsEnemyPlayer( attacker ) ) )
|
||||
{
|
||||
attacker challenges::destroyScoreStreak( weapon, false, true );
|
||||
attacker challenges::destroyNonAirScoreStreak_PostStatsLock( weapon );
|
||||
scoreevents::processScoreEvent( "destroyed_combat_robot", attacker, combatRobot.owner, weapon );
|
||||
LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_COMBAT_ROBOT", attacker.entnum );
|
||||
}
|
||||
|
||||
combatRobot killstreaks::play_destroyed_dialog_on_owner( "combat_robot", combatRobot.killstreak_id );
|
||||
|
||||
combatRobot notify( "combat_robot_shutdown" );
|
||||
}
|
||||
|
||||
function WatchCombatRobotLanding()
|
||||
{
|
||||
robot = self;
|
||||
robot endon( "death" );
|
||||
robot endon( "combat_robot_shutdown" );
|
||||
|
||||
// wait for landing
|
||||
while( robot flagsys::get( "in_vehicle" ) )
|
||||
{
|
||||
wait 1;
|
||||
}
|
||||
|
||||
robot notify( "combat_robot_land" );
|
||||
|
||||
robot.ignoreTriggerDamage = false;
|
||||
|
||||
// only check if on nav mesh after finishing traversals
|
||||
while ( isdefined( robot.traverseStartNode ) )
|
||||
{
|
||||
robot waittill( "traverse_end" );
|
||||
}
|
||||
|
||||
v_on_navmesh = GetClosestPointOnNavMesh( robot.origin, 50, 20 );
|
||||
///#sphere( robot.origin, 5, ( 1, 0, 0 ), 1, true, 10, 200 );#/
|
||||
|
||||
if ( isdefined ( v_on_navmesh ) )
|
||||
{
|
||||
player = robot.owner;
|
||||
|
||||
robot SetupCombatRobotHintTrigger( player );
|
||||
}
|
||||
else
|
||||
{
|
||||
robot notify( "combat_robot_shutdown" );
|
||||
}
|
||||
}
|
||||
|
||||
function SetupCombatRobotHintTrigger( player )
|
||||
{
|
||||
robot = self;
|
||||
if ( isdefined( robot.useTrigger ) )
|
||||
{
|
||||
robot.useTrigger delete();
|
||||
}
|
||||
robot.useTrigger = spawn( "trigger_radius_use", player.origin, 32, 32 );
|
||||
robot.useTrigger EnableLinkTo();
|
||||
robot.useTrigger LinkTo( player );
|
||||
robot.useTrigger SetHintLowPriority( true );
|
||||
robot.useTrigger SetCursorHint( "HINT_NOICON" );
|
||||
robot.useTrigger SetHintString( &"KILLSTREAK_COMBAT_ROBOT_GUARD_HINT" );
|
||||
|
||||
robot.useTrigger SetTeamForTrigger( player.team );
|
||||
robot.useTrigger.team = player.team;
|
||||
|
||||
player ClientClaimTrigger( robot.useTrigger );
|
||||
player.remoteControlTrigger = robot.useTrigger;
|
||||
robot.useTrigger.ClaimedBy = player;
|
||||
}
|
||||
|
||||
function WatchCombatRobotOwnerDisconnect( player )
|
||||
{
|
||||
combatRobot = self;
|
||||
combatRobot notify( "WatchCombatRobotOwnerDisconnect_singleton" );
|
||||
combatRobot endon( "WatchCombatRobotOwnerDisconnect_singleton" );
|
||||
combatRobot endon( "combat_robot_shutdown" );
|
||||
|
||||
player util::waittill_any( "joined_team", "disconnect", "joined_spectators" );
|
||||
combatRobot notify( "combat_robot_shutdown" );
|
||||
}
|
||||
|
||||
function private _corpseWatcher()
|
||||
{
|
||||
archetype = self.archetype;
|
||||
self waittill("actor_corpse", corpse);
|
||||
corpse clientfield::set("arch_actor_fire_fx", 3);
|
||||
}
|
||||
|
||||
function private _explodeRobot( combatRobot )
|
||||
{
|
||||
combatRobot clientfield::set("arch_actor_fire_fx", 1);
|
||||
clientfield::set(
|
||||
"robot_mind_control_explosion", 1 );
|
||||
combatRobot thread _corpseWatcher();
|
||||
|
||||
if ( RandomInt( 100 ) >= 50 )
|
||||
GibServerUtils::GibLeftArm( combatRobot );
|
||||
else
|
||||
GibServerUtils::GibRightArm( combatRobot );
|
||||
|
||||
GibServerUtils::GibLegs( combatRobot );
|
||||
GibServerUtils::GibHead( combatRobot );
|
||||
|
||||
velocity = combatRobot GetVelocity() * ( 1 / 8 );
|
||||
|
||||
combatRobot StartRagdoll();
|
||||
combatRobot LaunchRagdoll(
|
||||
( velocity[0] + RandomFloatRange( -20, 20 ),
|
||||
velocity[1] + RandomFloatRange( -20, 20 ),
|
||||
RandomFloatRange( 60, 80 ) ),
|
||||
"j_mainroot" );
|
||||
}
|
||||
|
||||
function OnCombatRobotTimeout()
|
||||
{
|
||||
combatRobot = self;
|
||||
|
||||
combatRobot killstreaks::play_pilot_dialog_on_owner( "timeout", "combat_robot" );
|
||||
|
||||
combatRobot ai::set_behavior_attribute( "shutdown", true );
|
||||
|
||||
wait RandomFloatRange( 3.0, 4.5 );
|
||||
|
||||
_explodeRobot( combatRobot );
|
||||
|
||||
params = level.killstreakBundle["combat_robot"];
|
||||
|
||||
if( isdefined( params.ksExplosionFX ) )
|
||||
{
|
||||
PlayFXOnTag( params.ksExplosionFX, combatRobot, "tag_origin" );
|
||||
}
|
||||
Target_Remove( combatRobot );
|
||||
|
||||
if(!isdefined(params.ksExplosionOuterRadius))params.ksExplosionOuterRadius=200;
|
||||
if(!isdefined(params.ksExplosionInnerRadius))params.ksExplosionInnerRadius=1;
|
||||
if(!isdefined(params.ksExplosionOuterDamage))params.ksExplosionOuterDamage=25;
|
||||
if(!isdefined(params.ksExplosionInnerDamage))params.ksExplosionInnerDamage=350;
|
||||
if(!isdefined(params.ksExplosionMagnitude))params.ksExplosionMagnitude=1;
|
||||
|
||||
PhysicsExplosionSphere( combatRobot.origin,
|
||||
params.ksExplosionOuterRadius,
|
||||
params.ksExplosionInnerRadius,
|
||||
params.ksExplosionMagnitude,
|
||||
params.ksExplosionOuterDamage,
|
||||
params.ksExplosionInnerDamage );
|
||||
|
||||
if( isdefined( combatRobot.owner ) )
|
||||
{
|
||||
RadiusDamage( combatRobot.origin,
|
||||
params.ksExplosionOuterRadius,
|
||||
params.ksExplosionInnerDamage,
|
||||
params.ksExplosionOuterDamage,
|
||||
combatRobot.owner,
|
||||
"MOD_EXPLOSIVE",
|
||||
GetWeapon( "combat_robot_marker" ) );
|
||||
|
||||
if( isdefined( params.ksExplosionRumble ) )
|
||||
combatRobot.owner PlayRumbleOnEntity( params.ksExplosionRumble );
|
||||
}
|
||||
|
||||
wait( 0.2 );
|
||||
|
||||
combatRobot notify( "combat_robot_shutdown" );
|
||||
}
|
||||
|
||||
function WatchCombatRobotShutdown()
|
||||
{
|
||||
combatRobot = self;
|
||||
combatRobotTeam = combatRobot.originalteam;
|
||||
combatRobotKillstreakId = combatRobot.killstreak_id;
|
||||
combatRobot waittill( "combat_robot_shutdown" );
|
||||
|
||||
combatRobot playsound ("evt_combat_bot_mech_fail_explode");
|
||||
|
||||
if( isdefined( combatRobot.useTrigger ) )
|
||||
combatRobot.useTrigger delete();
|
||||
|
||||
if( isdefined( combatRobot.markerFXHandle ) )
|
||||
combatRobot.markerFXHandle delete();
|
||||
|
||||
_DestroyGuardMarker( combatRobot );
|
||||
|
||||
killstreakrules::killstreakStop( "combat_robot", combatRobotTeam, combatRobotKillstreakId );
|
||||
|
||||
if( isdefined( combatRobot ) )
|
||||
{
|
||||
if( Target_IsTarget( combatRobot ) )
|
||||
Target_Remove( combatRobot );
|
||||
if( !level.gameEnded ) // kill and do damage do nothing after game end
|
||||
{
|
||||
if( combatRobot flagsys::get( "in_vehicle" ) )
|
||||
combatRobot Unlink();
|
||||
combatRobot Kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sndWatchCombatRobotVoxNotifies()
|
||||
{
|
||||
combatRobot = self;
|
||||
combatRobot endon( "combat_robot_shutdown" );
|
||||
combatRobot endon( "death" );
|
||||
|
||||
combatRobot PlaySoundOnTag( "vox_robot_chatter", "j_head" );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
soundAlias = undefined;
|
||||
combatRobot waittill("bhtn_action_notify", notify_string);
|
||||
|
||||
switch( notify_string )
|
||||
{
|
||||
case "charge":
|
||||
case "attack_melee":
|
||||
case "attack_kill":
|
||||
case "modeSwap":
|
||||
soundAlias = "vox_robot_chatter";
|
||||
break;
|
||||
}
|
||||
|
||||
if( isdefined( soundAlias ) )
|
||||
{
|
||||
combatRobot PlaySoundOnTag( soundAlias, "j_head" );
|
||||
wait(1.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
function sndWatchExit()
|
||||
{
|
||||
combatRobot = self;
|
||||
combatRobot endon( "combat_robot_shutdown" );
|
||||
combatRobot endon( "death" );
|
||||
|
||||
combatRobot waittill( "exiting_vehicle" );
|
||||
|
||||
combatRobot playsound( "veh_vtol_supply_robot_launch" );
|
||||
}
|
||||
function sndWatchLanding()
|
||||
{
|
||||
combatRobot = self;
|
||||
combatRobot endon( "combat_robot_shutdown" );
|
||||
combatRobot endon( "death" );
|
||||
|
||||
combatRobot waittill( "falling", falltime );
|
||||
|
||||
wait_time = falltime - .5;
|
||||
|
||||
if ( wait_time > 0 )
|
||||
wait( wait_time );
|
||||
|
||||
combatRobot playsound( "veh_vtol_supply_robot_land" );
|
||||
}
|
||||
function sndWatchActivate()
|
||||
{
|
||||
combatRobot = self;
|
||||
combatRobot endon( "combat_robot_shutdown" );
|
||||
combatRobot endon( "death" );
|
||||
|
||||
combatRobot waittill( "landing" );
|
||||
wait(.1);
|
||||
combatRobot playsound( "veh_vtol_supply_robot_activate" );
|
||||
}
|
||||
|
||||
function combatRobotDamageOverride( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex, modelIndex )
|
||||
{
|
||||
combatRobot = self;
|
||||
|
||||
if( combatRobot flagsys::get( "in_vehicle" ) && ( sMeansOfDeath == "MOD_TRIGGER_HURT" ) ) // the dropship goes through hurt triggers sometimes
|
||||
iDamage = 0;
|
||||
else
|
||||
iDamage = killstreaks::OnDamagePerWeapon( "combat_robot", eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, self.maxhealth, undefined, self.maxhealth*0.4, undefined, 0, undefined, true, 1.0 );
|
||||
|
||||
combatRobot.missileTrackDamage += iDamage;
|
||||
|
||||
if ( iDamage > 0 && isdefined( eAttacker ) )
|
||||
{
|
||||
if ( isPlayer( eAttacker) )
|
||||
{
|
||||
if ( isdefined( combatRobot.owner ) )
|
||||
{
|
||||
challenges::combat_robot_damage( eAttacker, combatRobot.Owner );
|
||||
}
|
||||
}
|
||||
}
|
||||
return iDamage;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
|
||||
#namespace counteruav;
|
||||
|
||||
function autoexec __init__sytem__() { system::register("counteruav",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
clientfield::register( "toplayer", "counteruav", 1, 1, "int", &CounterUAVChanged, !true, true );
|
||||
}
|
||||
|
||||
function CounterUAVChanged( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
player = GetLocalPlayer( localClientNum );
|
||||
assert( isdefined( player ) );
|
||||
|
||||
player SetEnemyGlobalScrambler( newVal );
|
||||
}
|
||||
@@ -0,0 +1,684 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\gametypes\_battlechatter;
|
||||
#using scripts\mp\gametypes\_globallogic_audio;
|
||||
#using scripts\mp\killstreaks\_airsupport;
|
||||
#using scripts\mp\killstreaks\_helicopter;
|
||||
#using scripts\mp\killstreaks\_killstreak_bundles;
|
||||
#using scripts\mp\killstreaks\_killstreak_detect;
|
||||
#using scripts\mp\killstreaks\_killstreak_hacking;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_satellite;
|
||||
#using scripts\mp\teams\_teams;
|
||||
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\challenges_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\damagefeedback_shared;
|
||||
#using scripts\shared\hostmigration_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\math_shared;
|
||||
#using scripts\shared\scoreevents_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\tweakables_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\weapons\_heatseekingmissile;
|
||||
#using scripts\shared\weapons\_weaponobjects;
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#namespace counteruav;
|
||||
|
||||
#precache( "string", "KILLSTREAK_COUNTERUAV_INBOUND" );
|
||||
#precache( "string", "KILLSTREAK_COUNTERUAV_NOT_AVAILABLE" );
|
||||
#precache( "string", "KILLSTREAK_EARNED_COUNTERUAV" );
|
||||
#precache( "string", "KILLSTREAK_DESTROYED_COUNTERUAV" );
|
||||
#precache( "string", "KILLSTREAK_COUNTERUAV_HACKED" );
|
||||
#precache( "string", "mpl_killstreak_radar" );
|
||||
|
||||
|
||||
function init()
|
||||
{
|
||||
level.activeCounterUAVs = [];
|
||||
level.counter_uav_positions = GenerateRandomPoints( ( 20 ) );
|
||||
level.counter_uav_position_index = [];
|
||||
level.counter_uav_offsets = BuildOffsetList( ( 0, 0, 0 ), ( 3 ), ( 450 ), ( 450 ) );
|
||||
|
||||
if ( level.teamBased )
|
||||
{
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
level.activeCounterUAVs[ team ] = 0;
|
||||
level.counter_uav_position_index[ team ] = 0;
|
||||
|
||||
level thread MovementManagerThink( team );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
level.activeCounterUAVs = [];
|
||||
}
|
||||
|
||||
level.activePlayerCounterUAVs = [];
|
||||
|
||||
level.counter_uav_entities = [];
|
||||
|
||||
if( tweakables::getTweakableValue( "killstreak", "allowcounteruav" ) )
|
||||
{
|
||||
killstreaks::register( "counteruav", "counteruav", "killstreak_counteruav", "counteruav_used", &ActivateCounterUAV );
|
||||
killstreaks::register_strings( "counteruav", &"KILLSTREAK_EARNED_COUNTERUAV", &"KILLSTREAK_COUNTERUAV_NOT_AVAILABLE", &"KILLSTREAK_COUNTERUAV_INBOUND", undefined, &"KILLSTREAK_COUNTERUAV_HACKED" );
|
||||
killstreaks::register_dialog( "counteruav", "mpl_killstreak_radar", "counterUavDialogBundle", "counterUavPilotDialogBundle", "friendlyCounterUav", "enemyCounterUav", "enemyCounterUavMultiple", "friendlyCounterUavHacked", "enemyCounterUavHacked", "requestCounterUav", "threatCounterUav" );
|
||||
}
|
||||
|
||||
clientfield::register( "toplayer", "counteruav", 1, 1, "int" );
|
||||
level thread WatchCounterUAVs();
|
||||
|
||||
callback::on_connect( &OnPlayerConnect );
|
||||
callback::on_spawned( &OnPlayerSpawned );
|
||||
callback::on_joined_team( &OnPlayerJoinedTeam );
|
||||
|
||||
/#
|
||||
if ( GetDvarInt( "scr_cuav_offset_debug" ) )
|
||||
level thread WaitAndDebugDrawOffsetList();
|
||||
#/
|
||||
|
||||
}
|
||||
|
||||
function OnPlayerConnect()
|
||||
{
|
||||
self.entNum = self getEntityNumber();
|
||||
|
||||
if( !level.teamBased )
|
||||
{
|
||||
level.activeCounterUAVs[ self.entNum ] = 0;
|
||||
level.counter_uav_position_index[ self.entNum ] = 0;
|
||||
self thread MovementManagerThink( self.entnum );
|
||||
}
|
||||
|
||||
level.activePlayerCounterUAVs[ self.entNum ] = 0;
|
||||
}
|
||||
|
||||
function OnPlayerSpawned()
|
||||
{
|
||||
if( self EnemyCounterUAVActive() )
|
||||
{
|
||||
self clientfield::set_to_player( "counteruav", 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
self clientfield::set_to_player( "counteruav", 0 );
|
||||
}
|
||||
}
|
||||
|
||||
function GenerateRandomPoints( count )
|
||||
{
|
||||
points = [];
|
||||
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
point = airsupport::GetRandomMapPoint(
|
||||
(isdefined(level.cuav_map_x_offset)?level.cuav_map_x_offset:0),
|
||||
(isdefined(level.cuav_map_y_offset)?level.cuav_map_y_offset:0),
|
||||
(isdefined(level.cuav_map_x_percentage)?level.cuav_map_x_percentage:( 0.50 )),
|
||||
(isdefined(level.cuav_map_y_percentage)?level.cuav_map_y_percentage:( 0.50 )) );
|
||||
|
||||
minFlyHeight = airsupport::getMinimumFlyHeight();
|
||||
point = point + ( 0, 0, minFlyHeight + (isdefined(level.counter_uav_position_z_offset)?level.counter_uav_position_z_offset:( 1000 )) );
|
||||
points[ i ] = point;
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
function MovementManagerThink( teamOrEntNum )
|
||||
{
|
||||
while( true )
|
||||
{
|
||||
level waittill( "counter_uav_updated" );
|
||||
|
||||
activeCount = 0;
|
||||
|
||||
while( level.activeCounterUAVs[ teamOrEntNum ] > 0 )
|
||||
{
|
||||
if( activeCount == 0 )
|
||||
{
|
||||
activeCount = level.activeCounterUAVs[ teamOrEntNum ];
|
||||
}
|
||||
|
||||
currentIndex = level.counter_uav_position_index[ teamOrEntNum ];
|
||||
newIndex = currentIndex;
|
||||
|
||||
while( newIndex == currentIndex )
|
||||
{
|
||||
newIndex = RandomIntRange( 0, ( 20 ) );
|
||||
}
|
||||
|
||||
destination = level.counter_uav_positions[ newIndex ];
|
||||
level.counter_uav_position_index[ teamOrEntNum ] = newIndex;
|
||||
|
||||
level notify( "counter_uav_move_" + teamOrEntNum );
|
||||
wait( ( 5 ) + RandomIntRange( ( 5 ), ( 10 ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function GetCurrentPosition( teamOrEntNum )
|
||||
{
|
||||
basePosition = level.counter_uav_positions[ level.counter_uav_position_index[ teamOrEntNum ] ];
|
||||
offset = level.counter_uav_offsets[ self.cuav_offset_index ];
|
||||
|
||||
return basePosition + offset;
|
||||
}
|
||||
|
||||
function AssignFirstAvailableOffsetIndex()
|
||||
{
|
||||
self.cuav_offset_index = GetFirstAvailableOffsetIndex();
|
||||
|
||||
MaintainCouterUavEntities();
|
||||
}
|
||||
|
||||
function GetFirstAvailableOffsetIndex()
|
||||
{
|
||||
// init available offset array
|
||||
available_offsets = [];
|
||||
for( i = 0; i < level.counter_uav_offsets.size; i++ )
|
||||
available_offsets[ i ] = true;
|
||||
|
||||
// update available offsets array
|
||||
foreach( cuav in level.counter_uav_entities )
|
||||
{
|
||||
if ( isdefined( cuav ) )
|
||||
{
|
||||
available_offsets[ cuav.cuav_offset_index ] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// return first available
|
||||
for( i = 0; i < available_offsets.size; i++ )
|
||||
{
|
||||
if ( available_offsets[ i ] )
|
||||
return i;
|
||||
}
|
||||
|
||||
/#util::warning("Max counter-uav available offset slots reached. Using slot 0 for now.");#/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function MaintainCouterUavEntities()
|
||||
{
|
||||
for( i = level.counter_uav_entities.size; i >= 0; i-- )
|
||||
{
|
||||
if ( !isdefined( level.counter_uav_entities[ i ] ) )
|
||||
{
|
||||
ArrayRemoveIndex( level.counter_uav_entities, i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/#
|
||||
function WaitAndDebugDrawOffsetList()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
|
||||
wait 10;
|
||||
DebugDrawOffsetList();
|
||||
}
|
||||
|
||||
function DebugDrawOffsetList()
|
||||
{
|
||||
basePosition = level.counter_uav_positions[ 0 ];
|
||||
|
||||
foreach ( offset in level.counter_uav_offsets )
|
||||
{
|
||||
util::debug_sphere( basePosition + offset, 24, ( 0.95, 0.05, 0.05 ), 0.75, 9999999 );
|
||||
}
|
||||
}
|
||||
#/
|
||||
|
||||
function BuildOffsetList( startOffset, depth, offset_x, offset_y )
|
||||
{
|
||||
offsets = [];
|
||||
for( col = 0; col < depth; col++ )
|
||||
{
|
||||
itemCount = math::pow( 2, col );
|
||||
startingIndex = ( itemCount - 1 );
|
||||
|
||||
for( i = 0; i < itemCount; i++ )
|
||||
{
|
||||
x = offset_x * col;
|
||||
|
||||
y = 0;
|
||||
if( itemCount > 1 )
|
||||
{
|
||||
y = ( i * offset_y );
|
||||
total_y = offset_y * startingIndex;
|
||||
y -= ( total_y / 2 );
|
||||
}
|
||||
|
||||
offsets[ startingIndex + i ] = startOffset + ( x, y, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
return offsets;
|
||||
}
|
||||
|
||||
function ActivateCounterUAV()
|
||||
{
|
||||
if( self killstreakrules::isKillstreakAllowed( "counteruav", self.team ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
killstreak_id = self killstreakrules::killstreakStart( "counteruav", self.team );
|
||||
if( killstreak_id == -1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
counterUav = SpawnCounterUAV( self, killstreak_id );
|
||||
if( !isdefined( counterUav ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
counterUAV SetScale( ( 1 ) );
|
||||
|
||||
counterUav clientfield::set( "enemyvehicle", 1 );
|
||||
counterUav.killstreak_id = killstreak_id;
|
||||
|
||||
counterUav thread killstreaks::WaitTillEMP( &DestroyCounterUavByEMP );
|
||||
counterUav thread killstreaks::WaitForTimeout( "counteruav", ( 30000 ), &OnTimeout, "delete", "death", "crashing" );
|
||||
counterUav thread killstreaks::WaitForTimecheck( ( ( 30000 ) / 2 ), &OnTimecheck, "delete", "death", "crashing" );
|
||||
counterUav thread util::WaitTillEndOnThreaded( "death", &DestroyCounterUav, "delete", "leaving" );
|
||||
|
||||
counterUav SetCanDamage( true );
|
||||
counterUav thread killstreaks::MonitorDamage( "counteruav", ( 700 ), &DestroyCounterUAV, ( ( 700 ) * 0.5 ), &OnLowHealth, 0, undefined, true );
|
||||
|
||||
counterUav PlayLoopSound( "veh_uav_engine_loop", 1 );
|
||||
|
||||
counterUav thread ListenForMove();
|
||||
|
||||
self killstreaks::play_killstreak_start_dialog( "counteruav", self.team, killstreak_id );
|
||||
counterUav killstreaks::play_pilot_dialog_on_owner( "arrive", "counteruav", killstreak_id );
|
||||
counterUav thread killstreaks::player_killstreak_threat_tracking( "counteruav" );
|
||||
self AddWeaponStat( GetWeapon( "counteruav" ), "used", 1 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function HackedPreFunction( hacker )
|
||||
{
|
||||
cuav = self;
|
||||
cuav ResetActiveCounterUAV();
|
||||
}
|
||||
|
||||
function SpawnCounterUAV( owner, killstreak_id )
|
||||
{
|
||||
minFlyHeight = airsupport::getMinimumFlyHeight();
|
||||
//cuav = spawn( "script_model", airsupport::GetMapCenter() + ( 0, 0, ( minFlyHeight + COUNTER_UAV_POSITION_Z_OFFSET ) ) );
|
||||
|
||||
cuav = SpawnVehicle( "veh_counteruav_mp", airsupport::GetMapCenter() + ( 0, 0, ( minFlyHeight + (isdefined(level.counter_uav_position_z_offset)?level.counter_uav_position_z_offset:( 1000 )) ) ), ( 0, 0, 0 ), "counteruav" );
|
||||
cuav AssignFirstAvailableOffsetIndex();
|
||||
|
||||
cuav killstreaks::configure_team( "counteruav", killstreak_id, owner, undefined, undefined, &ConfigureTeamPost );
|
||||
cuav killstreak_hacking::enable_hacking( "counteruav", &HackedPreFunction, undefined );
|
||||
|
||||
cuav.targetname = "counteruav";
|
||||
|
||||
killstreak_detect::killstreakTargetSet( cuav );
|
||||
|
||||
cuav thread heatseekingmissile::MissileTarget_ProximityDetonateIncomingMissile( "crashing", undefined, true );
|
||||
|
||||
cuav.maxhealth = ( 700 );
|
||||
cuav.health = 99999;
|
||||
cuav.rocketDamage = ( 700 ) + 1;
|
||||
|
||||
cuav SetDrawInfrared( true );
|
||||
|
||||
if ( !isdefined( level.counter_uav_entities ) ) level.counter_uav_entities = []; else if ( !IsArray( level.counter_uav_entities ) ) level.counter_uav_entities = array( level.counter_uav_entities ); level.counter_uav_entities[level.counter_uav_entities.size]=cuav;;
|
||||
|
||||
return cuav;
|
||||
}
|
||||
|
||||
|
||||
function ConfigureTeamPost( owner, isHacked )
|
||||
{
|
||||
cuav = self;
|
||||
|
||||
if ( isHacked == false )
|
||||
{
|
||||
cuav teams::HideToSameTeam();
|
||||
}
|
||||
else
|
||||
{
|
||||
cuav SetVisibleToAll();
|
||||
}
|
||||
cuav thread teams::WaitUntilTeamChangeSingleton( owner, "CUAV_watch_team_change", &OnTeamChange, self.entNum, "death", "leaving", "crashing" );
|
||||
cuav AddActiveCounterUAV();
|
||||
}
|
||||
|
||||
|
||||
function ListenForMove()
|
||||
{
|
||||
self endon( "death" );
|
||||
self endon( "leaving" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
self thread CounterUAVMove();
|
||||
level util::waittill_any( "counter_uav_move_" + self.team, "counter_uav_move_" + self.ownerEntNum );
|
||||
}
|
||||
}
|
||||
|
||||
function CounterUAVMove()
|
||||
{
|
||||
self endon( "death" );
|
||||
self endon( "leaving" );
|
||||
level endon( "counter_uav_move_" + self.team );
|
||||
|
||||
destination = ( 0, 0, 0 );
|
||||
|
||||
if( level.teamBased )
|
||||
{
|
||||
destination = self GetCurrentPosition( self.team );
|
||||
}
|
||||
else
|
||||
{
|
||||
destination = self GetCurrentPosition( self.ownerEntNum );
|
||||
}
|
||||
|
||||
lookAngles = VectorToAngles( destination - self.origin );
|
||||
rotationAccelerationDuration = ( 0.5 ) * ( 0.2 );
|
||||
rotationDecelerationDuration = ( 0.5 ) *( 0.2 );
|
||||
|
||||
// as a vehicle, we cannot use RotateTo anymore; we'll figure this out soon
|
||||
// self RotateTo( lookAngles, COUNTER_UAV_ROTATION_DURATION, rotationAccelerationDuration, rotationDecelerationDuration );
|
||||
// self waittill( "rotatedone" );
|
||||
|
||||
travelAccelerationDuration = ( 5 ) * ( 0.2 );
|
||||
travelDecelerationDuration = ( 5 ) * ( 0.2 );
|
||||
//self MoveTo( destination, COUNTER_UAV_SPEED, travelAccelerationDuration, travelDecelerationDuration );
|
||||
self SetVehGoalPos( destination, true, false );
|
||||
}
|
||||
|
||||
function PlayFx( name )
|
||||
{
|
||||
self endon( "death" );
|
||||
wait ( 0.1 );
|
||||
|
||||
if ( isdefined( self ) )
|
||||
{
|
||||
PlayFXOnTag( name, self, "tag_origin" );
|
||||
}
|
||||
}
|
||||
|
||||
function OnLowHealth( attacker, weapon )
|
||||
{
|
||||
self.is_damaged = true;
|
||||
params = level.killstreakBundle["counteruav"];
|
||||
if( isdefined( params.fxLowHealth ) )
|
||||
PlayFXOnTag( params.fxLowHealth, self, "tag_origin" );
|
||||
}
|
||||
|
||||
function OnTeamChange( entNum, event )
|
||||
{
|
||||
DestroyCounterUAV( undefined, undefined );
|
||||
}
|
||||
|
||||
function OnPlayerJoinedTeam()
|
||||
{
|
||||
HideAllCounterUAVsToSameTeam();
|
||||
}
|
||||
|
||||
function OnTimeout()
|
||||
{
|
||||
self.leaving = true;
|
||||
|
||||
self killstreaks::play_pilot_dialog_on_owner( "timeout", "counteruav" );
|
||||
|
||||
self airsupport::Leave( ( 5 ) );
|
||||
wait( ( 5 ) );
|
||||
self RemoveActiveCounterUAV();
|
||||
Target_Remove( self );
|
||||
self delete();
|
||||
}
|
||||
|
||||
function OnTimecheck()
|
||||
{
|
||||
self killstreaks::play_pilot_dialog_on_owner( "timecheck", "counteruav", self.killstreak_id );
|
||||
}
|
||||
|
||||
function DestroyCounterUavByEMP( attacker, arg )
|
||||
{
|
||||
DestroyCounterUav( attacker, GetWeapon( "emp" ) );
|
||||
}
|
||||
|
||||
function DestroyCounterUAV( attacker, weapon )
|
||||
{
|
||||
if ( self.leaving !== true )
|
||||
{
|
||||
self killstreaks::play_destroyed_dialog_on_owner( "counteruav", self.killstreak_id );
|
||||
}
|
||||
|
||||
attacker = self [[ level.figure_out_attacker ]]( attacker );
|
||||
if( isdefined( attacker ) && ( !isdefined( self.owner ) || self.owner util::IsEnemyPlayer( attacker ) ) )
|
||||
{
|
||||
challenges::destroyedAircraft( attacker, weapon, false );
|
||||
scoreevents::processScoreEvent( "destroyed_counter_uav", attacker, self.owner, weapon );
|
||||
LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_COUNTERUAV", attacker.entnum );
|
||||
attacker challenges::addFlySwatterStat( weapon, self );
|
||||
}
|
||||
|
||||
self PlaySound( "evt_helicopter_midair_exp" );
|
||||
self RemoveActiveCounterUAV();
|
||||
|
||||
if ( Target_IsTarget( self ) )
|
||||
{
|
||||
Target_Remove( self );
|
||||
}
|
||||
|
||||
self thread DeleteCounterUAV();
|
||||
}
|
||||
|
||||
function DeleteCounterUAV()
|
||||
{
|
||||
self notify( "crashing" );
|
||||
|
||||
params = level.killstreakBundle["counteruav"];
|
||||
if( isdefined( params.ksExplosionFX ) && isdefined( self ) )
|
||||
self thread PlayFx( params.ksExplosionFX );
|
||||
|
||||
wait( 0.1 );
|
||||
|
||||
if ( isdefined( self ) )
|
||||
{
|
||||
self setModel( "tag_origin" );
|
||||
}
|
||||
|
||||
wait( 0.2 );
|
||||
|
||||
if ( isdefined( self ) )
|
||||
{
|
||||
self notify( "delete" );
|
||||
self delete();
|
||||
}
|
||||
}
|
||||
|
||||
function EnemyCounterUAVActive()
|
||||
{
|
||||
if( level.teamBased )
|
||||
{
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
if( team == self.team )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( TeamHasActiveCounterUAV( team ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
enemies = self teams::GetEnemyPlayers();
|
||||
foreach( player in enemies )
|
||||
{
|
||||
if( player HasActiveCounterUAV() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function HasActiveCounterUAV()
|
||||
{
|
||||
return ( level.activeCounterUAVs[ self.entNum ] > 0 );
|
||||
}
|
||||
|
||||
function TeamHasActiveCounterUAV( team )
|
||||
{
|
||||
return ( level.activeCounterUAVs[ team ] > 0 );
|
||||
}
|
||||
|
||||
function HasIndexActiveCounterUAV( team_or_entnum )
|
||||
{
|
||||
return ( level.activeCounterUAVs[ team_or_entnum ] > 0 );
|
||||
}
|
||||
|
||||
|
||||
function AddActiveCounterUAV()
|
||||
{
|
||||
if ( level.teamBased )
|
||||
{
|
||||
level.activeCounterUAVs[ self.team ]++;
|
||||
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
if ( team == self.team )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( satellite::HasSatellite( team ) )
|
||||
{
|
||||
self.owner challenges::blockedSatellite();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
level.activeCounterUAVs[ self.ownerEntnum ]++;
|
||||
|
||||
keys = getarraykeys( level.activeCounterUAVs );
|
||||
for ( i = 0; i < keys.size; i++ )
|
||||
{
|
||||
if( keys[i] == self.ownerEntNum )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( satellite::HasSatellite( keys[i] ) )
|
||||
{
|
||||
self.owner challenges::blockedSatellite();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
level.activePlayerCounterUAVs[ self.ownerEntNum ]++;
|
||||
|
||||
level notify( "counter_uav_updated" );
|
||||
}
|
||||
|
||||
function RemoveActiveCounterUAV()
|
||||
{
|
||||
cuav = self;
|
||||
cuav ResetActiveCounterUAV();
|
||||
cuav killstreakrules::killstreakStop( "counteruav", self.originalteam, self.killstreak_id );
|
||||
}
|
||||
|
||||
function ResetActiveCounterUAV()
|
||||
{
|
||||
if ( level.teamBased )
|
||||
{
|
||||
level.activeCounterUAVs[ self.team ]--;
|
||||
assert( level.activeCounterUAVs[ self.team ] >= 0 );
|
||||
if ( level.activeCounterUAVs[ self.team ] < 0 )
|
||||
{
|
||||
level.activeCounterUAVs[ self.team ] = 0;
|
||||
}
|
||||
}
|
||||
else if ( isdefined( self.owner ) )
|
||||
{
|
||||
assert( isdefined( self.ownerEntNum ) );
|
||||
if ( !isdefined( self.ownerEntNum ) )
|
||||
{
|
||||
self.ownerEntNum = self.owner getEntityNumber();
|
||||
}
|
||||
|
||||
level.activeCounterUAVs[self.ownerEntNum ]--;
|
||||
|
||||
assert( level.activeCounterUAVs[ self.ownerEntNum ] >= 0 );
|
||||
if ( level.activeCounterUAVs[ self.ownerEntNum ] < 0 )
|
||||
{
|
||||
level.activeCounterUAVs[ self.ownerEntNum ] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
level.activePlayerCounterUAVs[ self.ownerEntNum ]--;
|
||||
|
||||
level notify ( "counter_uav_updated" );
|
||||
}
|
||||
|
||||
|
||||
function WatchCounterUAVs()
|
||||
{
|
||||
while( true )
|
||||
{
|
||||
level waittill( "counter_uav_updated" );
|
||||
|
||||
foreach( player in level.players )
|
||||
{
|
||||
if( player EnemyCounterUAVActive() )
|
||||
{
|
||||
player clientfield::set_to_player( "counteruav", 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
player clientfield::set_to_player( "counteruav", 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function HideAllCounterUAVsToSameTeam()
|
||||
{
|
||||
foreach( counteruav in level.counter_uav_entities )
|
||||
{
|
||||
if ( isdefined( counteruav ) )
|
||||
{
|
||||
counteruav teams::HideToSameTeam();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
#using scripts\shared\visionset_mgr_shared;
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#using scripts\shared\visionset_mgr_shared;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#namespace dart;
|
||||
|
||||
function autoexec __init__sytem__() { system::register("dart",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
clientfield::register( "toplayer", "dart_update_ammo", 1, 2, "int", &update_ammo, !true, !true );
|
||||
clientfield::register( "toplayer", "fog_bank_3", 1, 1, "int", &fog_bank_3_callback, !true, !true);
|
||||
|
||||
level.dartBundle = struct::get_script_bundle( "killstreak", "killstreak_dart" );
|
||||
vehicle::add_vehicletype_callback( level.dartBundle.ksDartVehicle,&spawned );
|
||||
visionset_mgr::register_visionset_info( "dart_visionset", 1, 1, undefined, "mp_vehicles_dart" );
|
||||
visionset_mgr::register_visionset_info( "sentinel_visionset", 1, 1, undefined, "mp_vehicles_sentinel" );
|
||||
visionset_mgr::register_visionset_info( "remote_missile_visionset", 1, 1, undefined, "mp_hellstorm" );
|
||||
}
|
||||
|
||||
function update_ammo( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
SetUIModelValue( GetUIModel( GetUIModelForController( localClientNum ), "vehicle.ammo" ), newVal );
|
||||
|
||||
// /# IPrintLnBold( "Dart Ammo Count: " + newVal ); #/
|
||||
}
|
||||
|
||||
function spawned(localClientNum)
|
||||
{
|
||||
self.killstreakBundle = level.dartBundle;
|
||||
}
|
||||
|
||||
function fog_bank_3_callback(localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump)
|
||||
{
|
||||
if ( oldVal != newVal )
|
||||
{
|
||||
if ( newVal == 1 )
|
||||
{
|
||||
SetWorldFogActiveBank(localClientNum, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWorldFogActiveBank(localClientNum, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,827 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\challenges_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\hostmigration_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\popups_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
#using scripts\shared\vehicle_death_shared;
|
||||
#using scripts\shared\weapons\_hacker_tool;
|
||||
#using scripts\shared\scoreevents_shared;
|
||||
#using scripts\shared\math_shared;
|
||||
#using scripts\shared\weapons\_heatseekingmissile;
|
||||
#using scripts\mp\killstreaks\_qrdrone;
|
||||
#using scripts\mp\killstreaks\_airsupport;
|
||||
#using scripts\shared\vehicle_ai_shared;
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\gametypes\_shellshock;
|
||||
#using scripts\mp\killstreaks\_killstreak_bundles;
|
||||
#using scripts\mp\killstreaks\_killstreak_detect;
|
||||
#using scripts\mp\killstreaks\_killstreak_hacking;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_remote_weapons;
|
||||
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
#using scripts\shared\visionset_mgr_shared;
|
||||
|
||||
#namespace dart;
|
||||
|
||||
|
||||
|
||||
|
||||
#precache( "string", "KILLSTREAK_DART_HACKED" );
|
||||
#precache( "string", "KILLSTREAK_DART_EARNED" );
|
||||
#precache( "string", "KILLSTREAK_DART_NOT_AVAILABLE" );
|
||||
#precache( "string", "KILLSTREAK_DART_INBOUND" );
|
||||
#precache( "string", "KILLSTREAK_DART_HACKED" );
|
||||
#precache( "string", "KILLSTREAK_DESTROYED_DART" );
|
||||
#precache( "string", "mpl_killstreak_dart_strt" );
|
||||
|
||||
function init()
|
||||
{
|
||||
killstreaks::register( "dart", "dart", "killstreak_dart", "dart_used", &ActivateDart, true) ;
|
||||
killstreaks::register_strings( "dart", &"KILLSTREAK_DART_EARNED", &"KILLSTREAK_DART_NOT_AVAILABLE", &"KILLSTREAK_DART_INBOUND", undefined, &"KILLSTREAK_DART_HACKED" );
|
||||
killstreaks::register_dialog( "dart", "mpl_killstreak_dart_strt", "dartDialogBundle", "dartPilotDialogBundle", "friendlyDart", "enemyDart", "enemyDartMultiple", "friendlyDartHacked", "enemyDartHacked", "requestDart", "threatDart" );
|
||||
killstreaks::override_entity_camera_in_demo( "dart", true );
|
||||
|
||||
killstreaks::register_alt_weapon( "dart", "killstreak_remote" );
|
||||
killstreaks::register_alt_weapon( "dart", "dart_blade" );
|
||||
killstreaks::register_alt_weapon( "dart", "dart_turret" );
|
||||
|
||||
clientfield::register( "toplayer", "dart_update_ammo", 1, 2, "int" );
|
||||
clientfield::register( "toplayer", "fog_bank_3", 1, 1, "int" );
|
||||
|
||||
remote_weapons::RegisterRemoteWeapon( "dart", &"", &StartDartRemoteControl, &EndDartRemoteControl, true );
|
||||
|
||||
visionset_mgr::register_info( "visionset", "dart_visionset", 1, 90, 16, true, &visionset_mgr::ramp_in_out_thread_per_player_death_shutdown, false );
|
||||
}
|
||||
|
||||
function wait_dart_timed_out( time )
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
self endon( "death" );
|
||||
self endon( "dart_throw_failed" );
|
||||
self endon( "dart_entered" );
|
||||
|
||||
wait( time );
|
||||
|
||||
self notify( "dart_throw_timed_out" );
|
||||
}
|
||||
|
||||
function wait_for_throw_status()
|
||||
{
|
||||
thread dart::wait_dart_timed_out( 5 );
|
||||
|
||||
notifyString = self util::waittill_any_return( "death", "disconnect", "dart_entered", "dart_throw_timed_out","dart_throw_failed" );
|
||||
|
||||
if ( notifyString == "dart_entered" || notifyString == "death" )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function ActivateDart( killstreakType )
|
||||
{
|
||||
player = self;
|
||||
|
||||
assert( IsPlayer( player ) );
|
||||
|
||||
if( !player killstreakrules::isKillstreakAllowed( "dart", player.team ) )
|
||||
return false;
|
||||
|
||||
player DisableOffhandWeapons();
|
||||
|
||||
missileWeapon = player GetCurrentWeapon();
|
||||
if( !( isdefined( missileWeapon ) && ( ( missileWeapon.name == "dart" ) || ( missileWeapon.name == "inventory_dart" ) ) ) )
|
||||
return false;
|
||||
|
||||
player thread WatchThrow( missileWeapon );
|
||||
|
||||
notifyString = player util::waittill_any_return( "weapon_change", "grenade_fire", "death", "disconnect", "joined_team", "emp_jammed", "emp_grenaded" );
|
||||
|
||||
if( notifyString == "death" || notifyString == "emp_jammed" || notifyString == "emp_grenaded" )
|
||||
{
|
||||
///#iprintln( "death" );#/
|
||||
if( player.waitingOnDartThrow )
|
||||
player notify( "dart_putaway" );
|
||||
|
||||
player EnableOffhandWeapons();
|
||||
return false;
|
||||
}
|
||||
|
||||
if( notifyString == "grenade_fire" )
|
||||
{
|
||||
// wait for the killStreakStart results
|
||||
return player wait_for_throw_status();
|
||||
}
|
||||
|
||||
if( notifyString == "weapon_change" )
|
||||
{
|
||||
if( player.waitingOnDartThrow )
|
||||
player notify( "dart_putaway" );
|
||||
|
||||
player EnableOffhandWeapons();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function cleanup_grenade()
|
||||
{
|
||||
self thread waitThenDelete( 0.05 );
|
||||
self.origin = self.origin + ( 0, 0, 1000 );
|
||||
}
|
||||
|
||||
function WatchThrow( missileWeapon )
|
||||
{
|
||||
assert( IsPlayer( self ) );
|
||||
player = self;
|
||||
playerEntNum = player.entNum;
|
||||
|
||||
player endon( "disconnect" );
|
||||
player endon( "joined_team" );
|
||||
// player endon( "death" ); // once the dart is thrown, even after death, the player should control it
|
||||
player endon( "dart_putaway" );
|
||||
|
||||
level endon( "game_ended" );
|
||||
|
||||
player.waitingOnDartThrow = 1;
|
||||
player waittill( "grenade_fire", grenade, weapon );
|
||||
player.waitingOnDartThrow = 0;
|
||||
|
||||
if( weapon != missileWeapon )
|
||||
{
|
||||
self notify("dart_throw_failed");
|
||||
return;
|
||||
}
|
||||
|
||||
trace = player check_launch_space(grenade.origin);
|
||||
|
||||
if ( trace["fraction"] < 1.0 )
|
||||
{
|
||||
self iprintlnbold( &"KILLSTREAK_DART_NOT_AVAILABLE" );
|
||||
grenade cleanup_grenade();
|
||||
self notify("dart_throw_failed");
|
||||
return;
|
||||
}
|
||||
|
||||
killstreak_id = player killstreakrules::killstreakStart( "dart", player.team, undefined, false );
|
||||
if( killstreak_id == (-1) )
|
||||
{
|
||||
grenade cleanup_grenade();
|
||||
self notify("dart_throw_failed");
|
||||
return;
|
||||
}
|
||||
|
||||
player.dart_thrown_time = GetTime();
|
||||
|
||||
player TakeWeapon( missileWeapon );
|
||||
|
||||
player killstreaks::set_killstreak_delay_killcam( "dart" ); // special case: death while watching does not prevent riding dart, and thus no killcam
|
||||
player.resurrect_not_allowed_by = "dart";
|
||||
|
||||
player AddWeaponStat( GetWeapon( "dart" ), "used", 1 );
|
||||
level thread popups::DisplayKillstreakTeamMessageToAll( "dart", player );
|
||||
|
||||
dart = player SpawnDart( grenade, killstreak_id, trace["position"] );
|
||||
if( isdefined( dart ) )
|
||||
{
|
||||
player killstreaks::play_killstreak_start_dialog( "dart", player.team, killstreak_id );
|
||||
}
|
||||
}
|
||||
|
||||
function HackedPreFunction( hacker )
|
||||
{
|
||||
dart = self;
|
||||
dart.owner util::freeze_player_controls( false );
|
||||
visionset_mgr::deactivate( "visionset", "dart_visionset", dart.owner );
|
||||
dart.owner clientfield::set_to_player( "fog_bank_3", 0 );
|
||||
dart.owner unlink();
|
||||
dart clientfield::set( "vehicletransition", 0 );
|
||||
dart.owner killstreaks::clear_using_remote();
|
||||
dart.owner killstreaks::unhide_compass();
|
||||
dart.owner vehicle::stop_monitor_missiles_locked_on_to_me();
|
||||
dart.owner vehicle::stop_monitor_damage_as_occupant();
|
||||
dart DisableDartMissileLocking();
|
||||
}
|
||||
|
||||
function HackedPostFunction( hacker )
|
||||
{
|
||||
dart = self;
|
||||
hacker StartDartRemoteControl( dart );
|
||||
|
||||
hacker killstreak_hacking::set_vehicle_drivable_time_starting_now( dart );
|
||||
hacker remote_weapons::UseRemoteWeapon( dart, "dart", false );
|
||||
hacker killstreaks::set_killstreak_delay_killcam( "dart" );
|
||||
}
|
||||
|
||||
function dart_hacked_health_update( hacker )
|
||||
{
|
||||
dart = self;
|
||||
if ( dart.health > dart.hackedhealth )
|
||||
{
|
||||
dart.health = dart.hackedhealth;
|
||||
}
|
||||
}
|
||||
|
||||
function check_launch_space(origin)
|
||||
{
|
||||
player_angles = self getPlayerAngles();
|
||||
forward = AnglesToForward( player_angles );
|
||||
spawn_origin = origin + VectorScale( forward, 50 );
|
||||
|
||||
radius = 10;
|
||||
return physicstrace( origin, spawn_origin, ( -radius, -radius, 0 ), ( radius, radius, 2 * radius ), self, (1 << 0) );
|
||||
}
|
||||
|
||||
function SpawnDart( grenade, killstreak_id, spawn_origin )
|
||||
{
|
||||
///#iprintln( "Spawn Dart" );#/
|
||||
player = self;
|
||||
assert( IsPlayer( player ) );
|
||||
playerEntNum = player.entNum;
|
||||
player_angles = player getPlayerAngles();
|
||||
|
||||
grenade cleanup_grenade();
|
||||
|
||||
params = level.killstreakBundle["dart"];
|
||||
|
||||
if(!isdefined(params.ksDartVehicle))params.ksDartVehicle="veh_dart_mp";
|
||||
if(!isdefined(params.ksDartInitialSpeed))params.ksDartInitialSpeed=35;
|
||||
if(!isdefined(params.ksDartAcceleration))params.ksDartAcceleration=35;
|
||||
|
||||
dart = SpawnVehicle( params.ksDartVehicle, spawn_origin, player_angles, "dynamic_spawn_ai" );
|
||||
|
||||
//dart thread debug_origin();
|
||||
|
||||
dart.is_shutting_down = 0;
|
||||
dart.team = player.team;
|
||||
dart SetSpeedImmediate( params.ksDartInitialSpeed, params.ksDartAcceleration );
|
||||
dart.maxhealth = killstreak_bundles::get_max_health( "dart" );
|
||||
dart.health = dart.maxhealth;
|
||||
dart.hackedhealth = killstreak_bundles::get_hacked_health( "dart" );
|
||||
dart.hackedHealthUpdateCallback = &dart_hacked_health_update;
|
||||
|
||||
dart killstreaks::configure_team( "dart", killstreak_id, player, "small_vehicle" );
|
||||
dart killstreak_hacking::enable_hacking( "dart", &HackedPreFunction, &HackedPostFunction );
|
||||
|
||||
dart clientfield::set( "enemyvehicle", 1 );
|
||||
dart.killstreak_id = killstreak_id;
|
||||
dart.hardpointType = "dart";
|
||||
dart thread killstreaks::WaitForTimeout( "dart", ( 30 * 1000 ), &stop_remote_weapon, "remote_weapon_end", "death" );
|
||||
dart hacker_tool::registerWithhackerTool( ( 50 ), ( 2000 ) );
|
||||
dart.overrideVehicleDamage = &dartDamageOverride;
|
||||
dart.DetonateViaEMP = &emp_damage_cb;
|
||||
dart.do_scripted_crash = false;
|
||||
dart.delete_on_death = true;
|
||||
dart.one_remote_use = true;
|
||||
dart.vehcheckforpredictedcrash = true;
|
||||
dart.predictedCollisionTime = 0.2;
|
||||
dart.glasscollision_alt = true;
|
||||
dart.damageTaken = 0;
|
||||
dart.death_enter_cb = &waitRemoteControl;
|
||||
|
||||
Target_Set( dart );
|
||||
|
||||
dart vehicle::init_target_group();
|
||||
dart vehicle::add_to_target_group( dart );
|
||||
|
||||
dart thread WatchCollision();
|
||||
|
||||
dart thread WatchDeath();
|
||||
|
||||
dart thread WatchOwnerNonDeathEvents();
|
||||
|
||||
dart.forceWaitRemoteControl = true;
|
||||
|
||||
player util::waittill_any( "weapon_change", "death" ); // wait for the killstreak weapon to go away, or the player dies (special case for Dart)
|
||||
|
||||
player remote_weapons::UseRemoteWeapon( dart, "dart", true, true, true );
|
||||
|
||||
player notify( "dart_entered" );
|
||||
|
||||
return dart;
|
||||
}
|
||||
|
||||
function debug_origin()
|
||||
{
|
||||
self endon( "death" );
|
||||
while( 1 )
|
||||
{
|
||||
/#sphere( self.origin, 5, ( 1.0, 0, 0 ), 1.0, true, 2, 120 );#/
|
||||
{wait(.05);};
|
||||
}
|
||||
}
|
||||
|
||||
function waitRemoteControl()
|
||||
{
|
||||
dart = self;
|
||||
|
||||
remote_controlled = ( isdefined( dart.control_initiated ) && dart.control_initiated ) || ( isdefined( dart.controlled ) && dart.controlled );
|
||||
|
||||
if( remote_controlled )
|
||||
{
|
||||
notifyString = dart util::waittill_any_return( "remote_weapon_end", "dart_left" );
|
||||
if ( isdefined( notifyString ) )
|
||||
{
|
||||
if( notifyString == "remote_weapon_end" )
|
||||
dart waittill( "dart_left" );
|
||||
else
|
||||
dart waittill( "remote_weapon_end" );
|
||||
}
|
||||
}
|
||||
else
|
||||
dart waittill( "dart_left" );
|
||||
}
|
||||
|
||||
function StartDartRemoteControl( dart )
|
||||
{
|
||||
///#iprintln( "StartDartRemoteControl" );#/
|
||||
player = self;
|
||||
assert( IsPlayer( player ) );
|
||||
|
||||
if( !dart.is_shutting_down )
|
||||
{
|
||||
player.dart_thrown_time = undefined;
|
||||
|
||||
///#iprintln( "UseVehicle" );#/
|
||||
dart UseVehicle( player, 0 );///
|
||||
player.resurrect_not_allowed_by = undefined;
|
||||
dart clientfield::set( "vehicletransition", 1 );
|
||||
dart thread WatchAmmo();
|
||||
dart thread vehicle::monitor_missiles_locked_on_to_me( player );
|
||||
dart thread vehicle::monitor_damage_as_occupant( player );
|
||||
|
||||
player vehicle::set_vehicle_drivable_time_starting_now( ( 30 * 1000 ) );
|
||||
player.no_fade2black = true;
|
||||
|
||||
dart.inHeliProximity = false;
|
||||
|
||||
minHeightOverride = undefined;
|
||||
minz_struct = struct::get( "vehicle_oob_minz", "targetname");
|
||||
if( isdefined( minz_struct ) )
|
||||
minHeightOverride = minz_struct.origin[2];
|
||||
|
||||
dart thread qrdrone::QRDrone_watch_distance( ( 2000 ), minHeightOverride );
|
||||
dart.distance_shutdown_override = &DartDistanceFailure;
|
||||
|
||||
dart EnableDartMissileLocking();
|
||||
visionset_mgr::activate( "visionset", "dart_visionset", self, 1, 90000, 1 );
|
||||
player clientfield::set_to_player( "fog_bank_3", 1 );
|
||||
}
|
||||
}
|
||||
|
||||
function EndDartRemoteControl( dart, exitRequestedByOwner )
|
||||
{
|
||||
dart thread leave_dart();
|
||||
}
|
||||
|
||||
function DartDistanceFailure()
|
||||
{
|
||||
thread stop_remote_weapon();
|
||||
}
|
||||
|
||||
function stop_remote_weapon( attacker, weapon )
|
||||
{
|
||||
dart = self;
|
||||
|
||||
dart.DetonateViaEMP = undefined;
|
||||
|
||||
attacker = self [[ level.figure_out_attacker ]]( attacker );
|
||||
if ( isdefined( attacker ) && ( !isdefined( dart.owner ) || dart.owner util::IsEnemyPlayer( attacker ) ) )
|
||||
{
|
||||
challenges::destroyedAircraft( attacker, weapon, true );
|
||||
attacker challenges::addFlySwatterStat( weapon, self );
|
||||
scoreevents::processScoreEvent( "destroyed_dart", attacker, dart.owner, weapon );
|
||||
LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_DART", attacker.entnum );
|
||||
}
|
||||
|
||||
if( isdefined( attacker ) && attacker != dart.owner )
|
||||
{
|
||||
dart killstreaks::play_destroyed_dialog_on_owner( "dart", dart.killstreak_id );
|
||||
}
|
||||
|
||||
dart thread remote_weapons::EndRemoteControlWeaponUse( false );
|
||||
}
|
||||
|
||||
function dartDamageOverride( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
|
||||
{
|
||||
dart = self;
|
||||
|
||||
if( ( sMeansOfDeath == "MOD_TRIGGER_HURT" ) || ( isdefined( dart.is_shutting_down ) && dart.is_shutting_down ) )
|
||||
return 0;
|
||||
|
||||
player = dart.owner;
|
||||
|
||||
iDamage = killstreaks::OnDamagePerWeapon( "dart", eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, self.maxhealth, &stop_remote_weapon, self.maxhealth*0.4, undefined,
|
||||
0, &emp_damage_cb, true, 1.0 );
|
||||
|
||||
return iDamage;
|
||||
}
|
||||
|
||||
function emp_damage_cb( attacker, weapon )
|
||||
{
|
||||
dart = self;
|
||||
dart stop_remote_weapon( attacker, weapon );
|
||||
}
|
||||
|
||||
function DarPredictedCollision()
|
||||
{
|
||||
self endon( "death" );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
self waittill( "veh_predictedcollision", velocity, normal, ent, stype );
|
||||
self notify( "veh_collision", velocity, normal, ent, stype );
|
||||
|
||||
if( stype == "glass" )
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function WatchCollision()
|
||||
{
|
||||
dart = self;
|
||||
dart endon( "death" );
|
||||
dart.owner endon( "disconnect" );
|
||||
|
||||
dart thread DarPredictedCollision();
|
||||
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
dart waittill( "veh_collision", velocity, normal, ent, stype );
|
||||
|
||||
///#sphere( dart.origin, 5, ( 1.0, 0, 0 ), 1.0, true, 100, 120 );#/
|
||||
if( stype === "glass" )
|
||||
continue;
|
||||
|
||||
dart SetSpeedImmediate( 0 );
|
||||
dart vehicle_death::death_fx();
|
||||
|
||||
dart thread stop_remote_weapon();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function WatchDeath()
|
||||
{
|
||||
dart = self;
|
||||
player = dart.owner;
|
||||
|
||||
player endon( "dart_entered" ); // the remote weapon script should handle it from here on
|
||||
dart endon( "delete" );
|
||||
|
||||
dart waittill( "death" );
|
||||
//dart waittill( "death", attacker, damageFromUnderneath, weapon, point, dir, modType );
|
||||
|
||||
dart thread leave_dart();
|
||||
}
|
||||
|
||||
function WatchOwnerNonDeathEvents( endCondition1, endCondition2 )
|
||||
{
|
||||
dart = self;
|
||||
player = dart.owner;
|
||||
|
||||
player endon( "dart_entered" ); // the remote weapon script should handle it from here on
|
||||
dart endon( "death" );
|
||||
|
||||
dart thread WatchForGameEnd();
|
||||
|
||||
player util::waittill_any( "joined_team", "disconnect", "joined_spectators", "emp_jammed" );
|
||||
|
||||
dart thread leave_dart();
|
||||
}
|
||||
|
||||
function WatchForGameEnd()
|
||||
{
|
||||
dart = self;
|
||||
dart endon( "death" );
|
||||
|
||||
level waittill( "game_ended" );
|
||||
|
||||
dart thread leave_dart();
|
||||
}
|
||||
|
||||
function WatchAmmo()
|
||||
{
|
||||
dart = self;
|
||||
dart endon( "death" );
|
||||
|
||||
player = dart.owner;
|
||||
|
||||
player endon( "disconnect" );
|
||||
|
||||
shotCount = 0;
|
||||
|
||||
params = level.killstreakBundle["dart"];
|
||||
|
||||
if(!isdefined(params.ksDartShotCount))params.ksDartShotCount=3;
|
||||
if(!isdefined(params.ksDartBladeCount))params.ksDartBladeCount=6;
|
||||
if(!isdefined(params.ksDartWaitTimeAfterLastShot))params.ksDartWaitTimeAfterLastShot=1;
|
||||
|
||||
if(!isdefined(params.ksBladeStartDistance))params.ksBladeStartDistance=0;
|
||||
if(!isdefined(params.ksBladeEndDistance))params.ksBladeEndDistance=10000;
|
||||
if(!isdefined(params.ksBladeStartSpreadRadius))params.ksBladeStartSpreadRadius=50;
|
||||
if(!isdefined(params.ksBladeEndSpreadRadius))params.ksBladeEndSpreadRadius=1;
|
||||
|
||||
player clientfield::set_to_player( "dart_update_ammo", params.ksDartShotCount );
|
||||
|
||||
while( true )
|
||||
{
|
||||
dart waittill( "weapon_fired" );
|
||||
shotCount++;
|
||||
|
||||
player clientfield::set_to_player( "dart_update_ammo", params.ksDartShotCount - shotCount );
|
||||
|
||||
if( shotCount >= params.ksDartShotCount )
|
||||
{
|
||||
dart DisableDriverFiring( true );
|
||||
wait( params.ksDartWaitTimeAfterLastShot );
|
||||
dart stop_remote_weapon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function leave_dart()
|
||||
{
|
||||
dart = self;
|
||||
owner = dart.owner;
|
||||
|
||||
if( isdefined( owner ) )
|
||||
{
|
||||
visionset_mgr::deactivate( "visionset", "dart_visionset", owner );
|
||||
owner clientfield::set_to_player( "fog_bank_3", 0 );
|
||||
owner qrdrone::destroyHud();
|
||||
}
|
||||
|
||||
if( isdefined( dart ) && ( dart.is_shutting_down == 1 ) )
|
||||
return;
|
||||
|
||||
dart.is_shutting_down = 1;
|
||||
|
||||
dart clientfield::set( "timeout_beep", 0 );
|
||||
dart vehicle::lights_off();
|
||||
dart vehicle_death::death_fx();
|
||||
dart Hide();
|
||||
|
||||
dart_original_team = dart.originalteam;
|
||||
dart_killstreak_id = dart.killstreak_id;
|
||||
|
||||
if( Target_IsTarget( dart ) )
|
||||
Target_Remove( dart );
|
||||
|
||||
iF( isalive( dart ) )
|
||||
dart notify( "death" );
|
||||
|
||||
params = level.killstreakBundle["dart"];
|
||||
|
||||
if(!isdefined(params.ksDartExplosionOuterRadius))params.ksDartExplosionOuterRadius=200;
|
||||
if(!isdefined(params.ksDartExplosionInnerRadius))params.ksDartExplosionInnerRadius=1;
|
||||
if(!isdefined(params.ksDartExplosionOuterDamage))params.ksDartExplosionOuterDamage=25;
|
||||
if(!isdefined(params.ksDartExplosionInnerDamage))params.ksDartExplosionInnerDamage=350;
|
||||
if(!isdefined(params.ksDartExplosionMagnitude))params.ksDartExplosionMagnitude=1;
|
||||
|
||||
PhysicsExplosionSphere( dart.origin,
|
||||
params.ksDartExplosionOuterRadius,
|
||||
params.ksDartExplosionInnerRadius,
|
||||
params.ksDartExplosionMagnitude,
|
||||
params.ksDartExplosionOuterDamage,
|
||||
params.ksDartExplosionInnerDamage );
|
||||
|
||||
if( isdefined( owner ) )
|
||||
{
|
||||
owner killstreaks::set_killstreak_delay_killcam( "dart" ); // hold the respawn till we finish here
|
||||
|
||||
dart RadiusDamage( dart.origin,
|
||||
params.ksDartExplosionOuterRadius,
|
||||
params.ksDartExplosionInnerDamage,
|
||||
params.ksDartExplosionOuterDamage,
|
||||
owner,
|
||||
"MOD_EXPLOSIVE",
|
||||
GetWeapon( "dart" ) );
|
||||
|
||||
owner thread play_bda_dialog( self.pilotIndex );
|
||||
|
||||
if( ( isdefined( dart.controlled ) && dart.controlled ) || ( isdefined( dart.control_initiated ) && dart.control_initiated ) )
|
||||
{
|
||||
owner SetClientUIVisibilityFlag( "hud_visible", 0 );
|
||||
owner unlink();
|
||||
dart clientfield::set( "vehicletransition", 0 );
|
||||
|
||||
if( isdefined( params.ksExplosionRumble ) )
|
||||
owner PlayRumbleOnEntity( params.ksExplosionRumble );
|
||||
|
||||
owner vehicle::stop_monitor_missiles_locked_on_to_me();
|
||||
owner vehicle::stop_monitor_damage_as_occupant();
|
||||
|
||||
dart DisableDartMissileLocking();
|
||||
|
||||
owner util::freeze_player_controls( true );
|
||||
|
||||
forward = AnglesToForward( dart.angles );
|
||||
if(!isdefined(params.ksDartCameraWatchDistance))params.ksDartCameraWatchDistance=350;
|
||||
moveAmount = VectorScale( forward, -( params.ksDartCameraWatchDistance ) );
|
||||
|
||||
size = 4;
|
||||
trace = physicstrace( dart.origin, dart.origin + moveAmount, ( -size, -size, -size ), ( size, size, size ), undefined, (1 << 0) );
|
||||
|
||||
cam = spawn( "script_model", trace["position"] );
|
||||
cam SetModel( "tag_origin" );
|
||||
cam LinkTo( dart );
|
||||
dart SetSpeedImmediate( 0 );
|
||||
|
||||
owner CameraSetPosition( cam.origin );
|
||||
owner CameraSetLookAt( dart.origin );
|
||||
owner CameraActivate( true );
|
||||
|
||||
if(!isdefined(params.ksDartCameraWatchDuration))params.ksDartCameraWatchDuration=2;
|
||||
wait( params.ksDartCameraWatchDuration );
|
||||
|
||||
if ( isdefined( owner ) )
|
||||
{
|
||||
owner CameraActivate( false );
|
||||
}
|
||||
|
||||
cam delete();
|
||||
|
||||
if( isdefined( owner ) )
|
||||
{
|
||||
if( !level.gameEnded )
|
||||
owner util::freeze_player_controls( false );
|
||||
|
||||
owner SetClientUIVisibilityFlag( "hud_visible", 1 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isdefined( owner ) )
|
||||
{
|
||||
owner killstreaks::reset_killstreak_delay_killcam();
|
||||
}
|
||||
}
|
||||
|
||||
killstreakrules::killstreakStop( "dart", dart_original_team, dart_killstreak_id );
|
||||
|
||||
if ( isdefined( dart ) )
|
||||
{
|
||||
dart notify( "dart_left" );
|
||||
}
|
||||
}
|
||||
|
||||
function DeleteOnConditions( condition )
|
||||
{
|
||||
dart = self;
|
||||
dart endon( "delete" );
|
||||
|
||||
if( isdefined( condition ) )
|
||||
dart waittill( condition );
|
||||
|
||||
dart notify( "delete" );
|
||||
dart delete();
|
||||
}
|
||||
|
||||
function waitThenDelete( waitTime )
|
||||
{
|
||||
self endon( "delete" );
|
||||
self endon( "death" );
|
||||
wait( waitTime );
|
||||
self delete();
|
||||
}
|
||||
|
||||
function play_bda_dialog( pilotIndex )
|
||||
{
|
||||
self endon( "game_ended" );
|
||||
|
||||
wait( 0.5 );
|
||||
|
||||
if ( !isdefined( self.dartBda ) || self.dartBda == 0 )
|
||||
{
|
||||
bdaDialog = "killNone";
|
||||
}
|
||||
else if ( self.dartBda == 1 )
|
||||
{
|
||||
bdaDialog = "kill1";
|
||||
}
|
||||
else if ( self.dartBda == 2 )
|
||||
{
|
||||
bdaDialog = "kill2";
|
||||
}
|
||||
else if ( self.dartBda == 3 )
|
||||
{
|
||||
bdaDialog = "kill3";
|
||||
}
|
||||
else if ( self.dartBda > 3 )
|
||||
{
|
||||
bdaDialog = "killMultiple";
|
||||
}
|
||||
|
||||
self killstreaks::play_pilot_dialog( bdaDialog, "dart", undefined, pilotIndex );
|
||||
|
||||
self.dartBda = undefined;
|
||||
}
|
||||
|
||||
function EnableDartMissileLocking() // self == dart
|
||||
{
|
||||
dart = self;
|
||||
player = dart.owner;
|
||||
weapon = dart SeatGetWeapon( 0 );
|
||||
|
||||
player.get_stinger_target_override = &GetDartMissileTargets;
|
||||
player.is_still_valid_target_for_stinger_override = &IsStillValidDartMissileTarget;
|
||||
player.is_valid_target_for_stinger_override = &IsValidDartMissileTarget;
|
||||
player.dart_killstreak_weapon = weapon;
|
||||
|
||||
player thread heatseekingmissile::StingerIRTLoop( weapon );
|
||||
}
|
||||
|
||||
function DisableDartMissileLocking() // self == dart
|
||||
{
|
||||
player = self.owner;
|
||||
|
||||
player.get_stinger_target_override = undefined;
|
||||
player.is_still_valid_target_for_stinger_override = undefined;
|
||||
player.is_valid_target_for_stinger_override = undefined;
|
||||
player.dart_killstreak_weapon = undefined;
|
||||
|
||||
player notify( "stinger_IRT_off" );
|
||||
player heatseekingmissile::ClearIRTarget();
|
||||
}
|
||||
|
||||
function GetDartMissileTargets()
|
||||
{
|
||||
targets = ArrayCombine( target_getArray(), level.MissileEntities, false, false );
|
||||
targets = ArrayCombine( targets, level.players, false, false );
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
function IsValidDartMissileTarget( ent ) // self == player
|
||||
{
|
||||
player = self;
|
||||
|
||||
if ( !isdefined( ent ) )
|
||||
return false;
|
||||
|
||||
entIsPlayer = IsPlayer( ent );
|
||||
|
||||
if ( entIsPlayer && !IsAlive( ent ) )
|
||||
return false;
|
||||
|
||||
if ( ent.ignoreme === true )
|
||||
return false;
|
||||
|
||||
dart = player GetVehicleOccupied();
|
||||
if ( !isdefined( dart ) )
|
||||
return false;
|
||||
|
||||
if ( DistanceSquared( dart.origin, ent.origin ) > ( (player.dart_killstreak_weapon.lockOnMaxRange) * (player.dart_killstreak_weapon.lockOnMaxRange) ) )
|
||||
return false;
|
||||
|
||||
if ( entIsPlayer && ent HasPerk( "specialty_nokillstreakreticle" ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function IsStillValidDartMissileTarget( ent, weapon ) // self == player
|
||||
{
|
||||
player = self;
|
||||
|
||||
if ( !( target_isTarget( ent ) || IsPlayer( ent ) ) && !( isdefined( ent.allowContinuedLockonAfterInvis ) && ent.allowContinuedLockonAfterInvis ) )
|
||||
return false;
|
||||
|
||||
dart = player GetVehicleOccupied();
|
||||
if ( !isdefined( dart ) )
|
||||
return false;
|
||||
|
||||
entIsPlayer = IsPlayer( ent );
|
||||
|
||||
if ( entIsPlayer && !IsAlive( ent ) )
|
||||
return false;
|
||||
|
||||
if ( ent.ignoreme === true )
|
||||
return false;
|
||||
|
||||
if ( DistanceSquared( dart.origin, ent.origin ) > ( (player.dart_killstreak_weapon.lockOnMaxRange) * (player.dart_killstreak_weapon.lockOnMaxRange) ) )
|
||||
return false;
|
||||
|
||||
if ( entIsPlayer && ent HasPerk( "specialty_nokillstreakreticle" ) )
|
||||
return false;
|
||||
|
||||
if ( !heatseekingmissile::InsideStingerReticleLocked( ent, weapon ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,342 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\challenges_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\scoreevents_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
|
||||
#using scripts\mp\_challenges;
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\gametypes\_spawning;
|
||||
#using scripts\mp\killstreaks\_airsupport;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_satellite;
|
||||
#using scripts\mp\killstreaks\_planemortar;
|
||||
#using scripts\mp\killstreaks\_killstreak_bundles;
|
||||
#using scripts\mp\gametypes\_globallogic_audio;
|
||||
#using scripts\shared\weapons\_hacker_tool;
|
||||
#using scripts\mp\killstreaks\_killstreak_hacking;
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#namespace drone_strike;
|
||||
|
||||
|
||||
#precache( "locationselector", "map_directional_selector" );
|
||||
#precache( "string", "KILLSTREAK_DRONE_STRIKE_NOT_AVAILABLE" );
|
||||
#precache( "string", "KILLSTREAK_DRONE_STRIKE_EARNED" );
|
||||
#precache( "string", "KILLSTREAK_DRONE_STRIKE_INBOUND" );
|
||||
#precache( "string", "KILLSTREAK_DRONE_STRIKE_INBOUND_NEAR_PLAYER" );
|
||||
#precache( "string", "KILLSTREAK_DRONE_STRIKE_HACKED" );
|
||||
#precache( "string", "KILLSTREAK_DESTROYED_ROLLING_THUNDER_DRONE" );
|
||||
#precache( "string", "KILLSTREAK_DESTROYED_ROLLING_THUNDER_ALL_DRONES" );
|
||||
|
||||
#precache( "eventstring", "mpl_killstreak_DRONE_STRIKE" );
|
||||
#precache( "fx", "killstreaks/fx_rolling_thunder_thruster_trails" );
|
||||
|
||||
function init()
|
||||
{
|
||||
killstreaks::register( "drone_strike", "drone_strike", "killstreak_drone_strike", "drone_strike_used", &ActivateDroneStrike, true );
|
||||
killstreaks::register_strings( "drone_strike", &"KILLSTREAK_DRONE_STRIKE_EARNED", &"KILLSTREAK_DRONE_STRIKE_NOT_AVAILABLE", &"KILLSTREAK_DRONE_STRIKE_INBOUND", &"KILLSTREAK_DRONE_STRIKE_INBOUND_NEAR_PLAYER", &"KILLSTREAK_DRONE_STRIKE_HACKED" );
|
||||
killstreaks::register_dialog( "drone_strike", "mpl_killstreak_drone_strike", "droneStrikeDialogBundle", undefined, "friendlyDroneStrike", "enemyDroneStrike", "enemyDroneStrikeMultiple", "friendlyDroneStrikeHacked", "enemyDroneStrikeHacked", "requestDroneStrike", "threatDroneStrike" );
|
||||
killstreaks::set_team_kill_penalty_scale( "drone_strike", level.teamKillReducedPenalty );
|
||||
}
|
||||
|
||||
function ActivateDroneStrike()
|
||||
{
|
||||
if ( self killstreakrules::isKillstreakAllowed( "drone_strike", self.team ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result = self SelectDroneStrikePath();
|
||||
|
||||
if ( !isdefined( result ) || !result )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function SelectDroneStrikePath()
|
||||
{
|
||||
self BeginLocationNapalmSelection( "map_directional_selector" );
|
||||
self.selectingLocation = true;
|
||||
self thread airsupport::EndSelectionThink();
|
||||
|
||||
locations = [];
|
||||
if( !isdefined( self.pers["drone_strike_radar_used"] ) || !self.pers["drone_strike_radar_used"] )
|
||||
{
|
||||
self thread planemortar::SingleRadarSweep();
|
||||
}
|
||||
|
||||
location = self WaitForLocationSelection();
|
||||
|
||||
// if the player gets disconnected, self will be undefined
|
||||
if( !isdefined( self ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !isdefined( location.origin ) )
|
||||
{
|
||||
self.pers["drone_strike_radar_used"] = true;
|
||||
self notify( "cancel_selection" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( self killstreakrules::isKillstreakAllowed( "drone_strike", self.team ) == false)
|
||||
{
|
||||
self.pers["drone_strike_radar_used"] = true;
|
||||
self notify("cancel_selection");
|
||||
return false;
|
||||
}
|
||||
|
||||
self.pers["drone_strike_radar_used"] = false;
|
||||
return self airsupport::finishHardpointLocationUsage( location, &DroneStrikeLocationSelected );
|
||||
}
|
||||
|
||||
function WaitForLocationSelection()
|
||||
{
|
||||
self endon( "emp_jammed" );
|
||||
self endon( "emp_grenaded" );
|
||||
|
||||
self waittill( "confirm_location", location, yaw );
|
||||
|
||||
locationInfo = SpawnStruct();
|
||||
locationInfo.origin = location;
|
||||
locationInfo.yaw = yaw;
|
||||
|
||||
return locationInfo;
|
||||
}
|
||||
|
||||
function DroneStrikeLocationSelected( location )
|
||||
{
|
||||
team = self.team;
|
||||
killstreak_id = self killstreakrules::killstreakStart( "drone_strike", team, false, true );
|
||||
if( killstreak_id == (-1) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
self killstreaks::play_killstreak_start_dialog( "drone_strike", team, killstreak_id );
|
||||
self AddWeaponStat( GetWeapon( "drone_strike" ), "used", 1 );
|
||||
|
||||
spawn_influencer = level spawning::create_enemy_influencer( "artillery", location.origin, team );
|
||||
|
||||
self thread WatchForKillstreakEnd( team, spawn_influencer, killstreak_id );
|
||||
self thread StartDroneStrike( location.origin, location.yaw, team, killstreak_id );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function WatchForKillstreakEnd( team, influencer, killstreak_id )
|
||||
{
|
||||
self util::waittill_any( "disconnect", "joined_team", "joined_spectators", "drone_strike_complete", "emp_jammed" );
|
||||
killstreakrules::killstreakStop( "drone_strike", team, killstreak_id );
|
||||
}
|
||||
|
||||
function StartDroneStrike( position, yaw, team, killstreak_id )
|
||||
{
|
||||
self endon( "emp_jammed" );
|
||||
self endon( "joined_team" );
|
||||
self endon( "joined_spectators" );
|
||||
self endon( "disconnect" );
|
||||
|
||||
angles = ( 0, yaw, 0 );
|
||||
direction = AnglesToForward( angles );
|
||||
height = airsupport::getMinimumFlyHeight() + ( 3000 );
|
||||
|
||||
selectedPosition = ( position[0], position[1], height );
|
||||
startPoint = selectedPosition + VectorScale( direction, ( -14000 ) );
|
||||
endPoint = selectedPosition + VectorScale( direction, ( -6000 ) );
|
||||
|
||||
// trace to get the target point
|
||||
traceStartPos = ( position[0], position[1], height );
|
||||
traceEndPos = ( position[0], position[1], -height );
|
||||
trace = BulletTrace( traceStartPos, traceEndPos, 0, undefined );
|
||||
targetPoint = ( ( trace[ "fraction" ] < 1.0 ) ? trace[ "position" ] : ( position[0], position[1], 0.0 ) );
|
||||
|
||||
///#sphere( targetPoint, 20, ( 1, 0, 0 ), 1, true, 10, 400 );#/
|
||||
|
||||
initialOffset = -VectorScale( direction, ( ( ( 12 ) * 0.5 ) - 1 ) * ( 500 ) );
|
||||
|
||||
for( i = 0; i < ( 12 ); i++ )
|
||||
{
|
||||
right = AnglesToRight( angles );
|
||||
rightOffset = VectorScale( right, ( 300 ) );
|
||||
leftOffset = VectorScale( right, ( 900 ) );
|
||||
forwardOffset = endPoint + initialOffset + VectorScale( direction, i * ( 500 ) );
|
||||
|
||||
self thread SpawnDrone( startPoint + rightOffset, forwardOffset + rightOffset, targetPoint, angles, self.team, killstreak_id );
|
||||
self thread SpawnDrone( startPoint - rightOffset, forwardOffset - rightOffset, targetPoint, angles, self.team, killstreak_id );
|
||||
self thread SpawnDrone( startPoint + leftOffset, forwardOffset + leftOffset, targetPoint, angles, self.team, killstreak_id );
|
||||
wait( ( 1 ) );
|
||||
|
||||
self playsound ("mpl_thunder_flyover_wash");
|
||||
}
|
||||
|
||||
wait( 3 ); //Wait for the last drone to explode
|
||||
self notify( "drone_strike_complete" );
|
||||
}
|
||||
|
||||
function SpawnDrone( startPoint, endPoint, targetPoint, angles, team, killstreak_id )
|
||||
{
|
||||
drone = SpawnPlane( self, "script_model", startPoint );
|
||||
drone.team = team;
|
||||
drone.targetname = "drone_strike";
|
||||
drone SetOwner( self );
|
||||
drone.owner = self;
|
||||
drone.owner thread WatchOwnerEvents( drone );
|
||||
drone killstreaks::configure_team( "drone_strike", killstreak_id, self );
|
||||
drone killstreak_hacking::enable_hacking( "drone_strike" );
|
||||
Target_Set( drone );
|
||||
|
||||
drone endon( "delete" );
|
||||
drone endon( "death" );
|
||||
|
||||
drone.angles = angles;
|
||||
drone SetModel( "veh_t7_drone_rolling_thunder" );
|
||||
drone SetEnemyModel( "veh_t7_drone_rolling_thunder" );
|
||||
drone NotSolid();
|
||||
|
||||
PlayFxOnTag( "killstreaks/fx_rolling_thunder_thruster_trails", drone, "tag_fx");
|
||||
drone clientfield::set( "enemyvehicle", 1 );
|
||||
|
||||
drone SetupDamageHandling();
|
||||
drone thread WatchForEmp( self );
|
||||
|
||||
drone MoveTo( endpoint, ( 1.8 ), 0, 0 );
|
||||
wait ( ( 1.8 ) );
|
||||
|
||||
weapon = GetWeapon( "drone_strike" );
|
||||
velocity = drone GetVelocity();
|
||||
|
||||
halfGravity = 386;
|
||||
dXY = Abs( ( -6000 ) );
|
||||
dZ = endPoint[2] - targetPoint[2];
|
||||
dVxy = dXY * sqrt( halfGravity / dZ );
|
||||
|
||||
nvel = VectorNormalize( velocity );
|
||||
launchVel = nvel * dVxy;
|
||||
|
||||
bomb = self LaunchBomb( weapon, drone.origin, launchVel );
|
||||
|
||||
Target_Set( bomb );
|
||||
|
||||
bomb killstreaks::configure_team( "drone_strike", killstreak_id, self );
|
||||
bomb killstreak_hacking::enable_hacking( "drone_strike" );
|
||||
drone notify( "hackertool_update_ent", bomb );
|
||||
|
||||
bomb clientfield::set( "enemyvehicle", 1 );
|
||||
bomb.targetname = "drone_strike";
|
||||
bomb SetOwner( self );
|
||||
bomb.owner = self;
|
||||
bomb.team = team;
|
||||
bomb playsound( "mpl_thunder_incoming_start" );
|
||||
bomb SetupDamageHandling();
|
||||
bomb thread WatchForEmp( self );
|
||||
|
||||
bomb.owner thread WatchOwnerEvents( bomb );
|
||||
{wait(.05);};
|
||||
|
||||
drone Hide();
|
||||
|
||||
{wait(.05);};
|
||||
|
||||
drone Delete();
|
||||
}
|
||||
|
||||
function SetupDamageHandling()
|
||||
{
|
||||
drone = self;
|
||||
drone SetCanDamage( true );
|
||||
drone.maxhealth = killstreak_bundles::get_max_health( "drone_strike" );
|
||||
drone.lowhealth = killstreak_bundles::get_low_health( "drone_strike" );
|
||||
drone.health = drone.maxhealth;
|
||||
drone thread killstreaks::MonitorDamage( "drone_strike", drone.maxhealth, &DestroyDronePlane, drone.lowhealth, undefined, 0, &EmpDamageDrone, true );
|
||||
}
|
||||
|
||||
function DestroyDronePlane( attacker, weapon )
|
||||
{
|
||||
self endon( "death" );
|
||||
|
||||
attacker = self [[ level.figure_out_attacker ]]( attacker );
|
||||
if( isdefined( attacker ) && ( !isdefined( self.owner ) || self.owner util::IsEnemyPlayer( attacker ) ) )
|
||||
{
|
||||
challenges::destroyedAircraft( attacker, weapon, false );
|
||||
attacker challenges::addFlySwatterStat( weapon, self );
|
||||
scoreevents::processScoreEvent( "destroyed_rolling_thunder_drone", attacker, self.owner, weapon );
|
||||
LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_ROLLING_THUNDER_DRONE", attacker.entnum );
|
||||
}
|
||||
|
||||
params = level.killstreakBundle["drone_strike"];
|
||||
if( isdefined( params.ksExplosionFX ) )
|
||||
PlayFXOnTag( params.ksExplosionFX, self, "tag_origin" );
|
||||
|
||||
self setModel( "tag_origin" );
|
||||
|
||||
wait( 0.5 );
|
||||
|
||||
self delete();
|
||||
}
|
||||
|
||||
function WatchOwnerEvents( bomb )
|
||||
{
|
||||
player = self;
|
||||
|
||||
bomb endon( "death" );
|
||||
|
||||
player util::waittill_any( "disconnect", "joined_team", "joined_spectators" );
|
||||
|
||||
if( isdefined( isalive( bomb ) ) )
|
||||
bomb delete();
|
||||
}
|
||||
|
||||
function WatchForEmp( owner )
|
||||
{
|
||||
self endon( "delete" );
|
||||
self endon( "death" );
|
||||
|
||||
self waittill( "emp_deployed", attacker );
|
||||
|
||||
thread DroneStrikeAwardEMPScoreEvent( attacker, self );
|
||||
self BlowUpDroneStrike();
|
||||
}
|
||||
|
||||
function EmpDamageDrone( attacker )
|
||||
{
|
||||
thread DroneStrikeAwardEMPScoreEvent( attacker, self );
|
||||
self BlowUpDroneStrike();
|
||||
}
|
||||
|
||||
function DroneStrikeAwardEMPScoreEvent( attacker, victim )
|
||||
{
|
||||
owner = self.owner;
|
||||
|
||||
attacker endon( "disconnect" );
|
||||
attacker notify( "DroneStrikeAwardScoreEvent_singleton" );
|
||||
attacker endon( "DroneStrikeAwardScoreEvent_singleton" );
|
||||
waittillframeend;
|
||||
|
||||
attacker = self [[ level.figure_out_attacker ]]( attacker );
|
||||
scoreevents::processScoreEvent( "destroyed_rolling_thunder_all_drones", attacker, victim, GetWeapon( "emp" ) );
|
||||
challenges::destroyedAircraft( attacker, GetWeapon( "emp" ), false );
|
||||
attacker challenges::addFlySwatterStat( GetWeapon( "emp" ), self );
|
||||
LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_ROLLING_THUNDER_ALL_DRONES", attacker.entnum );
|
||||
|
||||
owner globallogic_audio::play_taacom_dialog( "destroyed", "drone_strike" );
|
||||
}
|
||||
|
||||
function BlowUpDroneStrike()
|
||||
{
|
||||
params = level.killstreakBundle["drone_strike"];
|
||||
if( isdefined( self ) && isdefined( params.ksExplosionFX ) )
|
||||
PlayFX( params.ksExplosionFX, self.origin );
|
||||
self delete();
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
|
||||
|
||||
#using_animtree ( "mp_emp_power_core" );
|
||||
|
||||
#precache( "client_fx", "killstreaks/fx_emp_core" );
|
||||
|
||||
#namespace emp;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function autoexec __init__sytem__() { system::register("emp",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
clientfield::register( "scriptmover", "emp_turret_init", 1, 1, "int", &emp_turret_init, !true, !true );
|
||||
clientfield::register( "vehicle", "emp_turret_deploy", 1, 1, "int", &emp_turret_deploy_start, !true, !true );
|
||||
|
||||
thread monitor_emp_killstreaks();
|
||||
}
|
||||
|
||||
function monitor_emp_killstreaks()
|
||||
{
|
||||
level endon( "disconnect" );
|
||||
|
||||
if ( !isdefined( level.emp_killstreaks ) )
|
||||
level.emp_killstreaks = [];
|
||||
|
||||
for(;;)
|
||||
{
|
||||
has_at_least_one_active_enemy_turret = false;
|
||||
ArrayRemoveValue( level.emp_killstreaks, undefined );
|
||||
local_players = GetLocalPlayers();
|
||||
|
||||
foreach( local_player in local_players )
|
||||
{
|
||||
if ( local_player IsLocalPlayer() == false )
|
||||
continue; // Note: a player joining a game is not a local player until after spawning in (is this a bug?)
|
||||
|
||||
closest_enemy_emp = emp::get_closest_enemy_emp_killstreak( local_player );
|
||||
|
||||
if ( isdefined( closest_enemy_emp ) )
|
||||
{
|
||||
has_at_least_one_active_enemy_turret = true;
|
||||
|
||||
localClientNum = local_player GetLocalClientNumber();
|
||||
update_distance_to_closest_emp( localClientNum, Distance( local_player.origin, closest_enemy_emp.origin ) );
|
||||
}
|
||||
}
|
||||
|
||||
wait ( has_at_least_one_active_enemy_turret ? 0.1 : 0.7 );
|
||||
}
|
||||
}
|
||||
|
||||
function get_closest_enemy_emp_killstreak( local_player )
|
||||
{
|
||||
closest_emp = undefined;
|
||||
closest_emp_distance_squared = 99999999;
|
||||
|
||||
foreach( emp in level.emp_killstreaks )
|
||||
{
|
||||
if ( emp.owner == local_player || emp.team == local_player.team )
|
||||
continue;
|
||||
|
||||
distance_squared = DistanceSquared( local_player.origin, emp.origin );
|
||||
if ( distance_squared < closest_emp_distance_squared )
|
||||
{
|
||||
closest_emp = emp;
|
||||
closest_emp_distance_squared = distance_squared;
|
||||
}
|
||||
}
|
||||
|
||||
return closest_emp;
|
||||
}
|
||||
|
||||
function update_distance_to_closest_emp( localClientNum, new_value )
|
||||
{
|
||||
if ( !isdefined( localClientNum ) )
|
||||
return;
|
||||
|
||||
distance_to_closest_enemy_emp_ui_model = GetUIModel( GetUIModelForController( localClientNum ), "distanceToClosestEnemyEmpKillstreak" );
|
||||
|
||||
if ( isdefined( distance_to_closest_enemy_emp_ui_model ) )
|
||||
SetUIModelValue( distance_to_closest_enemy_emp_ui_model, new_value );
|
||||
|
||||
// /# IPrintLnBold( "Distance to Closest Enemy EMP: " + new_value ); #/
|
||||
}
|
||||
|
||||
function emp_turret_init( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
self endon("entityshutdown");
|
||||
|
||||
if ( !newVal )
|
||||
return;
|
||||
|
||||
self UseAnimTree( #animtree );
|
||||
self SetAnimRestart( %o_turret_emp_core_deploy, 1.0, 0.0, 0.0 );
|
||||
self SetAnimTime( %o_turret_emp_core_deploy, 0.0 );
|
||||
}
|
||||
|
||||
function cleanup_fx_on_shutdown( localClientNum, handle )
|
||||
{
|
||||
self endon("kill_fx_cleanup");
|
||||
self waittill( "entityshutdown" );
|
||||
StopFx( localClientNum, handle );
|
||||
}
|
||||
|
||||
function emp_turret_deploy_start( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
self endon("entityshutdown");
|
||||
|
||||
self util::waittill_dobj( localClientNum );
|
||||
|
||||
if ( !isdefined(self) )
|
||||
return;
|
||||
|
||||
if ( newVal )
|
||||
{
|
||||
self thread emp_turret_deploy(localClientNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
self notify("kill_fx_cleanup");
|
||||
if ( isdefined( self.fxHandle ) )
|
||||
{
|
||||
StopFx( localClientNum, self.fxHandle );
|
||||
self.fxHandle = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emp_turret_deploy( localClientNum )
|
||||
{
|
||||
self endon("entityshutdown");
|
||||
|
||||
self UseAnimTree( #animtree );
|
||||
self SetAnimRestart( %o_turret_emp_core_deploy, 1.0, 0.0, 1.0 );
|
||||
length = GetAnimLength( %o_turret_emp_core_deploy );
|
||||
// self waittill("end"); // length of deploy anim
|
||||
wait length * 0.75;
|
||||
|
||||
self UseAnimTree( #animtree );
|
||||
self SetAnim( %o_turret_emp_core_spin, 1.0 );
|
||||
self.fxHandle = PlayFxOnTag( localClientNum, "killstreaks/fx_emp_core", self, "tag_fx" );
|
||||
|
||||
self thread cleanup_fx_on_shutdown( localClientNum, self.fxHandle );
|
||||
|
||||
wait length * 0.25;
|
||||
self SetAnim( %o_turret_emp_core_deploy, 0.0 ); // stop deploy anim
|
||||
}
|
||||
@@ -0,0 +1,470 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\gametypes\_hostmigration;
|
||||
#using scripts\mp\killstreaks\_airsupport;
|
||||
#using scripts\mp\killstreaks\_emp;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_killstreak_bundles;
|
||||
#using scripts\mp\killstreaks\_killstreak_hacking;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_placeables;
|
||||
#using scripts\mp\teams\_teams;
|
||||
#using scripts\mp\teams\_teams;
|
||||
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\challenges_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\hostmigration_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\popups_shared;
|
||||
#using scripts\shared\turret_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
#using scripts\shared\weapons\_weaponobjects;
|
||||
#using scripts\shared\scoreevents_shared;
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#using_animtree ( "mp_emp_power_core" );
|
||||
|
||||
#precache( "string", "KILLSTREAK_EARNED_EMP" );
|
||||
#precache( "string", "KILLSTREAK_EMP_NOT_AVAILABLE" );
|
||||
#precache( "string", "KILLSTREAK_EMP_INBOUND" );
|
||||
#precache( "string", "KILLSTREAK_EMP_HACKED" );
|
||||
#precache( "string", "KILLSTREAK_DESTROYED_EMP" );
|
||||
#precache( "triggerstring", "KILLSTREAK_EMP_PLACE_TURRET_HINT" );
|
||||
#precache( "triggerstring", "KILLSTREAK_EMP_INVALID_TURRET_LOCATION" );
|
||||
#precache( "triggerstring", "KILLSTREAK_EMP_TURRET_PICKUP" );
|
||||
#precache( "string", "mpl_killstreak_emp_activate" );
|
||||
|
||||
//#precache( "fx", "killstreaks/fx_emp_core" );
|
||||
#precache( "fx", "killstreaks/fx_emp_exp_death" );
|
||||
|
||||
|
||||
|
||||
|
||||
#namespace emp;
|
||||
|
||||
function init()
|
||||
{
|
||||
bundle = struct::get_script_bundle( "killstreak", "killstreak_emp" );
|
||||
level.empKillstreakBundle = bundle;
|
||||
|
||||
level.ActivePlayerEMPs = [];
|
||||
level.ActiveEMPs = [];
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
level.ActiveEMPs[ team ] = false;
|
||||
}
|
||||
|
||||
level.enemyEMPActiveFunc = &EnemyEMPActive;
|
||||
|
||||
level thread EMPTracker();
|
||||
|
||||
killstreaks::register( "emp", "emp", "killstreak_emp", "emp_used", &ActivateEMP );
|
||||
killstreaks::register_strings( "emp", &"KILLSTREAK_EARNED_EMP", &"KILLSTREAK_EMP_NOT_AVAILABLE", &"KILLSTREAK_EMP_INBOUND", undefined, &"KILLSTREAK_EMP_HACKED", false );
|
||||
killstreaks::register_dialog( "emp", "mpl_killstreak_emp_activate", "empDialogBundle", undefined, "friendlyEmp", "enemyEmp", "enemyEmpMultiple", "friendlyEmpHacked", "enemyEmpHacked", "requestEmp", "threatEmp" );
|
||||
|
||||
clientfield::register( "scriptmover", "emp_turret_init", 1, 1, "int" ); // re-export model in close position to save this clientfield
|
||||
clientfield::register( "vehicle", "emp_turret_deploy", 1, 1, "int" );
|
||||
|
||||
spinAnim = %o_turret_emp_core_spin;
|
||||
deployAnim = %o_turret_emp_core_deploy;
|
||||
|
||||
callback::on_spawned( &OnPlayerSpawned );
|
||||
callback::on_connect( &OnPlayerConnect );
|
||||
vehicle::add_main_callback( "emp_turret", &InitTurretVehicle );
|
||||
}
|
||||
|
||||
function InitTurretVehicle()
|
||||
{
|
||||
turretVehicle = self;
|
||||
|
||||
turretVehicle killstreaks::setup_health( "emp" );
|
||||
turretVehicle.damageTaken = 0;
|
||||
turretVehicle.health = turretVehicle.maxhealth;
|
||||
|
||||
turretVehicle clientfield::set( "enemyvehicle", 1 );
|
||||
turretVehicle.soundmod = "drone_land"; // TODO: update this to the correct value
|
||||
|
||||
turretVehicle.overrideVehicleDamage = &OnTurretDamage;
|
||||
turretVehicle.overrideVehicleDeath = &OnTurretDeath;
|
||||
|
||||
Target_Set( turretVehicle, ( 0, 0, 36 ) );
|
||||
}
|
||||
|
||||
function OnPlayerSpawned()
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
|
||||
self UpdateEMP();
|
||||
}
|
||||
|
||||
function OnPlayerConnect()
|
||||
{
|
||||
self.entNum = self getEntityNumber();
|
||||
level.ActivePlayerEMPs[ self.entNum ] = false;
|
||||
}
|
||||
|
||||
function ActivateEMP()
|
||||
{
|
||||
player = self;
|
||||
|
||||
killstreakId = player killstreakrules::killstreakStart( "emp", player.team, false, false );
|
||||
if( killstreakId == (-1) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bundle = level.empKillstreakBundle;
|
||||
|
||||
empBase = player placeables::SpawnPlaceable( "emp", killstreakId, &OnPlaceEMP, &OnCancelPlacement, undefined, &OnShutdown, undefined, undefined,
|
||||
"wpn_t7_turret_emp_core", "wpn_t7_turret_emp_core_yellow", "wpn_t7_turret_emp_core_red", true, "", undefined, undefined, 0,
|
||||
bundle.ksPlaceableHint, bundle.ksPlaceableInvalidLocationHint );
|
||||
|
||||
empBase thread util::ghost_wait_show_to_player( player );
|
||||
empBase.otherModel thread util::ghost_wait_show_to_others( player );
|
||||
empBase clientfield::set( "emp_turret_init", 1 );
|
||||
empBase.otherModel clientfield::set( "emp_turret_init", 1 );
|
||||
|
||||
event = empBase util::waittill_any_return( "placed", "cancelled", "death", "disconnect" );
|
||||
if( event != "placed" )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function OnPlaceEMP( emp )
|
||||
{
|
||||
player = self;
|
||||
assert( IsPlayer( player ) );
|
||||
assert( !isdefined( emp.vehicle ) );
|
||||
|
||||
emp.vehicle = SpawnVehicle( "emp_turret", emp.origin, emp.angles );
|
||||
emp.vehicle thread util::ghost_wait_show( 0.05 );
|
||||
|
||||
emp.vehicle.killstreakType = emp.killstreakType; // need to do this for enable_hacking
|
||||
|
||||
emp.vehicle.owner = player;
|
||||
emp.vehicle SetOwner( player );
|
||||
emp.vehicle.ownerEntNum = player.entNum;
|
||||
emp.vehicle.parentStruct = emp;
|
||||
|
||||
player.EMPTime = GetTime();
|
||||
player killstreaks::play_killstreak_start_dialog( "emp", player.pers["team"], emp.killstreakId );
|
||||
player AddWeaponStat( GetWeapon( "emp" ), "used", 1 );
|
||||
level thread popups::DisplayKillstreakTeamMessageToAll( "emp", player );
|
||||
emp.vehicle killstreaks::configure_team( "emp", emp.killstreakId, player );
|
||||
emp.vehicle killstreak_hacking::enable_hacking( "emp", &HackedCallbackPre, &HackedCallbackPost );
|
||||
emp thread killstreaks::WaitForTimeout( "emp", ( 60 * 1000 ), &on_timeout, "death" );
|
||||
if ( IsSentient( emp.vehicle ) == false )
|
||||
emp.vehicle MakeSentient(); // so other sentients will consider this as a potential enemy
|
||||
|
||||
emp.vehicle vehicle::disconnect_paths( 0, false );
|
||||
|
||||
// perform deploy on separate thread because of the wait delays
|
||||
// always complete OnPlace() in same frame for killstreak accounting; otherwise exploits can happen
|
||||
player thread DeployEmpTurret( emp );
|
||||
}
|
||||
|
||||
function DeployEmpTurret( emp )
|
||||
{
|
||||
player = self;
|
||||
|
||||
player endon( "disconnect" );
|
||||
player endon( "joined_team" );
|
||||
player endon( "joined_spectators" );
|
||||
|
||||
emp endon( "death" );
|
||||
|
||||
// deploy emp
|
||||
emp.vehicle UseAnimTree( #animtree );
|
||||
emp.vehicle SetAnim( %o_turret_emp_core_deploy, 1.0 );
|
||||
length = GetAnimLength( %o_turret_emp_core_deploy );
|
||||
emp.vehicle clientfield::set( "emp_turret_deploy", 1 );
|
||||
wait length * 0.75;
|
||||
|
||||
// fire emp pulse
|
||||
emp.vehicle thread PlayEMPFx();
|
||||
emp.vehicle playsound( "mpl_emp_turret_activate" );
|
||||
emp.vehicle SetAnim( %o_turret_emp_core_spin, 1.0 );
|
||||
|
||||
// Jam Enemies and destroy other scorestreaks!
|
||||
player thread EMP_JamEnemies( emp, false );
|
||||
|
||||
wait length * 0.25;
|
||||
emp.vehicle ClearAnim( %o_turret_emp_core_deploy, 0 ); // stop deploy anim
|
||||
}
|
||||
|
||||
function HackedCallbackPre( hacker )
|
||||
{
|
||||
emp_vehicle = self;
|
||||
emp_vehicle clientfield::set( "enemyvehicle", 2 );
|
||||
emp_vehicle.parentStruct killstreaks::configure_team( "emp", emp_vehicle.parentStruct.killstreakId, hacker, undefined, undefined, undefined, true );
|
||||
}
|
||||
|
||||
function HackedCallbackPost( hacker )
|
||||
{
|
||||
emp_vehicle = self;
|
||||
hacker thread EMP_JamEnemies( emp_vehicle.parentStruct, true );
|
||||
}
|
||||
|
||||
function DoneEMPFx( fxTagOrigin )
|
||||
{
|
||||
PlayFx( "killstreaks/fx_emp_exp_death", fxTagOrigin );
|
||||
playsoundatposition( "mpl_emp_turret_deactivate", fxTagOrigin );
|
||||
}
|
||||
|
||||
function PlayEMPFx()
|
||||
{
|
||||
emp_vehicle = self;
|
||||
emp_vehicle playloopsound( "mpl_emp_turret_loop_close" );
|
||||
|
||||
{wait(.05);}; // workaround for a bug where the fx would not play on subsequent deployment of power cores
|
||||
}
|
||||
|
||||
function on_timeout()
|
||||
{
|
||||
emp = self;
|
||||
|
||||
if ( isdefined( emp.vehicle ) )
|
||||
{
|
||||
fxTagOrigin = emp.vehicle GetTagorigin( "tag_fx" );
|
||||
DoneEMPFx( fxTagOrigin );
|
||||
}
|
||||
ShutdownEMP( emp );
|
||||
}
|
||||
|
||||
function OnCancelPlacement( emp )
|
||||
{
|
||||
StopEMP( emp.team, emp.ownerEntNum, emp.originalTeam, emp.killstreakId );
|
||||
}
|
||||
|
||||
function OnTurretDamage( eInflictor, attacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
|
||||
{
|
||||
empDamage = 0; // emp power core is not affected by emp damage
|
||||
|
||||
iDamage = self killstreaks::OnDamagePerWeapon( "emp", attacker, iDamage, iDFlags, sMeansOfDeath, weapon, self.maxhealth, undefined, self.maxhealth*0.4, undefined, empDamage, undefined, true, 1.0 );
|
||||
self.damageTaken += iDamage;
|
||||
|
||||
// turret death
|
||||
if ( self.damageTaken > self.maxHealth && !isdefined( self.will_die ) )
|
||||
{
|
||||
self.will_die = true;
|
||||
self thread OnDeathAfterFrameEnd( attacker, weapon );
|
||||
}
|
||||
|
||||
return iDamage;
|
||||
}
|
||||
|
||||
function OnTurretDeath( inflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime )
|
||||
{
|
||||
// currently, OnTurretDeath is not getting called, so we call OnDeath directly from OnTurretDamage
|
||||
self OnDeath( attacker, weapon );
|
||||
}
|
||||
|
||||
function OnDeathAfterFrameEnd( attacker, weapon )
|
||||
{
|
||||
waittillframeend;
|
||||
|
||||
if ( isdefined( self ) )
|
||||
{
|
||||
self OnDeath( attacker, weapon );
|
||||
}
|
||||
}
|
||||
|
||||
function OnDeath( attacker, weapon )
|
||||
{
|
||||
emp_vehicle = self;
|
||||
|
||||
fxTagOrigin = self GetTagorigin( "tag_fx" );
|
||||
DoneEMPFx( fxTagOrigin );
|
||||
if ( isdefined( attacker ) && IsPlayer( attacker ) && ( !isdefined( emp_vehicle.owner ) || emp_vehicle.owner util::IsEnemyPlayer( attacker ) ) )
|
||||
{
|
||||
attacker challenges::destroyScoreStreak( weapon, false, true, false );
|
||||
attacker challenges::destroyNonAirScoreStreak_PostStatsLock( weapon );
|
||||
attacker AddPlayerStat( "destroy_turret", 1 );
|
||||
attacker AddWeaponStat( weapon, "destroy_turret", 1 );
|
||||
scoreevents::processScoreEvent( "destroyed_emp", attacker, emp_vehicle.owner, weapon );
|
||||
LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_EMP", attacker.entnum );
|
||||
}
|
||||
|
||||
if ( isdefined( attacker ) && isdefined( emp_vehicle.owner ) && ( attacker != emp_vehicle.owner ) )
|
||||
emp_vehicle killstreaks::play_destroyed_dialog_on_owner( "emp", emp_vehicle.parentStruct.killstreakId );
|
||||
|
||||
ShutdownEMP( emp_vehicle.parentStruct );
|
||||
}
|
||||
|
||||
function OnShutdown( emp )
|
||||
{
|
||||
ShutdownEMP( emp );
|
||||
}
|
||||
|
||||
function ShutdownEMP( emp )
|
||||
{
|
||||
if (!isdefined( emp ) )
|
||||
return;
|
||||
|
||||
if ( isdefined( emp.already_shutdown ) )
|
||||
return;
|
||||
|
||||
emp.already_shutdown = true;
|
||||
|
||||
if ( isdefined( emp.vehicle ) )
|
||||
emp.vehicle clientfield::set( "emp_turret_deploy", 0 );
|
||||
|
||||
StopEMP( emp.team, emp.OwnerEntNum, emp.originalTeam, emp.killstreakId );
|
||||
|
||||
if ( isdefined( emp.otherModel ) )
|
||||
{
|
||||
emp.otherModel delete();
|
||||
}
|
||||
|
||||
if ( isdefined( emp.vehicle ) )
|
||||
{
|
||||
emp.vehicle delete();
|
||||
}
|
||||
|
||||
emp delete();
|
||||
}
|
||||
|
||||
function StopEMP( currentTeam, currentOwnerEntNum, originalTeam, killstreakID )
|
||||
{
|
||||
StopEMPEffect( currentTeam, currentOwnerEntNum );
|
||||
StopEMPRule( originalTeam, killstreakID );
|
||||
}
|
||||
|
||||
function StopEMPEffect( team, ownerEntNum )
|
||||
{
|
||||
level.ActiveEMPs[ team ] = false;
|
||||
level.ActivePlayerEMPs[ ownerEntNum ] = false;
|
||||
level notify ( "emp_updated" );
|
||||
}
|
||||
|
||||
function StopEMPRule( killstreakOriginalTeam, killstreakId )
|
||||
{
|
||||
killstreakrules::killstreakStop( "emp", killstreakOriginalTeam, killstreakId );
|
||||
}
|
||||
|
||||
function HasActiveEMP()
|
||||
{
|
||||
return ( level.ActivePlayerEMPs[ self.entNum ] );
|
||||
}
|
||||
|
||||
function TeamHasActiveEMP( team )
|
||||
{
|
||||
return ( level.ActiveEMPs[ team ] > 0 );
|
||||
}
|
||||
|
||||
function EnemyEMPActive()
|
||||
{
|
||||
if( level.teamBased )
|
||||
{
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
if( ( team != self.team ) && TeamHasActiveEMP( team ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
enemies = self teams::GetEnemyPlayers();
|
||||
foreach( player in enemies )
|
||||
{
|
||||
if( player HasActiveEMP() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function EnemyEMPOwner()
|
||||
{
|
||||
enemies = self teams::GetEnemyPlayers();
|
||||
foreach( player in enemies )
|
||||
{
|
||||
if( player HasActiveEMP() )
|
||||
{
|
||||
return player;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function EMP_JamEnemies( empEnt, hacked )
|
||||
{
|
||||
level endon ( "game_ended" );
|
||||
self endon( "killstreak_hacked" );
|
||||
|
||||
if( level.teamBased )
|
||||
{
|
||||
if ( hacked )
|
||||
{
|
||||
level.ActiveEMPs[ empEnt.OriginalTeam ] = false;
|
||||
}
|
||||
level.ActiveEMPs[ self.team ] = true;
|
||||
}
|
||||
|
||||
if( hacked )
|
||||
{
|
||||
level.ActivePlayerEMPs[ empEnt.originalOwnerEntNum ] = false;
|
||||
}
|
||||
level.ActivePlayerEMPs[ self.entNum ] = true;
|
||||
level notify( "emp_updated" );
|
||||
level notify( "emp_deployed" );
|
||||
|
||||
VisionSetNaked( "flash_grenade", 1.5 );
|
||||
wait ( 0.1 );
|
||||
VisionSetNaked( "flash_grenade", 0 );
|
||||
VisionSetNaked( GetDvarString( "mapname" ), 5.0 );
|
||||
|
||||
empKillstreakWeapon = GetWeapon( "emp" );
|
||||
empKillstreakWeapon.isEmpKillstreak = true;
|
||||
level killstreaks::DestroyOtherTeamsActiveVehicles( self, empKillstreakWeapon );
|
||||
level killstreaks::DestroyOtherTeamsEquipment( self, empKillstreakWeapon );
|
||||
level weaponobjects::destroy_other_teams_supplemental_watcher_objects( self, empKillstreakWeapon );
|
||||
}
|
||||
|
||||
function EMPTracker()
|
||||
{
|
||||
level endon ( "game_ended" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
level waittill( "emp_updated" );
|
||||
|
||||
foreach ( player in level.players )
|
||||
{
|
||||
player UpdateEMP();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function UpdateEMP()
|
||||
{
|
||||
player = self;
|
||||
|
||||
enemy_emp_active = player EnemyEMPActive();
|
||||
player setEMPJammed( enemy_emp_active );
|
||||
|
||||
emped = player isEMPJammed(); // ask because a perk may stop it
|
||||
player clientfield::set_to_player( "empd_monitor_distance", emped );
|
||||
|
||||
if( emped )
|
||||
{
|
||||
player notify( "emp_jammed" );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\math_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#using scripts\mp\_helicopter_sounds;
|
||||
#using scripts\mp\_util;
|
||||
|
||||
|
||||
|
||||
#using scripts\shared\duplicaterender_mgr;
|
||||
|
||||
|
||||
#namespace flak_drone;
|
||||
|
||||
|
||||
|
||||
function autoexec __init__sytem__() { system::register("flak_drone",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
clientfield::register( "vehicle", "flak_drone_camo", 1, 3, "int", &active_camo_changed, !true, !true );
|
||||
}
|
||||
|
||||
function active_camo_changed( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
flags_changed = self duplicate_render::set_dr_flag( "active_camo_flicker", newVal == ( 2 ) );
|
||||
flags_changed = self duplicate_render::set_dr_flag( "active_camo_on", false ) || flags_changed;
|
||||
flags_changed = self duplicate_render::set_dr_flag( "active_camo_reveal", true ) || flags_changed;
|
||||
if ( flags_changed )
|
||||
{
|
||||
self duplicate_render::update_dr_filters(localClientNum);
|
||||
}
|
||||
|
||||
self notify( "endtest" );
|
||||
|
||||
self thread doReveal( localClientNum, newVal != ( 0 ) );
|
||||
}
|
||||
|
||||
function doReveal( localClientNum, direction )
|
||||
{
|
||||
self notify( "endtest" );
|
||||
self endon( "endtest" );
|
||||
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
if( direction )
|
||||
{
|
||||
startVal = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
startVal = 0;
|
||||
}
|
||||
|
||||
while( ( startVal >= 0 ) && ( startVal <= 1 ) )
|
||||
{
|
||||
self MapShaderConstant( localClientNum, 0, "scriptVector0", startVal, 0, 0, 0 );
|
||||
if( direction )
|
||||
{
|
||||
startVal -= .016 / 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
startVal += .016 / 0.5;
|
||||
}
|
||||
wait( .016 );
|
||||
}
|
||||
|
||||
flags_changed = self duplicate_render::set_dr_flag( "active_camo_reveal", false );
|
||||
flags_changed = self duplicate_render::set_dr_flag( "active_camo_on", direction ) || flags_changed;
|
||||
if ( flags_changed )
|
||||
{
|
||||
self duplicate_render::update_dr_filters(localClientNum);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,539 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\array_shared;
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\math_shared;
|
||||
#using scripts\shared\statemachine_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\turret_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_ai_shared;
|
||||
#using scripts\shared\vehicle_death_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\gametypes\_shellshock;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_airsupport;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_remote_weapons;
|
||||
#using scripts\mp\teams\_teams;
|
||||
#using scripts\shared\weapons\_heatseekingmissile;
|
||||
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
|
||||
|
||||
#precache( "fx", "explosions/fx_vexp_wasp_gibb_death" );
|
||||
|
||||
#namespace flak_drone;
|
||||
|
||||
|
||||
|
||||
|
||||
function init()
|
||||
{
|
||||
clientfield::register( "vehicle", "flak_drone_camo", 1, 3, "int" );
|
||||
|
||||
vehicle::add_main_callback( "veh_flak_drone_mp", &InitFlakDrone );
|
||||
}
|
||||
|
||||
function InitFlakDrone()
|
||||
{
|
||||
self.health = self.healthdefault;
|
||||
self vehicle::friendly_fire_shield();
|
||||
self EnableAimAssist();
|
||||
self SetNearGoalNotifyDist( ( 40 ) );
|
||||
self SetHoverParams( ( 50.0 ), ( 75.0 ), ( 100.0 ) );
|
||||
self SetVehicleAvoidance( true );
|
||||
self.fovcosine = 0; // +/-90 degrees = 180
|
||||
self.fovcosinebusy = 0; //+/- 55 degrees = 110 fov
|
||||
self.vehAirCraftCollisionEnabled = true;
|
||||
self.goalRadius = 999999;
|
||||
self.goalHeight = 999999;
|
||||
self SetGoal( self.origin, false, self.goalRadius, self.goalHeight );
|
||||
self thread vehicle_ai::nudge_collision();
|
||||
|
||||
self.overrideVehicleDamage = &FlakDroneDamageOverride;
|
||||
|
||||
self vehicle_ai::init_state_machine_for_role( "default" );
|
||||
self vehicle_ai::get_state_callbacks( "combat" ).enter_func = &state_combat_enter;
|
||||
self vehicle_ai::get_state_callbacks( "combat" ).update_func = &state_combat_update;
|
||||
self vehicle_ai::get_state_callbacks( "off" ).enter_func = &state_off_enter;
|
||||
self vehicle_ai::get_state_callbacks( "off" ).update_func = &state_off_update;
|
||||
self vehicle_ai::get_state_callbacks( "death" ).update_func = &state_death_update;
|
||||
|
||||
self vehicle_ai::StartInitialState( "off" );
|
||||
}
|
||||
|
||||
function state_off_enter( params )
|
||||
{
|
||||
}
|
||||
|
||||
function state_off_update( params )
|
||||
{
|
||||
self endon( "change_state" );
|
||||
self endon( "death" );
|
||||
|
||||
while( !isdefined( self.parent ) )
|
||||
{
|
||||
wait( 0.1 ); //Wait for parent to be setup
|
||||
}
|
||||
|
||||
self.parent endon( "death" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
self SetSpeed( ( 400 ) );
|
||||
|
||||
if( ( isdefined( self.inpain ) && self.inpain ) )
|
||||
{
|
||||
wait( ( 0.1 ) );
|
||||
}
|
||||
|
||||
self ClearLookAtEnt();
|
||||
|
||||
self.current_pathto_pos = undefined;
|
||||
|
||||
queryOrigin = self.parent.origin + ( 0, 0, ( -75 ) );
|
||||
queryResult = PositionQuery_Source_Navigation( queryOrigin,
|
||||
( 25 ),
|
||||
( 75 ),
|
||||
( 40 ),
|
||||
( 40 ),
|
||||
self );
|
||||
|
||||
if( isdefined( queryResult ) )
|
||||
{
|
||||
PositionQuery_Filter_DistanceToGoal( queryResult, self );
|
||||
vehicle_ai::PositionQuery_Filter_OutOfGoalAnchor( queryResult );
|
||||
|
||||
best_point = undefined;
|
||||
best_score = -999999;
|
||||
|
||||
foreach ( point in queryResult.data )
|
||||
{
|
||||
randomScore = randomFloatRange( 0, 100 );
|
||||
distToOriginScore = point.distToOrigin2D * 0.2;
|
||||
|
||||
point.score += randomScore + distToOriginScore;
|
||||
/# if ( !isdefined( point._scoreDebug ) ) { point._scoreDebug = []; } point._scoreDebug[ "distToOrigin" ] = distToOriginScore; #/ point.score += distToOriginScore;;
|
||||
|
||||
if ( point.score > best_score )
|
||||
{
|
||||
best_score = point.score;
|
||||
best_point = point;
|
||||
}
|
||||
}
|
||||
|
||||
self vehicle_ai::PositionQuery_DebugScores( queryResult );
|
||||
|
||||
if( isdefined( best_point ) )
|
||||
{
|
||||
self.current_pathto_pos = best_point.origin;
|
||||
}
|
||||
}
|
||||
|
||||
if( IsDefined( self.current_pathto_pos ) )
|
||||
{
|
||||
self UpdateFlakDroneSpeed();
|
||||
if( self SetVehGoalPos( self.current_pathto_pos, true, false ) )
|
||||
{
|
||||
self playsound ("veh_wasp_vox");
|
||||
}
|
||||
else
|
||||
{
|
||||
self SetSpeed( ( 400 ) * 3 );
|
||||
self.current_pathto_pos = self GetClosestPointOnNavVolume( self.origin, 999999 );
|
||||
self SetVehGoalPos( self.current_pathto_pos, true, false );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( isDefined( self.parent.heliGoalPos ) )
|
||||
{
|
||||
self.current_pathto_pos = self.parent.heliGoalPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.current_pathto_pos = queryOrigin;
|
||||
}
|
||||
self UpdateFlakDroneSpeed();
|
||||
self SetVehGoalPos( self.current_pathto_pos, true, false );
|
||||
}
|
||||
|
||||
wait RandomFloatRange( ( .1 ), ( .2 ) );
|
||||
}
|
||||
}
|
||||
|
||||
function UpdateFlakDroneSpeed() // self == flak drone
|
||||
{
|
||||
desiredSpeed = ( 400 );
|
||||
|
||||
if ( isdefined( self.parent ) )
|
||||
{
|
||||
parentSpeed = self.parent GetSpeed();
|
||||
desiredSpeed = parentSpeed * 0.9; // lag a little back
|
||||
if ( Distance2DSquared( self.parent.origin, self.origin ) > ( (36) * (36) ) ) // match parent speed if too far from parent
|
||||
{
|
||||
if ( isdefined( self.current_pathto_pos ) )
|
||||
{
|
||||
flakDroneDistanceToGoalSquared = Distance2DSquared( self.origin, self.current_pathto_pos );
|
||||
parentDistanceToGoalSquared = Distance2DSquared( self.parent.origin, self.current_pathto_pos );
|
||||
if ( flakDroneDistanceToGoalSquared > parentDistanceToGoalSquared )
|
||||
{
|
||||
desiredSpeed = parentSpeed * 1.3;
|
||||
}
|
||||
else
|
||||
{
|
||||
desiredSpeed = parentSpeed * 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self SetSpeed( max( desiredSpeed, 10 ) );
|
||||
}
|
||||
|
||||
function state_combat_enter( params )
|
||||
{
|
||||
}
|
||||
|
||||
function state_combat_update( params )
|
||||
{
|
||||
drone = self;
|
||||
drone endon( "change_state" );
|
||||
drone endon( "death" );
|
||||
|
||||
drone thread SpawnFlakRocket( drone.incoming_missile, drone.origin, drone.parent );
|
||||
drone Ghost();
|
||||
}
|
||||
|
||||
function SpawnFlakRocket( missile, spawnPos, parent )
|
||||
{
|
||||
drone = self;
|
||||
|
||||
missile endon("death");
|
||||
missile Missile_SetTarget( parent );
|
||||
|
||||
rocket = MagicBullet( GetWeapon( "flak_drone_rocket" ), spawnPos, missile.origin, parent, missile );
|
||||
rocket.team = parent.team;
|
||||
rocket setTeam( parent.team );
|
||||
rocket clientfield::set( "enemyvehicle", 1 );
|
||||
rocket Missile_SetTarget( missile );
|
||||
missile thread CleanupAfterMissileDeath( rocket, drone ); // sometimes missile gets destroyed by the rocket
|
||||
|
||||
curDist = Distance( missile.origin, rocket.origin ); // note: algorithm requires distance (not distance squared)
|
||||
|
||||
tooCloseToPredictedParent = false;
|
||||
|
||||
/#
|
||||
debug_draw = GetDvarInt( "scr_flak_drone_debug_trails", 0 );
|
||||
debug_duration = GetDvarInt( "scr_flak_drone_debug_trails_duration", 20 * 20 ); // duration in number of server frames
|
||||
#/
|
||||
|
||||
while( true )
|
||||
{
|
||||
{wait(.05);};
|
||||
|
||||
prevDist = curDist;
|
||||
|
||||
if ( isdefined( rocket ) )
|
||||
{
|
||||
curDist = Distance( missile.origin, rocket.origin ); // can't use DistanceSquared() here
|
||||
|
||||
distDelta = prevDist - curDist;
|
||||
|
||||
predictedDist = curDist - distDelta;
|
||||
}
|
||||
|
||||
/#
|
||||
if ( debug_draw && isdefined( missile ) )
|
||||
util::debug_sphere( missile.origin, 6, ( 0.9, 0, 0 ), 0.9, debug_duration ); // small red sphere for missile trail
|
||||
|
||||
if ( debug_draw && isdefined( rocket ) )
|
||||
util::debug_sphere( rocket.origin, 6, ( 0, 0, 0.9 ), 0.9, debug_duration ); // small blue spheres for flak drone trail (as rocket)
|
||||
#/
|
||||
|
||||
if ( isdefined( parent ) )
|
||||
{
|
||||
parentVelocity = parent GetVelocity();
|
||||
parentPredictedLocation = parent.origin + ( parentVelocity * 0.05 );
|
||||
missileVelocity = missile GetVelocity();
|
||||
missilePredictedLocation = missile.origin + ( missileVelocity * 0.05 );
|
||||
if ( DistanceSquared( parentPredictedLocation, missilePredictedLocation ) < ( (1000) * (1000) )
|
||||
|| DistanceSquared( parent.origin, missilePredictedLocation ) < ( (1000) * (1000) ) )
|
||||
{
|
||||
tooCloseToPredictedParent = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( ( predictedDist < 0 ) || ( curDist > prevDist ) || tooCloseToPredictedParent || !isdefined( rocket ) )
|
||||
{
|
||||
/#
|
||||
if ( debug_draw && isdefined( parent ) )
|
||||
{
|
||||
if ( tooCloseToPredictedParent && ! ( ( predictedDist < 0 ) || ( curDist > prevDist ) ) )
|
||||
{
|
||||
util::debug_sphere( parent.origin, 18, ( 0.9, 0, 0.9 ), 0.9, debug_duration ); // large purple sphere means too close to parent
|
||||
}
|
||||
else
|
||||
{
|
||||
util::debug_sphere( parent.origin, 18, ( 0, 0.9, 0 ), 0.9, debug_duration ); // large green sphere means intercepted
|
||||
}
|
||||
}
|
||||
#/
|
||||
|
||||
if ( isdefined( rocket ) )
|
||||
{
|
||||
rocket detonate();
|
||||
}
|
||||
missile thread heatseekingmissile::_missileDetonate( missile.target_attacker, missile.target_weapon, missile.target_weapon.explosionradius, 10, 20 );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function CleanupAfterMissileDeath( rocket, flak_drone )
|
||||
{
|
||||
missile = self;
|
||||
missile waittill( "death" );
|
||||
|
||||
wait 0.5; // make sure explosions fire off before deleting
|
||||
|
||||
if ( isdefined( rocket ) )
|
||||
{
|
||||
rocket delete();
|
||||
}
|
||||
|
||||
if ( isdefined( flak_drone ) )
|
||||
{
|
||||
flak_drone delete();
|
||||
}
|
||||
}
|
||||
|
||||
function state_death_update( params )
|
||||
{
|
||||
self endon( "death" );
|
||||
doGibbedDeath = false;
|
||||
|
||||
if( isdefined( self.death_info ) )
|
||||
{
|
||||
if( isdefined( self.death_info.weapon ) )
|
||||
{
|
||||
if( self.death_info.weapon.dogibbing || self.death_info.weapon.doannihilate )
|
||||
{
|
||||
doGibbedDeath = true;
|
||||
}
|
||||
}
|
||||
if( isdefined( self.death_info.meansOfDeath ) )
|
||||
{
|
||||
meansOfDeath = self.death_info.meansOfDeath;
|
||||
if( meansOfDeath == "MOD_EXPLOSIVE" || meansOfDeath == "MOD_GRENADE_SPLASH" || meansOfDeath == "MOD_PROJECTILE_SPLASH" || meansOfDeath == "MOD_PROJECTILE" )
|
||||
{
|
||||
doGibbedDeath = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( doGibbedDeath )
|
||||
{
|
||||
self playsound ("veh_wasp_gibbed");
|
||||
PlayFxOnTag( "explosions/fx_vexp_wasp_gibb_death", self, "tag_origin" );
|
||||
self Ghost();
|
||||
self NotSolid();
|
||||
|
||||
wait( 5 );
|
||||
if( isdefined( self ) )
|
||||
{
|
||||
self Delete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self vehicle_death::flipping_shooting_death();
|
||||
}
|
||||
}
|
||||
|
||||
function drone_pain_for_time( time, stablizeParam, restoreLookPoint )
|
||||
{
|
||||
self endon( "death" );
|
||||
|
||||
self.painStartTime = GetTime();
|
||||
|
||||
if ( !( isdefined( self.inpain ) && self.inpain ) )
|
||||
{
|
||||
self.inpain = true;
|
||||
|
||||
while ( GetTime() < self.painStartTime + time * 1000 )
|
||||
{
|
||||
self SetVehVelocity( self.velocity * stablizeParam );
|
||||
self SetAngularVelocity( self GetAngularVelocity() * stablizeParam );
|
||||
wait 0.1;
|
||||
}
|
||||
|
||||
if ( isdefined( restoreLookPoint ) )
|
||||
{
|
||||
restoreLookEnt = Spawn( "script_model", restoreLookPoint );
|
||||
restoreLookEnt SetModel( "tag_origin" );
|
||||
|
||||
self ClearLookAtEnt();
|
||||
self SetLookAtEnt( restoreLookEnt );
|
||||
self setTurretTargetEnt( restoreLookEnt );
|
||||
wait 1.5;
|
||||
|
||||
self ClearLookAtEnt();
|
||||
self ClearTurretTarget();
|
||||
restoreLookEnt delete();
|
||||
}
|
||||
|
||||
self.inpain = false;
|
||||
}
|
||||
}
|
||||
|
||||
function drone_pain( eAttacker, damageType, hitPoint, hitDirection, hitLocationInfo, partName )
|
||||
{
|
||||
if ( !( isdefined( self.inpain ) && self.inpain ) )
|
||||
{
|
||||
yaw_vel = math::randomSign() * RandomFloatRange( 280, 320 );
|
||||
|
||||
ang_vel = self GetAngularVelocity();
|
||||
ang_vel += ( RandomFloatRange( -120, -100 ), yaw_vel, RandomFloatRange( -200, 200 ) );
|
||||
self SetAngularVelocity( ang_vel );
|
||||
|
||||
self thread drone_pain_for_time( 0.8, 0.7 );
|
||||
}
|
||||
}
|
||||
|
||||
function FlakDroneDamageOverride( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
|
||||
{
|
||||
if( sMeansOfDeath == "MOD_TRIGGER_HURT" )
|
||||
return 0;
|
||||
|
||||
if( isdefined( eAttacker ) && isdefined( eAttacker.team ) && eAttacker.team != self.team )
|
||||
{
|
||||
drone_pain( eAttacker, sMeansOfDeath, vPoint, vDir, sHitLoc, partName );
|
||||
}
|
||||
|
||||
return iDamage;
|
||||
}
|
||||
|
||||
function Spawn( parent, onDeathCallback )
|
||||
{
|
||||
if( !IsNavVolumeLoaded() )
|
||||
{
|
||||
/# IPrintLnBold( "Error: NavVolume Not Loaded" ); #/
|
||||
return undefined;
|
||||
}
|
||||
|
||||
spawnPoint = parent.origin + ( 0, 0, -50 );
|
||||
|
||||
drone = SpawnVehicle( "veh_flak_drone_mp", spawnPoint, parent.angles, "dynamic_spawn_ai" );
|
||||
drone.death_callback = onDeathCallback;
|
||||
drone configureTeam( parent, false );
|
||||
drone thread WatchGameEvents();
|
||||
drone thread WatchDeath();
|
||||
drone thread WatchParentDeath();
|
||||
drone thread WatchParentMissiles();
|
||||
return drone;
|
||||
}
|
||||
|
||||
function configureTeam( parent, isHacked )
|
||||
{
|
||||
drone = self;
|
||||
drone.team = parent.team;
|
||||
drone SetTeam( parent.team );
|
||||
if ( isHacked )
|
||||
{
|
||||
drone clientfield::set( "enemyvehicle", 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
drone clientfield::set( "enemyvehicle", 1 );
|
||||
}
|
||||
drone.parent = parent;
|
||||
|
||||
}
|
||||
|
||||
function WatchGameEvents()
|
||||
{
|
||||
drone = self;
|
||||
drone endon( "death" );
|
||||
|
||||
drone.parent.owner util::waittill_any( "game_ended", "emp_jammed", "disconnect", "joined_team" );
|
||||
drone Shutdown( true );
|
||||
}
|
||||
|
||||
function WatchDeath()
|
||||
{
|
||||
drone = self;
|
||||
drone.parent endon( "death" );
|
||||
|
||||
drone waittill( "death" );
|
||||
drone Shutdown( true );
|
||||
}
|
||||
|
||||
function WatchParentDeath()
|
||||
{
|
||||
drone = self;
|
||||
drone endon( "death" );
|
||||
|
||||
drone.parent waittill( "death" );
|
||||
drone Shutdown( true );
|
||||
}
|
||||
|
||||
function WatchParentMissiles()
|
||||
{
|
||||
drone = self;
|
||||
drone endon( "death" );
|
||||
drone.parent endon( "death" );
|
||||
|
||||
drone.parent waittill( "stinger_fired_at_me", missile, weapon, attacker );
|
||||
|
||||
drone.incoming_missile = missile;
|
||||
drone.incoming_missile.target_weapon = weapon;
|
||||
drone.incoming_missile.target_attacker = attacker;
|
||||
drone vehicle_ai::set_state( "combat" );
|
||||
}
|
||||
|
||||
function SetCamoState( state )
|
||||
{
|
||||
self clientfield::set( "flak_drone_camo", state );
|
||||
}
|
||||
|
||||
function Shutdown( explode )
|
||||
{
|
||||
drone = self;
|
||||
|
||||
if( isdefined( drone.death_callback ) )
|
||||
{
|
||||
drone.parent thread [[ drone.death_callback ]]();
|
||||
}
|
||||
|
||||
if( isdefined( drone ) && !isdefined( drone.parent ) )
|
||||
{
|
||||
drone Ghost();
|
||||
drone NotSolid();
|
||||
wait( 5 );
|
||||
if( isdefined( drone ) )
|
||||
drone Delete();
|
||||
}
|
||||
|
||||
if( isdefined( drone ) )
|
||||
{
|
||||
if( explode )
|
||||
{
|
||||
drone DoDamage( drone.health + 1000, drone.origin, drone, drone, "none", "MOD_EXPLOSIVE" );
|
||||
}
|
||||
else
|
||||
{
|
||||
drone Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,661 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\math_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
#using scripts\shared\callbacks_shared;
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#using scripts\mp\_helicopter_sounds;
|
||||
#using scripts\mp\_util;
|
||||
|
||||
|
||||
|
||||
#using scripts\shared\duplicaterender_mgr;
|
||||
|
||||
|
||||
#precache( "client_fx", "killstreaks/fx_heli_smk_trail_engine_33" );
|
||||
#precache( "client_fx", "killstreaks/fx_heli_smk_trail_engine_66" );
|
||||
#precache( "client_fx", "killstreaks/fx_drgnfire_rotor_wash_runner" );
|
||||
#precache( "client_fx", "killstreaks/fx_ed_lights_green" );
|
||||
#precache( "client_fx", "killstreaks/fx_ed_lights_red" );
|
||||
#precache( "client_fx", "killstreaks/fx_sc_lights_grn" );
|
||||
#precache( "client_fx", "killstreaks/fx_sc_lights_red" );
|
||||
#precache( "client_fx", "killstreaks/fx_vtol_lights_grn" );
|
||||
#precache( "client_fx", "killstreaks/fx_vtol_lights_red" );
|
||||
#precache( "client_fx", "killstreaks/fx_vtol_thruster" );
|
||||
#precache( "client_fx", "killstreaks/fx_drone_hunter_lights" );
|
||||
|
||||
#using_animtree( "mp_vehicles" );
|
||||
|
||||
#namespace helicopter;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function autoexec __init__sytem__() { system::register("helicopter",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
level.chopper_fx["damage"]["light_smoke"] = "killstreaks/fx_heli_smk_trail_engine_33";
|
||||
level.chopper_fx["damage"]["heavy_smoke"] = "killstreaks/fx_heli_smk_trail_engine_66";
|
||||
|
||||
level._effect["qrdrone_prop"] = "killstreaks/fx_drgnfire_rotor_wash_runner";
|
||||
level._effect["heli_guard_light"]["friendly"] = "killstreaks/fx_sc_lights_grn";
|
||||
level._effect["heli_guard_light"]["enemy"] = "killstreaks/fx_sc_lights_red";
|
||||
level._effect["heli_comlink_light"]["common"] = "killstreaks/fx_drone_hunter_lights";
|
||||
level._effect["heli_gunner_light"]["friendly"] = "killstreaks/fx_vtol_lights_grn";
|
||||
level._effect["heli_gunner_light"]["enemy"] = "killstreaks/fx_vtol_lights_red";
|
||||
|
||||
level._effect["heli_gunner"]["vtol_fx"] = "killstreaks/fx_vtol_thruster";
|
||||
level._effect["heli_gunner"]["vtol_fx_ft"] = "killstreaks/fx_vtol_thruster";
|
||||
|
||||
clientfield::register( "helicopter", "heli_warn_targeted", 1, 1, "int", &warnMissileLocking, !true, !true);
|
||||
clientfield::register( "helicopter", "heli_warn_locked", 1, 1, "int", &warnMissileLocked, !true, !true);
|
||||
clientfield::register( "helicopter", "heli_warn_fired", 1, 1, "int", &warnMissileFired, !true, !true);
|
||||
|
||||
clientfield::register( "helicopter", "supplydrop_care_package_state", 1, 1, "int",&supplydrop_care_package_state, !true, !true);
|
||||
clientfield::register( "helicopter", "supplydrop_ai_tank_state", 1, 1, "int",&supplydrop_ai_tank_state, !true, !true);
|
||||
|
||||
clientfield::register( "helicopter", "heli_comlink_bootup_anim", 1, 1, "int",&heli_comlink_bootup_anim, !true, !true);
|
||||
|
||||
|
||||
clientfield::register( "vehicle", "heli_warn_targeted", 1, 1, "int", &warnMissileLocking, !true, !true);
|
||||
clientfield::register( "vehicle", "heli_warn_locked", 1, 1, "int", &warnMissileLocked, !true, !true);
|
||||
clientfield::register( "vehicle", "heli_warn_fired", 1, 1, "int", &warnMissileFired, !true, !true);
|
||||
|
||||
clientfield::register( "vehicle", "supplydrop_care_package_state", 1, 1, "int",&supplydrop_care_package_state, !true, !true);
|
||||
clientfield::register( "vehicle", "supplydrop_ai_tank_state", 1, 1, "int",&supplydrop_ai_tank_state, !true, !true);
|
||||
|
||||
clientfield::register( "vehicle", "heli_comlink_bootup_anim", 1, 1, "int",&heli_comlink_bootup_anim, !true, !true);
|
||||
|
||||
duplicate_render::set_dr_filter_framebuffer( "active_camo_scorestreak", 90, "active_camo_on", "", 0, "mc/hud_outline_predator_camo_active_enemy_scorestreak", 0 );
|
||||
duplicate_render::set_dr_filter_framebuffer( "active_camo_flicker_scorestreak", 80, "active_camo_flicker", "", 0, "mc/hud_outline_predator_camo_disruption_enemy_scorestreak", 0 );
|
||||
duplicate_render::set_dr_filter_framebuffer_duplicate( "active_camo_reveal_scorestreak_dr", 90, "active_camo_reveal", "hide_model", 1, "mc/hud_outline_predator_camo_active_enemy_scorestreak", 0 );
|
||||
duplicate_render::set_dr_filter_framebuffer( "active_camo_reveal_scorestreak", 80, "active_camo_reveal,hide_model", "", 0, "mc/hud_outline_predator_scorestreak", 0 );
|
||||
|
||||
clientfield::register( "helicopter", "active_camo", 1, 3, "int", &active_camo_changed, !true, !true );
|
||||
clientfield::register( "vehicle", "active_camo", 1, 3, "int", &active_camo_changed, !true, !true );
|
||||
|
||||
clientfield::register( "toplayer", "marker_state", 1, 2, "int", &marker_state_changed, !true, !true );
|
||||
|
||||
clientfield::register( "scriptmover", "supplydrop_thrusters_state", 1, 1, "int", &setSupplydropThrustersState, !true, !true );
|
||||
clientfield::register( "scriptmover", "aitank_thrusters_state", 1, 1, "int", &setAITankhrustersState, !true, !true );
|
||||
|
||||
clientfield::register( "vehicle", "mothership", 1, 1, "int", &mothership_cb, !true, !true );
|
||||
|
||||
callback::on_spawned( &on_player_spawned );
|
||||
}
|
||||
|
||||
function on_player_spawned( localClientNum )
|
||||
{
|
||||
player = self;
|
||||
player waittill( "entityshutdown" );
|
||||
player.markerFX = undefined;
|
||||
if( isdefined( player.markerObj ) )
|
||||
{
|
||||
player.markerObj Delete();
|
||||
}
|
||||
if( isdefined( player.markerFXHandle ) )
|
||||
{
|
||||
KillFX( localClientNum, player.markerFXHandle );
|
||||
player.markerFXHandle = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function SetupAnimTree()
|
||||
{
|
||||
if ( self HasAnimTree() == false )
|
||||
self UseAnimTree( #animtree );
|
||||
}
|
||||
|
||||
function active_camo_changed( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if( newVal == ( 0 ) )
|
||||
{
|
||||
self thread heli_comlink_lights_on_after_wait( localClientNum, ( 0.7 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
self heli_comlink_lights_off( localClientNum );
|
||||
}
|
||||
|
||||
flags_changed = self duplicate_render::set_dr_flag( "active_camo_flicker", newVal == ( 2 ) );
|
||||
flags_changed = self duplicate_render::set_dr_flag( "active_camo_on", false ) || flags_changed;
|
||||
flags_changed = self duplicate_render::set_dr_flag( "active_camo_reveal", true ) || flags_changed;
|
||||
|
||||
if ( flags_changed )
|
||||
{
|
||||
self duplicate_render::update_dr_filters(localClientNum);
|
||||
}
|
||||
|
||||
self notify( "endtest" );
|
||||
|
||||
self thread doReveal( localClientNum, newVal != ( 0 ) );
|
||||
}
|
||||
|
||||
function doReveal( local_client_num, direction )
|
||||
{
|
||||
self notify( "endtest" );
|
||||
self endon( "endtest" );
|
||||
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
if( direction )
|
||||
{
|
||||
self duplicate_render::update_dr_flag( local_client_num, "hide_model", false );
|
||||
startVal = 0;
|
||||
endVal = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
self duplicate_render::update_dr_flag( local_client_num, "hide_model", true );
|
||||
startVal = 1;
|
||||
endVal = 0;
|
||||
}
|
||||
|
||||
priorValue = startVal;
|
||||
while( ( startVal >= 0 ) && ( startVal <= 1 ) )
|
||||
{
|
||||
self MapShaderConstant( local_client_num, 0, "scriptVector0", startVal, 0, 0, 0 );
|
||||
if( direction )
|
||||
{
|
||||
startVal += .016 / 0.5;
|
||||
if( ( priorValue < .5 ) && ( startVal >= .5 ) )
|
||||
{
|
||||
self duplicate_render::set_dr_flag( "hide_model", true );
|
||||
self duplicate_render::change_dr_flags(local_client_num);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
startVal -= .016 / 0.5;
|
||||
if( ( priorValue > .5 ) && ( startVal <= .5 ) )
|
||||
{
|
||||
self duplicate_render::set_dr_flag( "hide_model", false );
|
||||
self duplicate_render::change_dr_flags(local_client_num);
|
||||
}
|
||||
}
|
||||
priorValue = startVal;
|
||||
wait( .016 );
|
||||
}
|
||||
self MapShaderConstant( local_client_num, 0, "scriptVector0", endVal, 0, 0, 0 );
|
||||
|
||||
flags_changed = self duplicate_render::set_dr_flag( "active_camo_reveal", false );
|
||||
flags_changed = self duplicate_render::set_dr_flag( "active_camo_on", direction ) || flags_changed;
|
||||
if ( flags_changed )
|
||||
{
|
||||
self duplicate_render::update_dr_filters(local_client_num);
|
||||
}
|
||||
}
|
||||
|
||||
function heli_comlink_bootup_anim( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump)
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
self endon( "death" );
|
||||
|
||||
self SetupAnimTree();
|
||||
self SetAnim( %veh_anim_future_heli_gearup_bay_open, 1.0, 0.0, 1.0 );
|
||||
}
|
||||
|
||||
function supplydrop_care_package_state( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump)
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
self endon( "death" );
|
||||
self SetupAnimTree();
|
||||
if ( newVal == 1 )
|
||||
{
|
||||
self SetAnim( %o_drone_supply_care_idle, 1.0, 0.0, 1.0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
self SetAnim( %o_drone_supply_care_drop, 1.0, 0.0, 0.3 );
|
||||
}
|
||||
}
|
||||
|
||||
function supplydrop_ai_tank_state( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump)
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
self endon( "death" );
|
||||
self SetupAnimTree();
|
||||
|
||||
if ( newVal == 1 )
|
||||
{
|
||||
self SetAnim( %o_drone_supply_agr_idle, 1.0, 0.0, 1.0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
self SetAnim( %o_drone_supply_agr_drop, 1.0, 0.0, 0.3 );
|
||||
}
|
||||
}
|
||||
|
||||
function warnMissileLocking( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( newVal && !(self IsLocalClientDriver(localClientNum)) )
|
||||
return;
|
||||
|
||||
helicopter_sounds::play_targeted_sound( newVal );
|
||||
}
|
||||
|
||||
function warnMissileLocked( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( newVal && !(self IsLocalClientDriver(localClientNum)) )
|
||||
return;
|
||||
|
||||
helicopter_sounds::play_locked_sound( newVal );
|
||||
}
|
||||
|
||||
function warnMissileFired( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( newVal && !(self IsLocalClientDriver(localClientNum)) )
|
||||
return;
|
||||
|
||||
helicopter_sounds::play_fired_sound( newVal );
|
||||
}
|
||||
|
||||
function heli_deletefx(localClientNum)
|
||||
{
|
||||
if (isdefined(self.exhaustLeftFxHandle))
|
||||
{
|
||||
deletefx( localClientNum, self.exhaustLeftFxHandle );
|
||||
self.exhaustLeftFxHandle = undefined;
|
||||
}
|
||||
|
||||
if (isdefined(self.exhaustRightFxHandlee))
|
||||
{
|
||||
deletefx( localClientNum, self.exhaustRightFxHandle );
|
||||
self.exhaustRightFxHandle = undefined;
|
||||
}
|
||||
|
||||
if (isdefined(self.lightFXID))
|
||||
{
|
||||
deletefx( localClientNum, self.lightFXID );
|
||||
self.lightFXID = undefined;
|
||||
}
|
||||
|
||||
if (isdefined(self.propFXID))
|
||||
{
|
||||
deletefx( localClientNum, self.propFXID );
|
||||
self.propFXID = undefined;
|
||||
}
|
||||
|
||||
if (isdefined(self.vtolLeftFXID))
|
||||
{
|
||||
deletefx( localClientNum, self.vtolLeftFXID );
|
||||
self.vtolLeftFXID = undefined;
|
||||
}
|
||||
|
||||
if (isdefined(self.vtolRightFXID))
|
||||
{
|
||||
deletefx( localClientNum, self.vtolRightFXID );
|
||||
self.vtolRightFXID = undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function startfx(localClientNum)
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
if ( isdefined( self.vehicletype ) )
|
||||
{
|
||||
if ( self.vehicletype == "remote_mortar_vehicle_mp" )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( self.vehicletype == "vehicle_straferun_mp" )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if( isdefined( self.exhaustfxname ) && self.exhaustfxname != "" )
|
||||
{
|
||||
self.exhaustFx = self.exhaustfxname;
|
||||
}
|
||||
|
||||
if( isdefined(self.exhaustFx) )
|
||||
{
|
||||
self.exhaustLeftFxHandle = PlayFXOnTag( localClientNum, self.exhaustFx, self, "tag_engine_left" );
|
||||
if( !( isdefined( self.oneexhaust ) && self.oneexhaust ) /*!self.oneexhaust*/ )//TODO T7 - not sure why this isn't getting set anymore
|
||||
{
|
||||
self.exhaustRightFxHandle = PlayFXOnTag( localClientNum, self.exhaustFx, self, "tag_engine_right" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/# PrintLn("Client: _helicopter.csc - startfx() - exhaust rotor fx is not loaded"); #/
|
||||
}
|
||||
|
||||
if( isdefined( self.vehicletype ) )
|
||||
{
|
||||
light_fx = undefined;
|
||||
prop_fx = undefined;
|
||||
|
||||
switch( self.vehicletype )
|
||||
{
|
||||
case "heli_ai_mp":
|
||||
light_fx = "heli_comlink_light";
|
||||
break;
|
||||
case "heli_player_gunner_mp":
|
||||
//TODO store FX not on self to prevent edge cases where it doesnt get cleaned up
|
||||
self.vtolLeftFXID = PlayFXOnTag( localClientNum, level._effect["heli_gunner"]["vtol_fx"], self, "tag_engine_left" );
|
||||
self.vtolRightFXID = PlayFXOnTag( localClientNum, level._effect["heli_gunner"]["vtol_fx_ft"], self, "tag_engine_right" );
|
||||
light_fx = "heli_gunner_light";
|
||||
break;
|
||||
case "heli_guard_mp":
|
||||
light_fx = "heli_guard_light";
|
||||
break;
|
||||
case "qrdrone_mp":
|
||||
prop_fx = "qrdrone_prop";
|
||||
break;
|
||||
};
|
||||
|
||||
if ( isdefined( light_fx ) )
|
||||
{
|
||||
if ( self util::friend_not_foe( localClientNum ) )
|
||||
{
|
||||
self.lightFXID = PlayFXOnTag( localClientNum, level._effect[light_fx]["friendly"], self, "tag_origin" );
|
||||
}
|
||||
else
|
||||
{
|
||||
self.lightFXID = PlayFXOnTag( localClientNum, level._effect[light_fx]["enemy"], self, "tag_origin" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isdefined( prop_fx ) && !self IsLocalClientDriver( localClientNum ))
|
||||
{
|
||||
self.propFXID = PlayFXOnTag( localClientNum, level._effect[prop_fx], self, "tag_origin" );
|
||||
}
|
||||
}
|
||||
|
||||
self damage_fx_stages(localClientNum);
|
||||
}
|
||||
|
||||
function startfx_loop(localClientNum)
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
self thread helicopter_sounds::aircraft_dustkick(localClientNum);
|
||||
|
||||
startfx( localClientNum );
|
||||
|
||||
serverTime = getServerTime( 0 );
|
||||
lastServerTime = serverTime;
|
||||
|
||||
while( isdefined( self ) )
|
||||
{
|
||||
if (serverTime < lastServerTime)
|
||||
{
|
||||
heli_deletefx( localClientNum );
|
||||
startfx( localClientNum );
|
||||
}
|
||||
wait( 0.05 ); // small for added granularity. any bigger and rapid time switching can cause problems.
|
||||
lastServerTime = serverTime;
|
||||
serverTime = getServerTime( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
function damage_fx_stages(localClientNum)
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
last_damage_state = self GetHeliDamageState();
|
||||
fx = undefined;
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
if ( last_damage_state != self GetHeliDamageState() )
|
||||
{
|
||||
if ( self GetHeliDamageState() == 2 )
|
||||
{
|
||||
if ( isdefined(fx) )
|
||||
stopfx( localClientNum, fx );
|
||||
|
||||
fx = trail_fx( localClientNum, level.chopper_fx["damage"]["light_smoke"], "tag_engine_left" );
|
||||
}
|
||||
else if ( self GetHeliDamageState() == 1 )
|
||||
{
|
||||
if ( isdefined(fx) )
|
||||
stopfx( localClientNum, fx );
|
||||
|
||||
fx = trail_fx( localClientNum, level.chopper_fx["damage"]["heavy_smoke"], "tag_engine_left" );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( isdefined(fx) )
|
||||
stopfx( localClientNum, fx );
|
||||
|
||||
self notify( "stop trail" );
|
||||
}
|
||||
last_damage_state = self GetHeliDamageState();
|
||||
}
|
||||
wait(0.25);
|
||||
}
|
||||
}
|
||||
|
||||
function trail_fx( localClientNum, trail_fx, trail_tag )
|
||||
{
|
||||
id = playfxontag( localClientNum, trail_fx, self, trail_tag );
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
function heli_comlink_lights_on_after_wait( localClientNum, wait_time )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
self endon( "heli_comlink_lights_off" );
|
||||
|
||||
wait wait_time;
|
||||
|
||||
self heli_comlink_lights_on( localclientnum );
|
||||
}
|
||||
|
||||
function heli_comlink_lights_on( localClientNum )
|
||||
{
|
||||
if( !isdefined( self.light_fx_handles_heli_comlink ) )
|
||||
{
|
||||
self.light_fx_handles_heli_comlink = [];
|
||||
}
|
||||
|
||||
self.light_fx_handles_heli_comlink[ 0 ] = PlayFXOnTag( localClientNum, level._effect["heli_comlink_light"]["common"], self, "tag_fx_light_left" );
|
||||
self.light_fx_handles_heli_comlink[ 1 ] = PlayFXOnTag( localClientNum, level._effect["heli_comlink_light"]["common"], self, "tag_fx_light_right" );
|
||||
self.light_fx_handles_heli_comlink[ 2 ] = PlayFXOnTag( localClientNum, level._effect["heli_comlink_light"]["common"], self, "tag_fx_tail" );
|
||||
self.light_fx_handles_heli_comlink[ 3 ] = PlayFXOnTag( localClientNum, level._effect["heli_comlink_light"]["common"], self, "tag_fx_scanner" );
|
||||
|
||||
if( isdefined( self.team ) )
|
||||
{
|
||||
for ( i = 0; i < self.light_fx_handles_heli_comlink.size; i++ )
|
||||
SetFXTeam( localClientNum, self.light_fx_handles_heli_comlink[ i ], self.owner.team );
|
||||
}
|
||||
}
|
||||
|
||||
function heli_comlink_lights_off( localClientNum )
|
||||
{
|
||||
self notify( "heli_comlink_lights_off" );
|
||||
|
||||
if ( isdefined( self.light_fx_handles_heli_comlink ) )
|
||||
{
|
||||
for( i = 0; i < self.light_fx_handles_heli_comlink.size; i++ )
|
||||
{
|
||||
if ( isdefined( self.light_fx_handles_heli_comlink[ i ] ) )
|
||||
{
|
||||
DeleteFX( localClientNum, self.light_fx_handles_heli_comlink[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
self.light_fx_handles_heli_comlink = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function UpdateMarkerThread( localClientNum )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
player = self;
|
||||
|
||||
killstreakCoreBundle = struct::get_script_bundle( "killstreak", "killstreak_core" );
|
||||
|
||||
while( isdefined( player.markerObj ) )
|
||||
{
|
||||
viewAngles = GetLocalClientAngles( localClientNum );
|
||||
|
||||
forwardVector = VectorScale( AnglesToForward( viewAngles ), killstreakCoreBundle.ksMaxAirdropTargetRange );
|
||||
results = BulletTrace( player GetEye(), player GetEye() + forwardVector, false, player );
|
||||
|
||||
player.markerObj.origin = results["position"];
|
||||
|
||||
wait( .016 );
|
||||
}
|
||||
}
|
||||
|
||||
function StopCrateEffects( localClientNum )
|
||||
{
|
||||
crate = self;
|
||||
|
||||
if( isdefined( crate.thrusterFxHandle0 ) )
|
||||
StopFX( localClientNum, crate.thrusterFxHandle0 );
|
||||
if( isdefined( crate.thrusterFxHandle1 ) )
|
||||
StopFX( localClientNum, crate.thrusterFxHandle1 );
|
||||
if( isdefined( crate.thrusterFxHandle2 ) )
|
||||
StopFX( localClientNum, crate.thrusterFxHandle2 );
|
||||
if( isdefined( crate.thrusterFxHandle3 ) )
|
||||
StopFX( localClientNum, crate.thrusterFxHandle3 );
|
||||
|
||||
crate.thrusterFxHandle0 = undefined;
|
||||
crate.thrusterFxHandle1 = undefined;
|
||||
crate.thrusterFxHandle2 = undefined;
|
||||
crate.thrusterFxHandle3 = undefined;
|
||||
}
|
||||
|
||||
function CleanupThrustersThread( localClientNum )
|
||||
{
|
||||
crate = self;
|
||||
|
||||
crate notify( "CleanupThrustersThread_singleton" );
|
||||
crate endon( "CleanupThrustersThread_singleton" );
|
||||
|
||||
crate waittill( "entityshutdown" );
|
||||
|
||||
crate StopCrateEffects( localClientNum );
|
||||
}
|
||||
|
||||
function setSupplydropThrustersState( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
crate = self;
|
||||
params = struct::get_script_bundle( "killstreak", "killstreak_supply_drop" );
|
||||
|
||||
if( ( newVal != oldVal ) && isdefined( params.ksThrusterFX ) )
|
||||
{
|
||||
if( newVal == 1 )
|
||||
{
|
||||
crate StopCrateEffects( localClientNum );
|
||||
|
||||
crate.thrusterFxHandle0 = PlayFXOnTag( localClientNum, params.ksThrusterFX, crate, "tag_thruster_fx_01" );
|
||||
crate.thrusterFxHandle1 = PlayFXOnTag( localClientNum, params.ksThrusterFX, crate, "tag_thruster_fx_02" );
|
||||
crate.thrusterFxHandle2 = PlayFXOnTag( localClientNum, params.ksThrusterFX, crate, "tag_thruster_fx_03" );
|
||||
crate.thrusterFxHandle3 = PlayFXOnTag( localClientNum, params.ksThrusterFX, crate, "tag_thruster_fx_04" );
|
||||
|
||||
crate thread CleanupThrustersThread( localClientNum );
|
||||
}
|
||||
else
|
||||
{
|
||||
crate StopCrateEffects( localClientNum );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function mothership_cb( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
}
|
||||
|
||||
function setAITankhrustersState( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
crate = self;
|
||||
params = struct::get_script_bundle( "killstreak", "killstreak_ai_tank_drop" );
|
||||
|
||||
if( ( newVal != oldVal ) && isdefined( params.ksThrusterFX ) )
|
||||
{
|
||||
if( newVal == 1 )
|
||||
{
|
||||
crate StopCrateEffects( localClientNum );
|
||||
|
||||
crate.thrusterFxHandle0 = PlayFXOnTag( localClientNum, params.ksThrusterFX, crate, "tag_thruster_fx_01" );
|
||||
crate.thrusterFxHandle1 = PlayFXOnTag( localClientNum, params.ksThrusterFX, crate, "tag_thruster_fx_02" );
|
||||
crate.thrusterFxHandle2 = PlayFXOnTag( localClientNum, params.ksThrusterFX, crate, "tag_thruster_fx_03" );
|
||||
crate.thrusterFxHandle3 = PlayFXOnTag( localClientNum, params.ksThrusterFX, crate, "tag_thruster_fx_04" );
|
||||
|
||||
crate thread CleanupThrustersThread( localClientNum );
|
||||
}
|
||||
else
|
||||
{
|
||||
crate StopCrateEffects( localClientNum );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function marker_state_changed( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
player = self;
|
||||
|
||||
killstreakCoreBundle = struct::get_script_bundle( "killstreak", "killstreak_core" );
|
||||
|
||||
// Pick the new effect
|
||||
if( newVal == 1 )
|
||||
{
|
||||
player.markerFX = killstreakCoreBundle.fxValidLocation;
|
||||
}
|
||||
else if ( newVal == 2 )
|
||||
{
|
||||
player.markerFX = killstreakCoreBundle.fxInvalidLocation;
|
||||
}
|
||||
else
|
||||
{
|
||||
player.markerFX = undefined;
|
||||
}
|
||||
|
||||
// Another thread is waiting for dobj creation
|
||||
if ( isdefined( player.markerObj ) && !( player.markerObj hasdobj( localClientNum ) ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the old effect
|
||||
if( isdefined( player.markerFXHandle ) )
|
||||
{
|
||||
KillFX( localClientNum, player.markerFXHandle ) ;
|
||||
player.markerFXHandle = undefined;
|
||||
}
|
||||
|
||||
if ( isdefined( player.markerFX ) )
|
||||
{
|
||||
if( !isdefined( player.markerObj ) )
|
||||
{
|
||||
player.markerObj = Spawn( localClientNum, ( 0, 0, 0 ), "script_model" );
|
||||
player.markerObj.angles = ( 270, 0, 0 );
|
||||
|
||||
player.markerObj SetModel( "wpn_t7_none_world" ); // No-model model to create dobj
|
||||
|
||||
player.markerObj util::waittill_dobj( localClientNum );
|
||||
|
||||
player thread UpdateMarkerThread( localClientNum );
|
||||
}
|
||||
|
||||
player.markerFXHandle = PlayFXOnTag( localClientNum, player.markerFX, player.markerObj, "tag_origin" );
|
||||
}
|
||||
else if( isdefined( player.markerObj ) )
|
||||
{
|
||||
player.markerObj Delete();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,70 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\visionset_mgr_shared;
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
|
||||
|
||||
#namespace helicopter_gunner;
|
||||
|
||||
function autoexec __init__sytem__() { system::register("helicopter_gunner",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
clientfield::register( "vehicle", "vtol_turret_destroyed_0", 1, 1, "int", &turret_destroyed_0, !true, !true );
|
||||
clientfield::register( "vehicle", "vtol_turret_destroyed_1", 1, 1, "int", &turret_destroyed_1, !true, !true );
|
||||
clientfield::register( "toplayer", "vtol_update_client", 1, 1, "counter", &update_client, !true, !true );
|
||||
clientfield::register( "toplayer", "fog_bank_2", 1, 1, "int", &fog_bank_2_callback, !true, !true);
|
||||
|
||||
visionset_mgr::register_visionset_info( "mothership_visionset", 1, 1, undefined, "mp_vehicles_mothership" );
|
||||
}
|
||||
|
||||
function turret_destroyed_0( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
// /# IPrintLnBold( "Turret Destroyed A: " + newVal ); #/
|
||||
}
|
||||
|
||||
function turret_destroyed_1( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
// /# IPrintLnBold( "Turret Destroyed B: " + newVal ); #/
|
||||
}
|
||||
|
||||
function update_turret_destroyed( localClientNum, ui_model_name, new_value )
|
||||
{
|
||||
part_destroyed_ui_model = GetUIModel( GetUIModelForController( localClientNum ), ui_model_name );
|
||||
|
||||
if ( isdefined( part_destroyed_ui_model ) )
|
||||
SetUIModelValue( part_destroyed_ui_model, new_value );
|
||||
|
||||
// /# IPrintLnBold( ui_model_name + " set to: " + new_value ); #/
|
||||
}
|
||||
|
||||
function update_client( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
veh = GetPlayerVehicle( self );
|
||||
if( isdefined( veh ) )
|
||||
{
|
||||
update_turret_destroyed( localClientNum, "vehicle.partDestroyed.0", veh clientfield::get( "vtol_turret_destroyed_0" ) );
|
||||
update_turret_destroyed( localClientNum, "vehicle.partDestroyed.1", veh clientfield::get( "vtol_turret_destroyed_1" ) );
|
||||
}
|
||||
}
|
||||
|
||||
function fog_bank_2_callback(localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump)
|
||||
{
|
||||
if ( oldVal != newVal )
|
||||
{
|
||||
if ( newVal == 1 )
|
||||
{
|
||||
SetLitFogBank( localClientNum, -1, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLitFogBank( localClientNum, -1, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,471 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\popups_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
|
||||
#namespace killstreak_bundles;
|
||||
|
||||
function register_killstreak_bundle( killstreakType )
|
||||
{
|
||||
level.killstreakBundle[killstreakType] = struct::get_script_bundle( "killstreak", "killstreak_" + killstreakType );
|
||||
level.killstreakBundle["inventory_" + killstreakType] = level.killstreakBundle[killstreakType];
|
||||
level.killstreakMaxHealthFunction = &killstreak_bundles::get_max_health;
|
||||
assert( isdefined( level.killstreakBundle[killstreakType] ) );
|
||||
}
|
||||
|
||||
function get_bundle( killstreak )
|
||||
{
|
||||
if( killstreak.archetype === "raps" )
|
||||
return level.killstreakBundle["raps_drone"];
|
||||
else
|
||||
return level.killstreakBundle[killstreak.killstreakType];
|
||||
}
|
||||
|
||||
function get_hack_timeout()
|
||||
{
|
||||
killstreak = self;
|
||||
bundle = get_bundle( killstreak );
|
||||
|
||||
return bundle.ksHackTimeout;
|
||||
}
|
||||
|
||||
function get_hack_protection()
|
||||
{
|
||||
killstreak = self;
|
||||
hackedProtection = false;
|
||||
|
||||
bundle = get_bundle( killstreak );
|
||||
if ( isdefined( bundle.ksHackProtection ) )
|
||||
{
|
||||
hackedProtection = bundle.ksHackProtection;
|
||||
}
|
||||
|
||||
return hackedProtection;
|
||||
}
|
||||
|
||||
function get_hack_tool_inner_time()
|
||||
{
|
||||
killstreak = self;
|
||||
hackToolInnerTime = 10000;
|
||||
|
||||
bundle = get_bundle( killstreak );
|
||||
if ( isdefined( bundle.ksHackToolInnerTime ) )
|
||||
{
|
||||
hackToolInnerTime = bundle.ksHackToolInnerTime;
|
||||
}
|
||||
|
||||
return hackToolInnerTime;
|
||||
}
|
||||
|
||||
function get_hack_tool_outer_time()
|
||||
{
|
||||
killstreak = self;
|
||||
hackToolOuterTime = 10000;
|
||||
|
||||
bundle = get_bundle( killstreak );
|
||||
if ( isdefined( bundle.ksHackToolOuterTime ) )
|
||||
{
|
||||
hackToolOuterTime = bundle.ksHackToolOuterTime;
|
||||
}
|
||||
|
||||
return hackToolOuterTime;
|
||||
}
|
||||
|
||||
function get_hack_tool_inner_radius()
|
||||
{
|
||||
killstreak = self;
|
||||
hackedToolInnerRadius = 10000;
|
||||
|
||||
bundle = get_bundle( killstreak );
|
||||
if ( isdefined( bundle.ksHackToolInnerRadius ) )
|
||||
{
|
||||
hackedToolInnerRadius = bundle.ksHackToolInnerRadius;
|
||||
}
|
||||
|
||||
return hackedToolInnerRadius;
|
||||
}
|
||||
|
||||
|
||||
function get_hack_tool_outer_radius()
|
||||
{
|
||||
killstreak = self;
|
||||
hackedToolOuterRadius = 10000;
|
||||
|
||||
bundle = get_bundle( killstreak );
|
||||
if ( isdefined( bundle.ksHackToolOuterRadius ) )
|
||||
{
|
||||
hackedToolOuterRadius = bundle.ksHackToolOuterRadius;
|
||||
}
|
||||
|
||||
return hackedToolOuterRadius;
|
||||
}
|
||||
|
||||
|
||||
function get_lost_line_of_sight_limit_msec()
|
||||
{
|
||||
killstreak = self;
|
||||
hackedToolLostLineOfSightLimitMs = 1000;
|
||||
|
||||
bundle = get_bundle( killstreak );
|
||||
if ( isdefined( bundle.ksHackToolLostLineOfSightLimitMs ) )
|
||||
{
|
||||
hackedToolLostLineOfSightLimitMs = bundle.ksHackToolLostLineOfSightLimitMs;
|
||||
}
|
||||
|
||||
return hackedToolLostLineOfSightLimitMs;
|
||||
}
|
||||
|
||||
|
||||
function get_hack_tool_no_line_of_sight_time()
|
||||
{
|
||||
killstreak = self;
|
||||
hackToolNoLineOfSightTime = 1000;
|
||||
|
||||
bundle = get_bundle( killstreak );
|
||||
if ( isdefined( bundle.ksHackToolNoLineOfSightTime ) )
|
||||
{
|
||||
hackToolNoLineOfSightTime = bundle.ksHackToolNoLineOfSightTime;
|
||||
}
|
||||
|
||||
return hackToolNoLineOfSightTime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function get_hack_scoreevent()
|
||||
{
|
||||
killstreak = self;
|
||||
hackedScoreEvent = undefined;
|
||||
bundle = get_bundle( killstreak );
|
||||
if ( isdefined( bundle.ksHackScoreEvent ) )
|
||||
{
|
||||
hackedScoreEvent = bundle.ksHackScoreEvent;
|
||||
}
|
||||
|
||||
return hackedScoreEvent;
|
||||
}
|
||||
|
||||
function get_hack_fx()
|
||||
{
|
||||
killstreak = self;
|
||||
hackFX = "";
|
||||
|
||||
bundle = get_bundle( killstreak );
|
||||
if ( isdefined( bundle.ksHackFX ) )
|
||||
{
|
||||
hackFX = bundle.ksHackFX;
|
||||
}
|
||||
|
||||
return hackFX;
|
||||
}
|
||||
|
||||
function get_hack_loop_fx()
|
||||
{
|
||||
killstreak = self;
|
||||
hackLoopFX = "";
|
||||
|
||||
bundle = get_bundle( killstreak );
|
||||
if ( isdefined( bundle.ksHackLoopFX ) )
|
||||
{
|
||||
hackLoopFX = bundle.ksHackLoopFX;
|
||||
}
|
||||
|
||||
return hackLoopFX;
|
||||
}
|
||||
|
||||
function get_max_health( killstreakType )
|
||||
{
|
||||
bundle = level.killstreakBundle[killstreakType];
|
||||
|
||||
return bundle.ksHealth;
|
||||
}
|
||||
|
||||
function get_low_health( killstreakType )
|
||||
{
|
||||
bundle = level.killstreakBundle[killstreakType];
|
||||
|
||||
return bundle.ksLowHealth;
|
||||
}
|
||||
|
||||
function get_hacked_health( killstreakType )
|
||||
{
|
||||
bundle = level.killstreakBundle[killstreakType];
|
||||
|
||||
return bundle.ksHackedHealth;
|
||||
}
|
||||
|
||||
function get_shots_to_kill( weapon, meansOfDeath, bundle )
|
||||
{
|
||||
shotsToKill = undefined;
|
||||
|
||||
switch( weapon.rootweapon.name )
|
||||
{
|
||||
case "remote_missile_missile":
|
||||
shotsToKill = bundle.ksRemote_missile_missile;
|
||||
break;
|
||||
case "hero_annihilator":
|
||||
shotsToKill = bundle.ksHero_annihilator;
|
||||
break;
|
||||
case "hero_armblade":
|
||||
shotsToKill = bundle.ksHero_armblade;
|
||||
break;
|
||||
case "hero_bowlauncher":
|
||||
case "hero_bowlauncher2":
|
||||
case "hero_bowlauncher3":
|
||||
case "hero_bowlauncher4":
|
||||
if ( meansOfDeath == "MOD_PROJECTILE_SPLASH" || meansOfDeath == "MOD_PROJECTILE" )
|
||||
{
|
||||
shotsToKill = bundle.ksHero_bowlauncher;
|
||||
}
|
||||
else
|
||||
{
|
||||
shotstoKill = -1;
|
||||
}
|
||||
break;
|
||||
case "hero_gravityspikes":
|
||||
shotsToKill = bundle.ksHero_gravityspikes;
|
||||
break;
|
||||
case "hero_lightninggun":
|
||||
shotsToKill = bundle.ksHero_lightninggun;
|
||||
break;
|
||||
case "hero_minigun":
|
||||
case "hero_minigun_body3":
|
||||
shotsToKill = bundle.ksHero_minigun;
|
||||
break;
|
||||
case "hero_pineapplegun":
|
||||
shotsToKill = bundle.ksHero_pineapplegun;
|
||||
break;
|
||||
case "hero_firefly_swarm":
|
||||
shotsToKill = (isdefined(bundle.ksHero_firefly_swarm)?bundle.ksHero_firefly_swarm:0) * 4;
|
||||
break;
|
||||
case "dart_blade":
|
||||
case "dart_turret":
|
||||
shotsToKill = bundle.ksDartsToKill;
|
||||
break;
|
||||
case "gadget_heat_wave":
|
||||
shotsToKill = bundle.ksHero_heatwave;
|
||||
break;
|
||||
}
|
||||
|
||||
return (isdefined(shotsToKill)?shotsToKill:0);
|
||||
}
|
||||
|
||||
function get_emp_grenade_damage( killstreakType, maxhealth )
|
||||
{
|
||||
// weapon_damage returns as undefined if it is not handled here
|
||||
|
||||
emp_weapon_damage = undefined;
|
||||
|
||||
if ( isdefined( level.killstreakBundle[killstreakType] ) )
|
||||
{
|
||||
bundle = level.killstreakBundle[killstreakType];
|
||||
|
||||
empGrenadesToKill = (isdefined(bundle.ksEmpGrenadesToKill)?bundle.ksEmpGrenadesToKill:0);
|
||||
|
||||
if ( empGrenadesToKill == 0 )
|
||||
{
|
||||
// not handled here
|
||||
}
|
||||
else if ( empGrenadesToKill > 0 )
|
||||
{
|
||||
emp_weapon_damage = maxhealth / empGrenadesToKill + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// immune
|
||||
emp_weapon_damage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return emp_weapon_damage;
|
||||
}
|
||||
|
||||
function get_weapon_damage( killstreakType, maxhealth, attacker, weapon, type, damage, flags, chargeShotLevel )
|
||||
{
|
||||
// weapon_damage returns as undefined if it is not handled here
|
||||
|
||||
weapon_damage = undefined;
|
||||
|
||||
if ( isdefined( level.killstreakBundle[killstreakType] ) )
|
||||
{
|
||||
bundle = level.killstreakBundle[killstreakType];
|
||||
|
||||
if ( isdefined( weapon ) )
|
||||
{
|
||||
shotsToKill = get_shots_to_kill( weapon, type, bundle );
|
||||
|
||||
if ( shotsToKill == 0 )
|
||||
{
|
||||
// not handled here
|
||||
}
|
||||
else if ( shotsToKill > 0 )
|
||||
{
|
||||
if ( isdefined( chargeShotLevel ) && chargeShotLevel > 0 )
|
||||
{
|
||||
// chargeShotLevel should be between 0 and 1.
|
||||
// 1 = full charge
|
||||
// > 0 = fraction of charge
|
||||
shotsToKill = shotsToKill / chargeShotLevel;
|
||||
}
|
||||
|
||||
weapon_damage = maxhealth / shotsToKill + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// immune
|
||||
weapon_damage = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( !isdefined( weapon_damage ) )
|
||||
{
|
||||
if ( type == "MOD_RIFLE_BULLET" || type == "MOD_PISTOL_BULLET" || type == "MOD_HEAD_SHOT" )
|
||||
{
|
||||
hasArmorPiercing = isdefined( attacker ) && isPlayer( attacker ) && attacker HasPerk( "specialty_armorpiercing" );
|
||||
|
||||
clipsToKill = (isdefined(bundle.ksClipsToKill)?bundle.ksClipsToKill:0);
|
||||
if( clipsToKill == -1 )
|
||||
{
|
||||
// immune
|
||||
weapon_damage = 0;
|
||||
}
|
||||
else if ( hasArmorPiercing && self.aitype !== "spawner_bo3_robot_grunt_assault_mp_escort" ) // HACK TU4 FFOTD DT 150126 - Don't apply FMJ damage to the escort robot
|
||||
{
|
||||
weapon_damage = damage + int( damage * level.cac_armorpiercing_data);
|
||||
}
|
||||
|
||||
if ( weapon.weapClass == "spread" )
|
||||
{
|
||||
ksShotgunMultiplier = (isdefined(bundle.ksShotgunMultiplier)?bundle.ksShotgunMultiplier:1);
|
||||
|
||||
if ( ksShotgunMultiplier == 0 )
|
||||
{
|
||||
// not handled here
|
||||
}
|
||||
else if ( ksShotgunMultiplier > 0 )
|
||||
{
|
||||
weapon_damage = (isdefined(weapon_damage)?weapon_damage:damage) * ksShotgunMultiplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( ( type == "MOD_PROJECTILE" || type == "MOD_EXPLOSIVE" )
|
||||
&& ( !isdefined( weapon.isEmpKillstreak ) || !weapon.isEmpKillstreak )
|
||||
&& ( weapon.statIndex != level.weaponPistolEnergy.statIndex )
|
||||
&& ( weapon.statIndex != level.weaponSpecialCrossbow.statIndex )
|
||||
&& ( weapon.statIndex != level.weaponSmgNailGun.statIndex )
|
||||
&& ( weapon.statIndex != level.weaponBouncingBetty.statIndex ) )
|
||||
{
|
||||
if ( weapon.statIndex == level.weaponShotgunEnergy.statIndex )
|
||||
{
|
||||
shotgunEnergyToKill = (isdefined(bundle.ksShotgunEnergyToKill)?bundle.ksShotgunEnergyToKill:0);
|
||||
|
||||
if ( shotgunEnergyToKill == 0 )
|
||||
{
|
||||
// not handled here
|
||||
}
|
||||
else if ( shotgunEnergyToKill > 0 )
|
||||
{
|
||||
weapon_damage = maxhealth / shotgunEnergyToKill + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// immune
|
||||
weapon_damage = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rocketsToKill = (isdefined(bundle.ksRocketsToKill)?bundle.ksRocketsToKill:0);
|
||||
|
||||
if ( rocketsToKill == 0 )
|
||||
{
|
||||
// not handled here
|
||||
}
|
||||
else if ( rocketsToKill > 0 )
|
||||
{
|
||||
if ( weapon.rootweapon.name == "launcher_multi" )
|
||||
{
|
||||
rocketsToKill *= 2;
|
||||
}
|
||||
|
||||
weapon_damage = maxhealth / rocketsToKill + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// immune
|
||||
weapon_damage = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (( type == "MOD_GRENADE" || type == "MOD_GRENADE_SPLASH" ) && ( !isdefined( weapon.isEmpKillstreak ) || !weapon.isEmpKillstreak ) )
|
||||
{
|
||||
grenadeDamageMultiplier = (isdefined(bundle.ksGrenadeDamageMultiplier)?bundle.ksGrenadeDamageMultiplier:0);
|
||||
|
||||
if ( grenadeDamageMultiplier == 0 )
|
||||
{
|
||||
// not handled here
|
||||
}
|
||||
else if ( grenadeDamageMultiplier > 0 )
|
||||
{
|
||||
weapon_damage = damage * grenadeDamageMultiplier;
|
||||
}
|
||||
else
|
||||
{
|
||||
// immune
|
||||
weapon_damage = 0;
|
||||
}
|
||||
}
|
||||
else if ( type == "MOD_MELEE_WEAPON_BUTT" || type == "MOD_MELEE" )
|
||||
{
|
||||
ksMeleeDamageMultiplier = (isdefined(bundle.ksMeleeDamageMultiplier)?bundle.ksMeleeDamageMultiplier:0);
|
||||
|
||||
if ( ksMeleeDamageMultiplier == 0 )
|
||||
{
|
||||
// not handled here
|
||||
}
|
||||
else if ( ksMeleeDamageMultiplier > 0 )
|
||||
{
|
||||
weapon_damage = damage * ksMeleeDamageMultiplier;
|
||||
}
|
||||
else
|
||||
{
|
||||
// immune
|
||||
weapon_damage = 0;
|
||||
}
|
||||
}
|
||||
else if ( type == "MOD_PROJECTILE_SPLASH" )
|
||||
{
|
||||
ksProjectileSpashMultiplier = (isdefined(bundle.ksProjectileSpashMultiplier)?bundle.ksProjectileSpashMultiplier:0);
|
||||
|
||||
if ( ksProjectileSpashMultiplier == 0 )
|
||||
{
|
||||
// not handled here
|
||||
}
|
||||
else if ( ksProjectileSpashMultiplier > 0 )
|
||||
{
|
||||
weapon_damage = damage * ksProjectileSpashMultiplier;
|
||||
}
|
||||
else
|
||||
{
|
||||
// immune
|
||||
weapon_damage = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return weapon_damage;
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\array_shared;
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\duplicaterender_mgr;
|
||||
#using scripts\shared\filter_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
|
||||
#using scripts\shared\system_shared;
|
||||
|
||||
#namespace killstreak_detect;
|
||||
|
||||
function autoexec __init__sytem__() { system::register("killstreak_detect",&__init__,undefined,undefined); }
|
||||
|
||||
|
||||
function __init__()
|
||||
{
|
||||
callback::on_localplayer_spawned( &watch_killstreak_detect_perks_changed );
|
||||
|
||||
clientfield::register( "scriptmover", "enemyvehicle", 1, 2, "int", &enemyScriptMoverVehicle_changed, !true, !true );
|
||||
clientfield::register( "vehicle", "enemyvehicle", 1, 2, "int", &enemyvehicle_changed, !true, true );
|
||||
clientfield::register( "helicopter", "enemyvehicle", 1, 2, "int", &enemyvehicle_changed, !true, true );
|
||||
clientfield::register( "missile", "enemyvehicle", 1, 2, "int", &enemyMissileVehicle_changed, !true, true );
|
||||
clientfield::register( "actor", "enemyvehicle", 1, 2, "int", &enemyvehicle_changed, !true, true );
|
||||
|
||||
clientfield::register( "vehicle", "vehicletransition", 1, 1, "int", &vehicle_transition, !true, true );
|
||||
|
||||
if(!isdefined(level.enemyvehicles))level.enemyvehicles=[];
|
||||
if(!isdefined(level.enemymissiles))level.enemymissiles=[];
|
||||
|
||||
level.emp_killstreaks = [];
|
||||
}
|
||||
|
||||
function vehicle_transition( local_client_num, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
player = GetLocalPlayer( local_client_num );
|
||||
friend = self util::friend_not_foe( local_client_num, true );
|
||||
|
||||
if( friend && isdefined( player ) && player duplicate_render::show_friendly_outlines( local_client_num ) )
|
||||
{
|
||||
showOutlines = !(self IsLocalClientDriver( local_client_num ) );
|
||||
self duplicate_render::set_item_friendly_vehicle( local_client_num, showOutlines );
|
||||
}
|
||||
}
|
||||
|
||||
function should_set_compass_icon( local_client_num )
|
||||
{
|
||||
local_player = GetLocalPlayer( local_client_num );
|
||||
|
||||
return ( isdefined( local_player ) && isdefined( self.team ) && ( local_player.team === self.team || local_player HasPerk( local_client_num, "specialty_showenemyvehicles" ) ) );
|
||||
}
|
||||
|
||||
function enemyScriptMoverVehicle_changed( local_client_num, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( isdefined( level.scriptMoverCompassIcons ) && isdefined( self.model ) )
|
||||
{
|
||||
if ( isdefined( level.scriptMoverCompassIcons[self.model] ) )
|
||||
{
|
||||
if ( self should_set_compass_icon( local_client_num ) )
|
||||
{
|
||||
self setCompassIcon( level.scriptMoverCompassIcons[self.model] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enemyvehicle_changed( local_client_num, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump );
|
||||
}
|
||||
|
||||
function enemyMissileVehicle_changed( local_client_num, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( isdefined( level.missileCompassIcons ) && isdefined( self.weapon ) )
|
||||
{
|
||||
if ( isdefined( level.missileCompassIcons[self.weapon] ) )
|
||||
{
|
||||
if ( self should_set_compass_icon( local_client_num ) )
|
||||
{
|
||||
self setCompassIcon( level.missileCompassIcons[self.weapon] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enemymissile_changed( local_client_num, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump );
|
||||
}
|
||||
|
||||
function enemymissile_changed( local_client_num, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
self updateTeamMissiles( local_client_num, newVal );
|
||||
self util::add_remove_list( level.enemymissiles, newVal );
|
||||
self updateEnemyMissiles( local_client_num, newVal );
|
||||
}
|
||||
|
||||
function enemyvehicle_changed( local_client_num, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
self updateTeamVehicles( local_client_num, newVal );
|
||||
self util::add_remove_list( level.enemyvehicles, newVal );
|
||||
|
||||
self updateEnemyVehicles( local_client_num, newVal );
|
||||
|
||||
if ( isdefined( self.model ) && self.model == "wpn_t7_turret_emp_core" && self.type === "vehicle" )
|
||||
{
|
||||
if ( !isdefined( level.emp_killstreaks ) ) level.emp_killstreaks = []; else if ( !IsArray( level.emp_killstreaks ) ) level.emp_killstreaks = array( level.emp_killstreaks ); level.emp_killstreaks[level.emp_killstreaks.size]=self;;
|
||||
}
|
||||
}
|
||||
|
||||
function updateTeamVehicles( local_client_num, newVal )
|
||||
{
|
||||
self checkTeamVehicles( local_client_num );
|
||||
}
|
||||
|
||||
function updateTeamMissiles( local_client_num, newVal )
|
||||
{
|
||||
self checkTeamMissiles( local_client_num );
|
||||
}
|
||||
|
||||
function updateEnemyVehicles( local_client_num, newVal )
|
||||
{
|
||||
if ( !( isdefined( self ) ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
watcher = GetLocalPlayer( local_client_num );
|
||||
friend = self util::friend_not_foe( local_client_num, true );
|
||||
|
||||
self duplicate_render::set_dr_flag( "enemyvehicle_fb", !friend );
|
||||
|
||||
self duplicate_render::set_item_enemy_vehicle( local_client_num, false );
|
||||
self duplicate_render::set_item_friendly_vehicle( local_client_num, false );
|
||||
self.isEnemyVehicle = false;
|
||||
if ( !friend && IsDefined( watcher ) && watcher HasPerk( local_client_num, "specialty_showenemyvehicles" ) )
|
||||
{
|
||||
if ( !isdefined( self.isbreachingfirewall ) || self.isbreachingfirewall == false )
|
||||
{
|
||||
self duplicate_render::set_item_enemy_vehicle( local_client_num, newVal );
|
||||
}
|
||||
self.isEnemyVehicle = true;
|
||||
self duplicate_render::set_item_friendly_vehicle( local_client_num, false );
|
||||
}
|
||||
else if( ( friend === true ) && isDefined( watcher ) && watcher duplicate_render::show_friendly_outlines(local_client_num) )
|
||||
{
|
||||
driver = ( self.type === "vehicle" ) && self IsLocalClientDriver( local_client_num );
|
||||
showOutlines = ( driver === false ) && ( newVal === 1 || newVal === 2 );
|
||||
self duplicate_render::set_item_friendly_vehicle( local_client_num, showOutlines );
|
||||
}
|
||||
else
|
||||
{
|
||||
self duplicate_render::set_item_friendly_vehicle( local_client_num, false );
|
||||
}
|
||||
|
||||
if ( newVal == 2 )
|
||||
{
|
||||
//self duplicate_render::set_hacker_tool_hacked( local_client_num, true );
|
||||
self.killstreakIsHacked = true;
|
||||
}
|
||||
|
||||
self duplicate_render::update_dr_filters( local_client_num );
|
||||
}
|
||||
|
||||
function updateEnemyMissiles( local_client_num, newVal )
|
||||
{
|
||||
if ( !( isdefined( self ) ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
watcher = GetLocalPlayer( local_client_num );
|
||||
friend = self util::friend_not_foe( local_client_num, true );
|
||||
|
||||
self duplicate_render::set_dr_flag( "enemyvehicle_fb", !friend );
|
||||
|
||||
self duplicate_render::set_item_enemy_explosive( local_client_num, false );
|
||||
self duplicate_render::set_item_friendly_explosive( local_client_num, false );
|
||||
self.isEnemyVehicle = false;
|
||||
if ( !friend && IsDefined( watcher ) && watcher HasPerk( local_client_num, "specialty_showenemyvehicles" ) )
|
||||
{
|
||||
if ( !isdefined( self.isbreachingfirewall ) || self.isbreachingfirewall == false )
|
||||
{
|
||||
self duplicate_render::set_item_enemy_explosive( local_client_num, newVal );
|
||||
}
|
||||
self.isEnemyVehicle = true;
|
||||
self duplicate_render::set_item_friendly_explosive( local_client_num, false );
|
||||
}
|
||||
else if( ( friend === true ) && isDefined( watcher ) && watcher duplicate_render::show_friendly_outlines(local_client_num) )
|
||||
{
|
||||
showOutlines = ( newVal === 1 || newVal === 2 );
|
||||
self duplicate_render::set_item_friendly_explosive( local_client_num, showOutlines );
|
||||
}
|
||||
else
|
||||
{
|
||||
self duplicate_render::set_item_friendly_explosive( local_client_num, false );
|
||||
}
|
||||
|
||||
if ( newVal == 2 )
|
||||
{
|
||||
//self duplicate_render::set_hacker_tool_hacked( local_client_num, true );
|
||||
self.killstreakIsHacked = true;
|
||||
}
|
||||
|
||||
self duplicate_render::update_dr_filters( local_client_num );
|
||||
}
|
||||
|
||||
function watch_killstreak_detect_perks_changed(local_client_num)
|
||||
{
|
||||
if( self != GetLocalPlayer( local_client_num ) )
|
||||
return;
|
||||
|
||||
self notify( "watch_killstreak_detect_perks_changed" );
|
||||
self endon( "watch_killstreak_detect_perks_changed" );
|
||||
self endon( "death" );
|
||||
self endon( "disconnect" );
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
while(IsDefined(self))
|
||||
{
|
||||
{wait(.016);};
|
||||
util::clean_deleted(level.enemyvehicles);
|
||||
util::clean_deleted(level.enemymissiles);
|
||||
array::thread_all( level.enemyvehicles, &updateEnemyVehicles, local_client_num, 1 );
|
||||
array::thread_all( level.enemymissiles, &updateEnemyMissiles, local_client_num, 1 );
|
||||
self waittill("perks_changed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function checkTeamVehicles( localClientNum )
|
||||
{
|
||||
if ( !isdefined ( self.owner ) || !isdefined ( self.owner.team ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !isdefined( self.vehicleOldTeam ) )
|
||||
{
|
||||
self.vehicleOldTeam = self.team;
|
||||
}
|
||||
|
||||
if ( !isdefined( self.vehicleOldOwnerTeam ) )
|
||||
{
|
||||
self.vehicleOldOwnerTeam = self.owner.team;
|
||||
}
|
||||
|
||||
watcher = GetLocalPlayer( localClientNum );
|
||||
|
||||
if ( !isdefined( self.vehicleOldWatcherTeam ) )
|
||||
{
|
||||
self.vehicleOldWatcherTeam = watcher.team;
|
||||
}
|
||||
|
||||
if ( self.vehicleOldTeam != self.team || self.vehicleOldOwnerTeam != self.owner.team || self.vehicleOldWatcherTeam != watcher.team)
|
||||
{
|
||||
self.vehicleOldTeam = self.team;
|
||||
self.vehicleOldOwnerTeam = self.owner.team;
|
||||
self.vehicleOldWatcherTeam = watcher.team;
|
||||
|
||||
self notify( "team_changed" );
|
||||
}
|
||||
}
|
||||
|
||||
function checkTeamMissiles( localClientNum )
|
||||
{
|
||||
if ( !isdefined ( self.owner ) || !isdefined ( self.owner.team ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !isdefined( self.missileOldTeam ) )
|
||||
{
|
||||
self.missileOldTeam = self.team;
|
||||
}
|
||||
|
||||
if ( !isdefined( self.missileOldOwnerTeam ) )
|
||||
{
|
||||
self.missileOldOwnerTeam = self.owner.team;
|
||||
}
|
||||
|
||||
watcher = GetLocalPlayer( localClientNum );
|
||||
|
||||
if ( !isdefined( self.missileOldWatcherTeam ) )
|
||||
{
|
||||
self.missileOldWatcherTeam = watcher.team;
|
||||
}
|
||||
|
||||
if ( self.missileOldTeam != self.team || self.missileOldOwnerTeam != self.owner.team || self.missileOldWatcherTeam != watcher.team)
|
||||
{
|
||||
self.missileOldTeam = self.team;
|
||||
self.missileOldOwnerTeam = self.owner.team;
|
||||
self.missileOldWatcherTeam = watcher.team;
|
||||
|
||||
self notify( "team_changed" );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\weapons\_proximity_grenade;
|
||||
#using scripts\shared\util_shared;
|
||||
|
||||
#using scripts\mp\killstreaks\_killstreak_hacking;
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#namespace killstreak_detect;
|
||||
|
||||
function autoexec __init__sytem__() { system::register("killstreak_detect",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
clientfield::register( "vehicle", "enemyvehicle", 1, 2, "int" );
|
||||
clientfield::register( "scriptmover", "enemyvehicle", 1, 2, "int" );
|
||||
clientfield::register( "helicopter", "enemyvehicle", 1, 2, "int" );
|
||||
clientfield::register( "missile", "enemyvehicle", 1, 2, "int" );
|
||||
clientfield::register( "actor", "enemyvehicle", 1, 2, "int" );
|
||||
clientfield::register( "vehicle", "vehicletransition", 1, 1, "int" );
|
||||
}
|
||||
|
||||
|
||||
function killstreakTargetSet( killstreakEntity, offset )
|
||||
{
|
||||
if ( !isdefined( offset ) )
|
||||
{
|
||||
offset = ( 0, 0, 0 );
|
||||
}
|
||||
Target_Set( killstreakEntity, offset );
|
||||
/#
|
||||
killstreakEntity thread killstreak_hacking::killstreak_switch_team( killstreakEntity.owner );
|
||||
#/
|
||||
}
|
||||
|
||||
|
||||
function killstreakTargetClear( killstreakEntity )
|
||||
{
|
||||
Target_Remove( killstreakEntity );
|
||||
/#
|
||||
killstreakEntity thread killstreak_hacking::killstreak_switch_team_end();
|
||||
#/
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\popups_shared;
|
||||
#using scripts\shared\scoreevents_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_killstreak_bundles;
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#namespace killstreak_hacking;
|
||||
|
||||
function enable_hacking( killstreakName, preHackFunction, postHackFunction )
|
||||
{
|
||||
killstreak = self;
|
||||
|
||||
level.challenge_scorestreaksenabled = true;
|
||||
killstreak.challenge_isScoreStreak = true;
|
||||
killstreak.killstreak_hackedCallback = &_hacked_callback;
|
||||
killstreak.killstreakPreHackFunction = preHackFunction;
|
||||
killstreak.killstreakPostHackFunction = postHackFunction;
|
||||
killstreak.hackerToolInnerTimeMs = killstreak killstreak_bundles::get_hack_tool_inner_time();
|
||||
killstreak.hackerToolOuterTimeMs = killstreak killstreak_bundles::get_hack_tool_outer_time();
|
||||
killstreak.hackerToolInnerRadius = killstreak killstreak_bundles::get_hack_tool_inner_radius();
|
||||
killstreak.hackerToolOuterRadius = killstreak killstreak_bundles::get_hack_tool_outer_radius();
|
||||
killstreak.hackerToolRadius = killstreak.hackerToolOuterRadius;
|
||||
killstreak.killstreakHackLoopFX = killstreak killstreak_bundles::get_hack_loop_fx();
|
||||
killstreak.killstreakHackFX = killstreak killstreak_bundles::get_hack_fx();
|
||||
killstreak.killstreakHackScoreEvent = killstreak killstreak_bundles::get_hack_scoreevent();
|
||||
killstreak.killstreakHackLostLineOfSightLimitMs = killstreak killstreak_bundles::get_lost_line_of_sight_limit_msec();
|
||||
killstreak.killstreakHackLostLineOfSightTimeMs = killstreak killstreak_bundles::get_hack_tool_no_line_of_sight_time();
|
||||
|
||||
killstreak.killstreak_hackedProtection = killstreak killstreak_bundles::get_hack_protection();
|
||||
}
|
||||
|
||||
function disable_hacking()
|
||||
{
|
||||
killstreak = self;
|
||||
|
||||
killstreak.killstreak_hackedCallback = undefined;
|
||||
}
|
||||
|
||||
function hackerFX()
|
||||
{
|
||||
killstreak = self;
|
||||
|
||||
if ( isdefined( killstreak.killstreakHackFX ) && killstreak.killstreakHackFX != "" )
|
||||
{
|
||||
playfxontag( killstreak.killstreakHackFX, killstreak, "tag_origin" );
|
||||
}
|
||||
}
|
||||
|
||||
function hackerLoopFX()
|
||||
{
|
||||
killstreak = self;
|
||||
|
||||
if ( isdefined( killstreak.killstreakLoopHackFX ) && killstreak.killstreakLoopHackFX != "" )
|
||||
{
|
||||
playfxontag( killstreak.killstreakLoopHackFX, killstreak, "tag_origin" );
|
||||
}
|
||||
}
|
||||
|
||||
function private _hacked_callback( hacker )
|
||||
{
|
||||
killstreak = self;
|
||||
|
||||
originalOwner = killstreak.owner;
|
||||
|
||||
if ( isdefined( killstreak.killstreakHackScoreEvent ) )
|
||||
{
|
||||
scoreevents::processscoreevent( killstreak.killstreakHackScoreEvent, hacker, originalOwner, level.weaponHackerTool );
|
||||
}
|
||||
|
||||
if ( isdefined( killstreak.killstreakPreHackFunction ) )
|
||||
{
|
||||
killstreak thread [[killstreak.killstreakPreHackFunction]]( hacker );
|
||||
}
|
||||
|
||||
killstreak killstreaks::configure_team_internal( hacker, true );
|
||||
killstreak clientfield::set( "enemyvehicle", 2 );
|
||||
if ( isdefined ( killstreak.killstreakHackFX ) )
|
||||
{
|
||||
killstreak thread hackerFX();
|
||||
}
|
||||
if ( isdefined ( killstreak.killstreakHackLoopFX ) )
|
||||
{
|
||||
killstreak thread hackerLoopFX();
|
||||
}
|
||||
|
||||
if ( isdefined( killstreak.killstreakPostHackFunction ) )
|
||||
{
|
||||
killstreak thread [[killstreak.killstreakPostHackFunction]]( hacker );
|
||||
}
|
||||
|
||||
killstreakType = killstreak.killstreakType;
|
||||
if ( isdefined ( killstreak.hackedKillstreakRef ) )
|
||||
{
|
||||
killstreakType = killstreak.hackedKillstreakRef;
|
||||
}
|
||||
|
||||
level thread popups::DisplayKillstreakHackedTeamMessageToAll( killstreakType, hacker );
|
||||
|
||||
killstreak _update_health( hacker );
|
||||
}
|
||||
|
||||
function override_hacked_killstreak_reference( KillstreakRef )
|
||||
{
|
||||
killstreak = self;
|
||||
|
||||
killstreak.hackedKillstreakRef = KillstreakRef;
|
||||
}
|
||||
|
||||
function get_hacked_timeout_duration_ms()
|
||||
{
|
||||
killstreak = self;
|
||||
|
||||
timeout = killstreak killstreak_bundles::get_hack_timeout();
|
||||
|
||||
|
||||
if ( !isdefined( timeout ) || timeout <= 0 )
|
||||
{
|
||||
/#
|
||||
assertmsg( "get_hacked_timeout_duration_ms(): Set \"" + killstreak.killstreakType + "\" to a greater than zero value, in the killstreaks GDT" );
|
||||
#/
|
||||
return;
|
||||
}
|
||||
|
||||
return timeout * 1000;
|
||||
}
|
||||
|
||||
function set_vehicle_drivable_time_starting_now( killstreak, duration_ms = (-1) ) // self == player
|
||||
{
|
||||
if ( duration_ms == -1 )
|
||||
duration_ms = killstreak get_hacked_timeout_duration_ms();
|
||||
|
||||
return self vehicle::set_vehicle_drivable_time_starting_now( duration_ms );
|
||||
}
|
||||
|
||||
function _update_health( hacker )
|
||||
{
|
||||
killstreak = self;
|
||||
|
||||
if ( isdefined ( killstreak.hackedHealthUpdateCallback ) )
|
||||
{
|
||||
killstreak [[ killstreak.hackedHealthUpdateCallback ]]( hacker );
|
||||
}
|
||||
else if ( IsSentient( killstreak ) )
|
||||
{
|
||||
hackedHealth = killstreak_bundles::get_hacked_health( killstreak.killstreakType );
|
||||
assert( isdefined( hackedHealth ) );
|
||||
if ( self.health > hackedhealth )
|
||||
{
|
||||
self.health = hackedhealth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/#hacker iprintlnbold( "Hacked but no update of health occured" );#/
|
||||
}
|
||||
}
|
||||
|
||||
/#
|
||||
function killstreak_switch_team_end()
|
||||
{
|
||||
killstreakEntity = self;
|
||||
killstreakEntity notify( "killstreak_switch_team_end" );
|
||||
}
|
||||
|
||||
function killstreak_switch_team( owner )
|
||||
{
|
||||
killstreakEntity = self;
|
||||
killstreakEntity notify( "killstreak_switch_team_singleton" );
|
||||
killstreakEntity endon( "killstreak_switch_team_singleton" );
|
||||
killstreakEntity endon( "death" );
|
||||
|
||||
//Init my dvar
|
||||
SetDvar("scr_killstreak_switch_team", "");
|
||||
|
||||
while( true )
|
||||
{
|
||||
wait(0.5);
|
||||
|
||||
//Grab my dvar every .5 seconds in the form of an int
|
||||
devgui_int = GetDvarint( "scr_killstreak_switch_team");
|
||||
|
||||
//"" returns as zero with GetDvarInt
|
||||
if(devgui_int != 0)
|
||||
{
|
||||
// spawn a larry to be the opposing team
|
||||
team = "autoassign";
|
||||
|
||||
if( isdefined( level.getEnemyTeam ) && isdefined( owner ) && isdefined( owner.team ) )
|
||||
{
|
||||
team = [[level.getEnemyTeam]]( owner.team );
|
||||
}
|
||||
|
||||
if ( isdefined( level.devOnGetOrMakeBot ) )
|
||||
{
|
||||
player = [[level.devOnGetOrMakeBot]]( team );
|
||||
}
|
||||
|
||||
if( !isdefined( player ) )
|
||||
{
|
||||
println("Could not add test client");
|
||||
wait 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !isdefined( killstreakEntity.killstreak_hackedCallback ) )
|
||||
{
|
||||
/#
|
||||
iprintlnbold( "missing hacked callback" );
|
||||
#/
|
||||
return;
|
||||
}
|
||||
killstreakEntity notify( "killstreak_hacked", player );
|
||||
killstreakEntity.previouslyHacked = true;
|
||||
killstreakEntity [[ killstreakEntity.killstreak_hackedCallback ]]( player );
|
||||
|
||||
wait( 0.5 );
|
||||
SetDvar("scr_killstreak_switch_team", "0");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#/
|
||||
|
||||
@@ -0,0 +1,552 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\popups_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\weapons\_weapons;
|
||||
|
||||
Line truncated
|
||||
|
||||
#using scripts\mp\gametypes\_globallogic_utils;
|
||||
#using scripts\mp\gametypes\_loadout;
|
||||
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_supplydrop;
|
||||
|
||||
#precache( "material", "hud_ks_minigun" );
|
||||
#precache( "material", "hud_ks_m32" );
|
||||
#precache( "string", "KILLSTREAK_EARNED_MINIGUN" );
|
||||
#precache( "string", "KILLSTREAK_MINIGUN_NOT_AVAILABLE" );
|
||||
#precache( "string", "KILLSTREAK_MINIGUN_INBOUND" );
|
||||
#precache( "eventstring", "mpl_killstreak_minigun" );
|
||||
#precache( "eventstring", "mpl_killstreak_m32" );
|
||||
|
||||
#namespace killstreak_weapons;
|
||||
|
||||
function init()
|
||||
{
|
||||
killstreaks::register("minigun", "minigun", "killstreak_minigun", "minigun_used",&useCarriedKillstreakWeapon, false, true, "MINIGUN_USED" );
|
||||
killstreaks::register_strings("minigun", &"KILLSTREAK_EARNED_MINIGUN", &"KILLSTREAK_MINIGUN_NOT_AVAILABLE", &"KILLSTREAK_MINIGUN_INBOUND", undefined, &"KILLSTREAK_MINIGUN_HACKED" );
|
||||
killstreaks::register_dialog("minigun", "mpl_killstreak_minigun", "kls_death_used", "","kls_death_enemy", "", "kls_death_ready");
|
||||
|
||||
killstreaks::register("m32", "m32", "killstreak_m32", "m32_used",&useCarriedKillstreakWeapon, false, true, "M32_USED" );
|
||||
killstreaks::register_strings("m32", &"KILLSTREAK_EARNED_M32", &"KILLSTREAK_M32_NOT_AVAILABLE", &"KILLSTREAK_M32_INBOUND", undefined, &"KILLSTREAK_M32_HACKED" );
|
||||
killstreaks::register_dialog("m32", "mpl_killstreak_m32", "kls_mgl_used", "","kls_mgl_enemy", "", "kls_mgl_ready");
|
||||
killstreaks::override_entity_camera_in_demo("m32", true);
|
||||
|
||||
level.killStreakIcons["killstreak_minigun"] = "hud_ks_minigun";
|
||||
level.killStreakIcons["killstreak_m32"] = "hud_ks_m32";
|
||||
level.killStreakIcons["killstreak_m202_flash"] = "hud_ks_m202";
|
||||
level.killStreakIcons["killstreak_m220_tow_drop"] = "hud_ks_tv_guided_marker";
|
||||
level.killStreakIcons["killstreak_m220_tow"] = "hud_ks_tv_guided_missile";
|
||||
//level.killStreakIcons["killstreak_mp40"] = "hud_mp40";
|
||||
|
||||
callback::on_spawned( &on_player_spawned );
|
||||
|
||||
SetDvar( "scr_HeldKillstreak_Penalty", 0 );
|
||||
}
|
||||
|
||||
function on_player_spawned()
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
|
||||
self.firedKillstreakWeapon = false;
|
||||
self.usingKillstreakHeldWeapon = undefined;
|
||||
|
||||
if ( !util::isFirstRound() && !util::isOneRound() )
|
||||
{
|
||||
if ( level.roundStartKillstreakDelay > (globallogic_utils::getTimePassed() / 1000) )
|
||||
{
|
||||
self thread watchKillstreakWeaponDelay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function watchKillstreakWeaponDelay()
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
self endon( "death" );
|
||||
|
||||
while(1)
|
||||
{
|
||||
currentWeapon = self GetCurrentWeapon();
|
||||
self waittill( "weapon_change", newWeapon );
|
||||
|
||||
if ( level.roundStartKillstreakDelay < (globallogic_utils::getTimePassed() / 1000) )
|
||||
return;
|
||||
|
||||
if ( !killstreaks::is_killstreak_weapon(newWeapon) )
|
||||
{
|
||||
wait( 0.5 );
|
||||
continue;
|
||||
}
|
||||
|
||||
killstreak = killstreaks::get_killstreak_for_weapon( newWeapon );
|
||||
if ( killstreaks::is_delayable_killstreak( killstreak ) && newWeapon.isCarriedKillstreak )
|
||||
{
|
||||
timeLeft = Int( level.roundStartKillstreakDelay - (globallogic_utils::getTimePassed() / 1000) );
|
||||
|
||||
if( !timeLeft )
|
||||
timeLeft = 1;
|
||||
|
||||
self iPrintLnBold( &"MP_UNAVAILABLE_FOR_N", " " + timeLeft + " ", &"EXE_SECONDS" );
|
||||
|
||||
self switchToWeapon( currentWeapon );
|
||||
wait(0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function useKillstreakWeaponDrop( hardpointType )
|
||||
{
|
||||
if( self supplydrop::isSupplyDropGrenadeAllowed(hardpointType) == false )
|
||||
return false;
|
||||
|
||||
result = self supplydrop::useSupplyDropMarker();
|
||||
|
||||
self notify( "supply_drop_marker_done" );
|
||||
|
||||
if ( !isdefined(result) || !result )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function useCarriedKillstreakWeapon( hardpointType )
|
||||
{
|
||||
if( !isdefined(hardpointType) )
|
||||
return false;
|
||||
|
||||
if ( self killstreakrules::isKillstreakAllowed( hardpointType, self.team ) == false )
|
||||
{
|
||||
self switchToWeapon( self.lastDroppableWeapon );
|
||||
return false;
|
||||
}
|
||||
|
||||
currentWeapon = self GetCurrentWeapon();
|
||||
killstreakWeapon = killstreaks::get_killstreak_weapon( hardpointType );
|
||||
|
||||
if ( killstreakWeapon == level.weaponNone )
|
||||
return false;
|
||||
|
||||
level weapons::add_limited_weapon( killstreakWeapon, self, 3 );
|
||||
|
||||
if ( issubstr( killstreakWeapon.name, "inventory" ) )
|
||||
isFromInventory = true;
|
||||
else
|
||||
isFromInventory = false;
|
||||
|
||||
currentAmmo = self getammocount( killstreakWeapon );
|
||||
if ( ( ( hardpointType == "minigun" || hardpointType == "inventory_minigun" ) && !( isdefined( self.minigunStart ) && self.minigunStart ) ) ||
|
||||
( ( hardpointType == "m32" || hardpointType == "inventory_m32" ) && !( isdefined( self.m32Start ) && self.m32Start ) ) )
|
||||
{
|
||||
if ( hardpointType == "minigun" || hardpointType == "inventory_minigun" )
|
||||
{
|
||||
self.minigunStart = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.m32Start = true;
|
||||
}
|
||||
self killstreaks::play_killstreak_start_dialog( hardpointType, self.team, true );
|
||||
self AddWeaponStat( killstreakWeapon, "used", 1 );
|
||||
level thread popups::DisplayTeamMessageToAll( level.killstreaks[hardpointType].inboundText, self );
|
||||
|
||||
self.pers["held_killstreak_clip_count"][killstreakWeapon] = ( killstreakWeapon.clipSize > currentAmmo ? currentAmmo : killstreakWeapon.clipSize );
|
||||
|
||||
|
||||
if ( isFromInventory == false )
|
||||
{
|
||||
if( self.pers["killstreak_quantity"][killstreakWeapon] > 0 )
|
||||
ammoPool = killstreakWeapon.maxAmmo;
|
||||
else
|
||||
ammoPool = self.pers["held_killstreak_ammo_count"][killstreakWeapon];
|
||||
|
||||
self setWeaponAmmoClip( killstreakWeapon, self.pers["held_killstreak_clip_count"][killstreakWeapon] );
|
||||
self setWeaponAmmoStock( killstreakWeapon, ammoPool - self.pers["held_killstreak_clip_count"][killstreakWeapon] );
|
||||
}
|
||||
}
|
||||
if ( hardpointType == "minigun" || hardpointType == "inventory_minigun" )
|
||||
{
|
||||
if ( !( isdefined( self.minigunActive ) && self.minigunActive ) )
|
||||
{
|
||||
killstreak_id = self killstreakrules::killstreakStart( hardpointType, self.team, false, false );
|
||||
|
||||
if( hardpointType == "inventory_minigun" )
|
||||
killstreak_id = self.pers["killstreak_unique_id"][self.pers["killstreak_unique_id"].size-1];
|
||||
|
||||
self.minigunId = killstreak_id;
|
||||
self.minigunActive = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
killstreak_id = self.minigunId;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !( isdefined( self.m32Active ) && self.m32Active ) )
|
||||
{
|
||||
killstreak_id = self killstreakrules::killstreakStart( hardpointType, self.team, false, false );
|
||||
|
||||
if( hardpointType == "inventory_m32" )
|
||||
killstreak_id = self.pers["killstreak_unique_id"][self.pers["killstreak_unique_id"].size-1];
|
||||
|
||||
self.m32Id = killstreak_id;
|
||||
self.m32Active = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
killstreak_id = self.m32Id;
|
||||
}
|
||||
}
|
||||
//right now we dont have handling for the killstreak not working
|
||||
assert ( killstreak_id != -1 );
|
||||
self.firedKillstreakWeapon = false;
|
||||
//This will make it so the player cannot pick up weapons while using this weapon for the first time.
|
||||
self setBlockWeaponPickup( killstreakWeapon, true );
|
||||
|
||||
if( isFromInventory )
|
||||
{
|
||||
self setWeaponAmmoClip( killstreakWeapon, self.pers["held_killstreak_clip_count"][killstreakWeapon] );
|
||||
self setWeaponAmmoStock( killstreakWeapon, self.pers["killstreak_ammo_count"][self.pers["killstreak_ammo_count"].size - 1] - self.pers["held_killstreak_clip_count"][killstreakWeapon] );
|
||||
}
|
||||
|
||||
notifyString = "killstreakWeapon_" + killstreakWeapon.name;
|
||||
self notify( notifyString );
|
||||
//Monitor weapon switching from the killstreak weapon
|
||||
self thread watchKillstreakWeaponSwitch( killstreakWeapon, killstreak_id, isFromInventory );
|
||||
self thread watchKillstreakWeaponDeath( killstreakWeapon, killstreak_id, isFromInventory );
|
||||
self thread watchKillstreakRoundChange( isFromInventory, killstreak_id );
|
||||
self thread WatchPlayerDeath( killstreakWeapon );
|
||||
|
||||
if( isFromInventory )
|
||||
self thread watchKillstreakRemoval( hardpointType, killstreak_id );
|
||||
|
||||
self.usingKillstreakHeldWeapon = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function useKillstreakWeaponFromCrate( hardpointType )
|
||||
{
|
||||
if( !isdefined(hardpointType) )
|
||||
return false;
|
||||
|
||||
killstreakWeapon = killstreaks::get_killstreak_weapon( hardpointType );
|
||||
if ( killstreakWeapon == level.weaponNone )
|
||||
return false;
|
||||
|
||||
self.firedKillstreakWeapon = false;
|
||||
|
||||
self setBlockWeaponPickup( killstreakWeapon, true );
|
||||
|
||||
killstreak_id = self killstreakrules::killstreakStart( hardpointType, self.team, false, false );
|
||||
//right now we dont have handling for the killstreak not working
|
||||
assert ( killstreak_id != -1 );
|
||||
|
||||
if( issubstr( killstreakWeapon.name, "inventory" ) )
|
||||
isFromInventory = true;
|
||||
else
|
||||
isFromInventory = false;
|
||||
|
||||
self thread watchKillstreakWeaponSwitch( killstreakWeapon, killstreak_id, isFromInventory );
|
||||
self thread watchKillstreakWeaponDeath( killstreakWeapon, killstreak_id, isFromInventory );
|
||||
|
||||
if( isFromInventory )
|
||||
self thread watchKillstreakRemoval( hardpointType, killstreak_id );
|
||||
|
||||
self.usingKillstreakHeldWeapon = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function watchKillstreakWeaponSwitch( killstreakWeapon, killstreak_id, isFromInventory )
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
self endon( "death" );
|
||||
noneWeapon = getWeapon( "none" );
|
||||
minigunWeapon = getWeapon( "minigun" );
|
||||
minigunInventoryWeapon = getWeapon( "inventory_minigun" );
|
||||
//self endon( "killstreak_weapon_taken" );
|
||||
|
||||
while(1)
|
||||
{
|
||||
currentWeapon = self GetCurrentWeapon();
|
||||
self waittill( "weapon_change", newWeapon );
|
||||
|
||||
if ( level.inFinalKillcam )
|
||||
continue;
|
||||
|
||||
if( newWeapon == noneWeapon )
|
||||
continue;
|
||||
|
||||
currentAmmo = self getammocount( killstreakWeapon );
|
||||
currentAmmoInClip = self GetWeaponAmmoClip( killstreakWeapon );
|
||||
|
||||
//If an inventory weapon, make sure the ammo is stored at the right index in the stack
|
||||
if( isFromInventory && currentAmmo > 0 )
|
||||
{
|
||||
killstreakIndex = self killstreaks::get_killstreak_index_by_id( killstreak_id );
|
||||
|
||||
if( isdefined( killstreakIndex ) )
|
||||
{
|
||||
self.pers["killstreak_ammo_count"][killstreakIndex] = currentAmmo;
|
||||
self.pers["held_killstreak_clip_count"][killstreakWeapon] = currentAmmoInClip;
|
||||
}
|
||||
}
|
||||
|
||||
if( killstreaks::is_killstreak_weapon( newWeapon ) && !newWeapon.isCarriedKillstreak )
|
||||
continue;
|
||||
|
||||
if( newWeapon.isGameplayWeapon )
|
||||
continue;
|
||||
|
||||
if( newWeapon == self.lastNonKillstreakWeapon && newWeapon.isCarriedKillstreak )
|
||||
continue;
|
||||
|
||||
KillstreakId = killstreaks::get_top_killstreak_unique_id();
|
||||
|
||||
self.pers["held_killstreak_ammo_count"][killstreakWeapon] = currentAmmo;
|
||||
self.pers["held_killstreak_clip_count"][killstreakWeapon] = currentAmmoInClip;
|
||||
|
||||
if ( killstreak_id != -1 )
|
||||
{
|
||||
self notify( "killstreak_weapon_switch" );
|
||||
}
|
||||
self.firedKillstreakWeapon = false;
|
||||
self.usingKillstreakHeldWeapon = undefined;
|
||||
|
||||
waittillframeend;
|
||||
|
||||
if ( currentAmmo == 0 || self.pers["killstreak_quantity"][killstreakWeapon] > 0 || ( isFromInventory && isdefined(KillstreakId) && KillstreakId != killstreak_id ) )
|
||||
{
|
||||
killstreakrules::killstreakStop( killstreaks::get_killstreak_for_weapon( killstreakWeapon ), self.team, killstreak_id );
|
||||
if ( killstreakWeapon == minigunInventoryWeapon || killstreakWeapon == minigunWeapon )
|
||||
{
|
||||
self.minigunStart = false;
|
||||
self.minigunActive = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.m32Start = false;
|
||||
self.m32Active = false;
|
||||
}
|
||||
|
||||
//Check if we have earned another one, if so refill ammo.
|
||||
if( self.pers["killstreak_quantity"][killstreakWeapon] > 0 )
|
||||
{
|
||||
self.pers["held_killstreak_ammo_count"][killstreakWeapon] = killstreakWeapon.maxAmmo;
|
||||
self loadout::setWeaponAmmoOverall( killstreakWeapon, self.pers["held_killstreak_ammo_count"][killstreakWeapon] );
|
||||
self.pers["killstreak_quantity"][killstreakWeapon]--;
|
||||
}
|
||||
}
|
||||
|
||||
if( isFromInventory && currentAmmo == 0 )
|
||||
{
|
||||
self TakeWeapon( killstreakWeapon );
|
||||
self killstreaks::remove_used_killstreak( killstreaks::get_killstreak_for_weapon( killstreakWeapon ), killstreak_id );
|
||||
self killstreaks::activate_next();
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function watchKillstreakWeaponDeath( killstreakWeapon, killstreak_id, isFromInventory )
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
self endon( "killstreak_weapon_switch" );
|
||||
|
||||
if( killstreak_id == -1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
oldTeam = self.team;
|
||||
|
||||
self waittill( "death" );
|
||||
|
||||
penalty = GetDvarFloat( "scr_HeldKillstreak_Penalty", 0.5 );
|
||||
maxAmmo = killstreakWeapon.maxAmmo;
|
||||
currentAmmo = self getammocount( killstreakWeapon );
|
||||
currentAmmoInClip = self GetWeaponAmmoClip( killstreakWeapon );
|
||||
|
||||
if ( self.pers["killstreak_quantity"].size == 0 ) // player changed teams
|
||||
{
|
||||
currentAmmo = 0;
|
||||
currentAmmoInClip = 0;
|
||||
}
|
||||
|
||||
maxClipSize = killstreakWeapon.clipSize;
|
||||
newAmmo = int( currentAmmo - (maxAmmo * penalty) );
|
||||
KillstreakId = killstreaks::get_top_killstreak_unique_id();
|
||||
|
||||
|
||||
//Check if we should penalize the player.
|
||||
if( self.lastNonKillstreakWeapon == killstreakWeapon )
|
||||
{
|
||||
if( newAmmo < 0 )
|
||||
{
|
||||
self.pers["held_killstreak_ammo_count"][killstreakWeapon] = 0;
|
||||
self.pers["held_killstreak_clip_count"][killstreakWeapon] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.pers["held_killstreak_ammo_count"][killstreakWeapon] = newAmmo;
|
||||
self.pers["held_killstreak_clip_count"][killstreakWeapon] = ( maxClipSize <= newAmmo ? maxClipSize : newAmmo );
|
||||
}
|
||||
}
|
||||
|
||||
self.usingKillstreakHeldWeapon = false;
|
||||
killstreakType = killstreaks::get_killstreak_for_weapon( killstreakWeapon );
|
||||
if ( newAmmo <= 0 || self.pers["killstreak_quantity"][killstreakWeapon] > 0 || ( isFromInventory && isdefined(KillstreakId) && KillstreakId != killstreak_id ) )
|
||||
{
|
||||
killstreakrules::killstreakStop( killstreakType, oldTeam, killstreak_id );
|
||||
if ( killstreakType == "minigun" || killstreakType == "inventory_minigun" )
|
||||
{
|
||||
self.minigunStart = false;
|
||||
self.minigunActive = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.m32Start = false;
|
||||
self.m32Active = false;
|
||||
}
|
||||
//Check if we have earned another one, if so refill ammo.
|
||||
if( isdefined( self.pers["killstreak_quantity"][killstreakWeapon] ) && self.pers["killstreak_quantity"][killstreakWeapon] > 0 )
|
||||
{
|
||||
self.pers["held_killstreak_ammo_count"][killstreakWeapon] = maxAmmo;
|
||||
self.pers["held_killstreak_clip_count"][killstreakWeapon] = maxClipSize;
|
||||
self setWeaponAmmoClip( killstreakWeapon, self.pers["held_killstreak_clip_count"][killstreakWeapon] );
|
||||
self setWeaponAmmoStock( killstreakWeapon, self.pers["held_killstreak_ammo_count"][killstreakWeapon] - self.pers["held_killstreak_clip_count"][killstreakWeapon] );
|
||||
self.pers["killstreak_quantity"][killstreakWeapon]--;
|
||||
}
|
||||
}
|
||||
if( isFromInventory && newAmmo <= 0 )
|
||||
{
|
||||
self TakeWeapon( killstreakWeapon );
|
||||
self killstreaks::remove_used_killstreak( killstreakType, killstreak_id );
|
||||
self killstreaks::activate_next();
|
||||
}
|
||||
else if( isFromInventory )//If an inventory weapon, make sure the ammo is stored at the right index in the stack
|
||||
{
|
||||
killstreakIndex = self killstreaks::get_killstreak_index_by_id( killstreak_id );
|
||||
|
||||
if( isdefined( killstreakIndex ) )
|
||||
{
|
||||
self.pers["killstreak_ammo_count"][killstreakIndex] = self.pers["held_killstreak_ammo_count"][killstreakWeapon];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function WatchPlayerDeath( killstreakWeapon )
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
|
||||
endonWeaponString = "killstreakWeapon_" + killstreakWeapon.name;
|
||||
self endon( endonWeaponString );
|
||||
|
||||
self waittill( "death" );
|
||||
|
||||
currentAmmo = self getammocount( killstreakWeapon );
|
||||
|
||||
self.pers["held_killstreak_clip_count"][killstreakWeapon] = ( killstreakWeapon.clipSize <= currentAmmo ? killstreakWeapon.clipSize : currentAmmo );
|
||||
}
|
||||
|
||||
function watchKillstreakRemoval( killstreakType, killstreak_id )
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
self endon( "death" );
|
||||
self endon( "killstreak_weapon_switch" );
|
||||
|
||||
self waittill( "oldest_killstreak_removed", removedKillstreakType, removed_id );
|
||||
|
||||
if ( killstreakType == removedKillstreakType && killstreak_id == removed_id )
|
||||
{
|
||||
removedKillstreakWeapon = killstreaks::get_killstreak_weapon( removedKillstreakType );
|
||||
if ( removedKillstreakWeapon.name == "inventory_minigun" )
|
||||
{
|
||||
self.minigunStart = false;
|
||||
self.minigunActive = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.m32Start = false;
|
||||
self.m32Active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function watchKillstreakRoundChange( isFromInventory, killstreak_id )
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
self endon( "death" );
|
||||
self endon( "killstreak_weapon_switch" );
|
||||
|
||||
self waittill( "round_ended" );
|
||||
|
||||
currentWeapon = self getCurrentWeapon();
|
||||
|
||||
if( !currentWeapon.isCarriedKillstreak )
|
||||
return;
|
||||
|
||||
currentAmmo = self getammocount( currentWeapon );
|
||||
maxClipSize = currentWeapon.clipSize;
|
||||
|
||||
//If an inventory weapon, make sure the ammo is stored at the right index in the stack
|
||||
if( isFromInventory && currentAmmo > 0 )
|
||||
{
|
||||
killstreakIndex = self killstreaks::get_killstreak_index_by_id( killstreak_id );
|
||||
|
||||
if( isDefined( killstreakIndex ) )
|
||||
{
|
||||
self.pers["killstreak_ammo_count"][killstreakIndex] = currentAmmo;
|
||||
self.pers["held_killstreak_clip_count"][currentWeapon] = ( maxClipSize <= currentAmmo ? maxClipSize : currentAmmo );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.pers["held_killstreak_ammo_count"][currentWeapon] = currentAmmo;
|
||||
self.pers["held_killstreak_clip_count"][currentWeapon] = ( maxClipSize <= currentAmmo ? maxClipSize : currentAmmo );
|
||||
}
|
||||
}
|
||||
|
||||
function checkIfSwitchableWeapon( currentWeapon, newWeapon, killstreakWeapon, currentKillstreakId )
|
||||
{
|
||||
switchableWeapon = true;
|
||||
topKillstreak = killstreaks::get_top_killstreak();
|
||||
killstreakId = killstreaks::get_top_killstreak_unique_id();
|
||||
|
||||
if( !isdefined(killstreakId) )
|
||||
killstreakId = -1;
|
||||
|
||||
if ( self HasWeapon( killstreakWeapon ) && !self GetAmmoCount( killstreakWeapon ) )//Safety check that we're holding an empty killstreak weapon
|
||||
switchableWeapon = true;
|
||||
else if( self.firedKillstreakWeapon && newWeapon == killstreakWeapon && currentWeapon.isCarriedKillstreak )//We have a new version of the killstreak weapon and we've already shot the equipped one
|
||||
switchableWeapon = true;
|
||||
else if( newWeapon.isEquipment )
|
||||
switchableWeapon = true;
|
||||
else if( isdefined( level.grenade_array[newWeapon] ) )
|
||||
switchableWeapon = false;
|
||||
else if( newWeapon.isCarriedKillstreak && currentWeapon.isCarriedKillstreak && (!isdefined(currentKillstreakID) || currentKillstreakId != killstreakId) )//new held killstreak weapon
|
||||
switchableWeapon = true;
|
||||
else if( killstreaks::is_killstreak_weapon( newWeapon ) )//allow killstreaks to be called in
|
||||
switchableWeapon = false;
|
||||
else if( newWeapon.isGameplayWeapon )//check for briefcase bomb, syrette, etc.
|
||||
switchableWeapon = false;
|
||||
else if( self.firedKillstreakWeapon )
|
||||
switchableWeapon = true;
|
||||
else if( self.lastNonKillstreakWeapon == killstreakWeapon )
|
||||
switchableWeapon = false;
|
||||
else if( isdefined(topKillstreak) && topKillstreak == killstreakWeapon && currentKillstreakId == killstreakId )//putting the killstreak away
|
||||
switchableWeapon = false;
|
||||
|
||||
|
||||
return switchableWeapon;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\popups_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_emp;
|
||||
#using scripts\mp\gametypes\_globallogic_audio;
|
||||
|
||||
#namespace killstreakrules;
|
||||
|
||||
function init()
|
||||
{
|
||||
level.killstreakrules = [];
|
||||
level.killstreaktype = [];
|
||||
level.killstreaks_triggered = [];
|
||||
level.matchRecorderKillstreakKills = [];
|
||||
|
||||
if( !isdefined( level.globalKillstreaksCalled ) )
|
||||
{
|
||||
level.globalKillstreaksCalled = 0;
|
||||
}
|
||||
|
||||
// Rule name, max count per team count
|
||||
createRule( "ai_tank", 4, 2);
|
||||
createRule( "airsupport", 1, 1);
|
||||
createRule( "combatrobot", 4, 2);
|
||||
createRule( "chopper", 2, 1);
|
||||
createRule( "chopperInTheAir", 2, 1);
|
||||
createRule( "counteruav", 6, 3);
|
||||
createRule( "dart", 4, 2);
|
||||
createRule( "dogs", 1, 1);
|
||||
createRule( "drone_strike", 1, 1);
|
||||
createRule( "emp", 2, 1);
|
||||
createRule( "firesupport", 1, 1);
|
||||
createRule( "missiledrone", 3, 3);
|
||||
createRule( "missileswarm", 1, 1);
|
||||
createRule( "planemortar", 1, 1);
|
||||
createRule( "playercontrolledchopper", 1, 1);
|
||||
createRule( "qrdrone", 3, 2);
|
||||
createRule( "uav", 10, 5);
|
||||
createRule( "raps" , 2, 1);
|
||||
createRule( "rcxd", 4, 2);
|
||||
createRule( "remote_missile", 2, 1);
|
||||
createRule( "remotemortar", 1, 1);
|
||||
createRule( "satellite", 2, 1);
|
||||
createRule( "sentinel", 4, 2);
|
||||
createRule( "straferun", 1, 1);
|
||||
createRule( "supplydrop", 4, 4);
|
||||
createRule( "targetableent", 32, 32);
|
||||
createRule( "turret", 8, 4);
|
||||
createRule( "vehicle", 7, 7);
|
||||
createRule( "weapon", 12, 6);
|
||||
|
||||
// KILLSTREAK Rule Name adds checks
|
||||
addKillstreakToRule( "ai_tank_drop", "ai_tank", true, true );
|
||||
addKillstreakToRule( "airstrike", "airsupport", true, true );
|
||||
addKillstreakToRule( "airstrike", "vehicle", true, true );
|
||||
addKillstreakToRule( "artillery", "firesupport", true, true );
|
||||
addKillstreakToRule( "auto_tow", "turret", true, true );
|
||||
addKillstreakToRule( "autoturret", "turret", true, true );
|
||||
addKillstreakToRule( "combat_robot", "combatrobot", true, true );
|
||||
addKillstreakToRule( "counteruav", "counteruav", true, true );
|
||||
addKillstreakToRule( "counteruav", "targetableent", true, true );
|
||||
addKillstreakToRule( "dart", "dart", true, true );
|
||||
addKillstreakToRule( "dogs", "dogs", true, true );
|
||||
addKillstreakToRule( "dogs_lvl2", "dogs", true, true );
|
||||
addKillstreakToRule( "dogs_lvl3", "dogs", true, true );
|
||||
addKillstreakToRule( "drone_strike", "drone_strike", true, true );
|
||||
addKillstreakToRule( "emp", "emp", true, true );
|
||||
addKillstreakToRule( "helicopter", "chopper", true, true );
|
||||
addKillstreakToRule( "helicopter", "chopperInTheAir", true, false );
|
||||
addKillstreakToRule( "helicopter", "playercontrolledchopper", false, true );
|
||||
addKillstreakToRule( "helicopter", "targetableent", true, true );
|
||||
addKillstreakToRule( "helicopter", "vehicle", true, true );
|
||||
|
||||
addKillstreakToRule( "helicopter_comlink", "chopper", true, true );
|
||||
addKillstreakToRule( "helicopter_comlink", "chopperInTheAir", true, false );
|
||||
addKillstreakToRule( "helicopter_comlink", "targetableent", true, true );
|
||||
addKillstreakToRule( "helicopter_comlink", "vehicle", true, true );
|
||||
|
||||
addKillstreakToRule( "helicopter_guard", "airsupport", true, true );
|
||||
|
||||
addKillstreakToRule( "helicopter_gunner", "chopperInTheAir", true, false );
|
||||
addKillstreakToRule( "helicopter_gunner", "playercontrolledchopper", true, true );
|
||||
addKillstreakToRule( "helicopter_gunner", "targetableent", true, true );
|
||||
addKillstreakToRule( "helicopter_gunner", "vehicle", true, true );
|
||||
|
||||
addKillstreakToRule( "helicopter_gunner_assistant", "chopperInTheAir", true, false );
|
||||
addKillstreakToRule( "helicopter_gunner_assistant", "playercontrolledchopper", true, true );
|
||||
addKillstreakToRule( "helicopter_gunner_assistant", "targetableent", true, true );
|
||||
addKillstreakToRule( "helicopter_gunner_assistant", "vehicle", true, true );
|
||||
|
||||
addKillstreakToRule( "helicopter_player_firstperson", "vehicle", true, true );
|
||||
addKillstreakToRule( "helicopter_player_firstperson", "chopperInTheAir", true, true );
|
||||
addKillstreakToRule( "helicopter_player_firstperson", "playercontrolledchopper", true, true );
|
||||
addKillstreakToRule( "helicopter_player_firstperson", "targetableent", true, true );
|
||||
addKillstreakToRule( "helicopter_player_gunner", "chopperInTheAir", true, true );
|
||||
addKillstreakToRule( "helicopter_player_gunner", "playercontrolledchopper", true, true );
|
||||
addKillstreakToRule( "helicopter_player_gunner", "targetableent", true, true );
|
||||
addKillstreakToRule( "helicopter_player_gunner", "vehicle", true, true );
|
||||
addKillstreakToRule( "helicopter_x2", "chopper", true, true );
|
||||
addKillstreakToRule( "helicopter_x2", "chopperInTheAir", true, false );
|
||||
addKillstreakToRule( "helicopter_x2", "playercontrolledchopper", false, true );
|
||||
addKillstreakToRule( "helicopter_x2", "targetableent", true, true );
|
||||
addKillstreakToRule( "helicopter_x2", "vehicle", true, true );
|
||||
addKillstreakToRule( "m202_flash", "weapon", true, true );
|
||||
addKillstreakToRule( "m220_tow", "weapon", true, true );
|
||||
addKillstreakToRule( "m220_tow_drop", "supplydrop", true, true );
|
||||
addKillstreakToRule( "m220_tow_drop", "vehicle", true, true );
|
||||
addKillstreakToRule( "m220_tow_killstreak", "weapon", true, true );
|
||||
addKillstreakToRule( "m32", "weapon", true, true );
|
||||
addKillstreakToRule( "m32_drop", "weapon", true, true );
|
||||
addKillstreakToRule( "microwave_turret", "turret", true, true );
|
||||
addKillstreakToRule( "minigun", "weapon", true, true );
|
||||
addKillstreakToRule( "minigun_drop", "weapon", true, true );
|
||||
addKillstreakToRule( "missile_drone", "missiledrone", true, true );
|
||||
addKillstreakToRule( "missile_swarm", "missileswarm", true, true );
|
||||
addKillstreakToRule( "mortar", "firesupport", true, true );
|
||||
addKillstreakToRule( "mp40_drop", "weapon", true, true );
|
||||
addKillstreakToRule( "napalm", "airsupport", true, true );
|
||||
addKillstreakToRule( "napalm", "vehicle", true, true );
|
||||
addKillstreakToRule( "planemortar", "planemortar", true, true );
|
||||
addKillstreakToRule( "qrdrone", "qrdrone", true, true );
|
||||
addKillstreakToRule( "qrdrone", "vehicle", true, true );
|
||||
addKillstreakToRule( "uav", "uav", true, true );
|
||||
addKillstreakToRule( "uav", "targetableent", true, true );
|
||||
addKillstreakToRule( "satellite", "satellite", true, true );
|
||||
addKillstreakToRule( "raps", "raps", true, true );
|
||||
addKillstreakToRule( "rcbomb", "rcxd", true, true );
|
||||
addKillstreakToRule( "remote_missile", "targetableent", true, true );
|
||||
addKillstreakToRule( "remote_missile", "remote_missile", true, true );
|
||||
addKillstreakToRule( "remote_mortar", "remotemortar", true, true );
|
||||
addKillstreakToRule( "remote_mortar", "targetableent", true, true );
|
||||
addKillstreakToRule( "sentinel", "sentinel", true, true );
|
||||
addKillstreakToRule( "straferun", "straferun", true, true );
|
||||
addKillstreakToRule( "supply_drop", "supplydrop", true, true );
|
||||
addKillstreakToRule( "supply_drop", "targetableent", true, true );
|
||||
addKillstreakToRule( "supply_drop", "vehicle", true, true );
|
||||
addKillstreakToRule( "supply_station", "supplydrop", true, true );
|
||||
addKillstreakToRule( "supply_station", "targetableent", true, true );
|
||||
addKillstreakToRule( "supply_station", "vehicle", true, true );
|
||||
addKillstreakToRule( "tow_turret_drop", "supplydrop", true, true );
|
||||
addKillstreakToRule( "tow_turret_drop", "vehicle", true, true );
|
||||
addKillstreakToRule( "turret_drop", "supplydrop", true, true );
|
||||
addKillstreakToRule( "turret_drop", "vehicle", true, true );
|
||||
}
|
||||
|
||||
function createRule( rule, maxAllowable, maxAllowablePerTeam )
|
||||
{
|
||||
level.killstreakrules[rule] = spawnstruct();
|
||||
level.killstreakrules[rule].cur = 0;
|
||||
level.killstreakrules[rule].curTeam = [];
|
||||
level.killstreakrules[rule].max = maxAllowable;
|
||||
level.killstreakrules[rule].maxPerTeam = maxAllowablePerTeam;
|
||||
}
|
||||
|
||||
function addKillstreakToRule( killstreak, rule, countTowards, checkAgainst, inventoryVariant )
|
||||
{
|
||||
if ( !isdefined (level.killstreaktype[killstreak] ) )
|
||||
level.killstreaktype[killstreak] = [];
|
||||
|
||||
keys = GetArrayKeys( level.killstreaktype[killstreak] );
|
||||
|
||||
// you need to add a rule before adding it to a killstreak
|
||||
assert( isdefined(level.killstreakrules[rule] ) );
|
||||
|
||||
if ( !isdefined( level.killstreaktype[killstreak][rule] ) )
|
||||
level.killstreaktype[killstreak][rule] = spawnstruct();
|
||||
|
||||
level.killstreaktype[killstreak][rule].counts = countTowards;
|
||||
|
||||
level.killstreaktype[killstreak][rule].checks = checkAgainst;
|
||||
|
||||
if( !( isdefined( inventoryVariant ) && inventoryVariant ) )
|
||||
addKillstreakToRule( "inventory_" + killstreak, rule, countTowards, checkAgainst, true );
|
||||
}
|
||||
|
||||
// returns killstreakid or if killstreak is not allowed
|
||||
function killstreakStart( hardpointType, team, hacked, displayTeamMessage )
|
||||
{
|
||||
/#
|
||||
assert( isdefined( team ), "team needs to be defined" );
|
||||
#/
|
||||
|
||||
if ( self isKillstreakAllowed( hardpointType, team ) == false )
|
||||
return (-1);
|
||||
|
||||
assert ( isdefined ( hardpointType ) );
|
||||
|
||||
if( !isdefined( hacked ) )
|
||||
hacked = false;
|
||||
|
||||
if ( !isdefined( displayTeamMessage ) )
|
||||
displayTeamMessage = true;
|
||||
|
||||
if( GetDvarInt( "teamOpsEnabled" ) == 1 )
|
||||
displayTeamMessage = false;
|
||||
|
||||
if ( displayTeamMessage == true )
|
||||
{
|
||||
if ( !hacked )
|
||||
self displayKillstreakStartTeamMessageToAll( hardpointType );
|
||||
}
|
||||
|
||||
keys = GetArrayKeys( level.killstreaktype[hardpointType] );
|
||||
|
||||
foreach( key in keys )
|
||||
{
|
||||
// Check if killstreak is counted by this rule
|
||||
if ( !level.killstreaktype[hardpointType][key].counts )
|
||||
continue;
|
||||
|
||||
assert( isdefined(level.killstreakrules[key] ) );
|
||||
level.killstreakrules[key].cur++;
|
||||
if ( level.teambased )
|
||||
{
|
||||
if ( !isdefined( level.killstreakrules[key].curTeam[team] ) )
|
||||
level.killstreakrules[key].curTeam[team] = 0;
|
||||
level.killstreakrules[key].curTeam[team]++;
|
||||
}
|
||||
}
|
||||
|
||||
level notify( "killstreak_started", hardpointType, team, self );
|
||||
|
||||
killstreak_id = level.globalKillstreaksCalled;
|
||||
level.globalKillstreaksCalled++;
|
||||
|
||||
killstreak_data = [];
|
||||
killstreak_data[ "caller" ] = self GetXUID();
|
||||
killstreak_data[ "spawnid" ] = getplayerspawnid( self );
|
||||
killstreak_data[ "starttime" ] = gettime();
|
||||
killstreak_data[ "type" ] = hardpointType;
|
||||
killstreak_data[ "endtime" ] = 0;
|
||||
level.matchRecorderKillstreakKills[ killstreak_id ] = 0;
|
||||
|
||||
level.killstreaks_triggered[ killstreak_id ] = killstreak_data;
|
||||
|
||||
/#
|
||||
killstreak_debug_text( "Started killstreak: " + hardpointtype + " for team: " + team + " id: " + killstreak_id );
|
||||
#/
|
||||
|
||||
return killstreak_id;
|
||||
}
|
||||
|
||||
function displayKillstreakStartTeamMessageToAll( hardpointType )
|
||||
{
|
||||
if( GetDvarInt( "teamOpsEnabled" ) == 1 )
|
||||
return;
|
||||
|
||||
if ( isdefined( level.killstreaks[hardpointType] ) && isdefined( level.killstreaks[hardpointType].inboundtext ) )
|
||||
level thread popups::DisplayKillstreakTeamMessageToAll( hardpointType, self );
|
||||
}
|
||||
|
||||
function RecordKillstreakEndDirect(eventIndex, recordStreakIndex, totalKills)
|
||||
{
|
||||
player = self;
|
||||
|
||||
player RecordKillstreakEndEvent( eventIndex, recordStreakIndex, totalKills );
|
||||
|
||||
player.killstreakEvents[recordStreakIndex] = undefined;
|
||||
}
|
||||
|
||||
function RecordKillstreakEnd(recordStreakIndex, totalKills)
|
||||
{
|
||||
player = self;
|
||||
|
||||
if(!IsPlayer(player))
|
||||
return;
|
||||
|
||||
if(!IsDefined(totalKills))
|
||||
totalkills = 0;
|
||||
|
||||
if(!isDefined(player.killstreakEvents))
|
||||
{
|
||||
// This may store an eventIndex or number of kills, depending on whether a killstreak event or an end event happens first, respectively
|
||||
player.killstreakEvents = associativeArray();
|
||||
}
|
||||
eventIndex = player.killstreakEvents[recordStreakIndex];
|
||||
// Note that some killstreaks fire their end before their begin, so we need to check if the eventIndex is defined to determine that
|
||||
// Two cases - 1) KillstreakEvent happens first (correctly)
|
||||
if(isDefined(eventIndex))
|
||||
{
|
||||
player RecordKillstreakEndDirect(eventIndex, recordStreakIndex, totalKills);
|
||||
}
|
||||
else
|
||||
{
|
||||
// KillstreakEndEvent happens first
|
||||
player.killstreakEvents[recordStreakIndex] = totalKills;
|
||||
}
|
||||
}
|
||||
|
||||
function killstreakStop( hardpointType, team, id )
|
||||
{
|
||||
/#
|
||||
assert( isdefined( team ), "team needs to be defined" );
|
||||
#/
|
||||
|
||||
assert ( isdefined ( hardpointType ) );
|
||||
//assert( isdefined( id ), "Must provide the associated killstreak_id for " + hardpointType );
|
||||
|
||||
/#
|
||||
idstr = "undefined";
|
||||
if (IsDefined(id))
|
||||
idstr = id;
|
||||
killstreak_debug_text( "Stopped killstreak: " + hardpointtype + " for team: " + team + " id: " + idstr );
|
||||
#/
|
||||
keys = GetArrayKeys( level.killstreaktype[hardpointType] );
|
||||
|
||||
foreach( key in keys )
|
||||
{
|
||||
// Check if killstreak is counted by this rule
|
||||
if ( !level.killstreaktype[hardpointType][key].counts )
|
||||
continue;
|
||||
|
||||
assert( isdefined(level.killstreakrules[key] ) );
|
||||
level.killstreakrules[key].cur--;
|
||||
|
||||
assert (level.killstreakrules[key].cur >= 0 );
|
||||
|
||||
if ( level.teambased )
|
||||
{
|
||||
assert( isdefined( team ) );
|
||||
assert( isdefined( level.killstreakrules[key].curTeam[team] ) );
|
||||
|
||||
level.killstreakrules[key].curTeam[team]--;
|
||||
assert (level.killstreakrules[key].curTeam[team] >= 0 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !isdefined(id) || (id == (-1)) )
|
||||
{
|
||||
killstreak_debug_text("WARNING! Invalid killstreak id detected for " + hardpointType );
|
||||
|
||||
// log a lightweight entry in the DB to assist tracking down invalid cases
|
||||
bbPrint( "mpkillstreakuses", "starttime %d endtime %d name %s team %s", 0, GetTime(), hardpointType, team );
|
||||
return;
|
||||
}
|
||||
level.killstreaks_triggered[ id ][ "endtime" ] = GetTime();
|
||||
|
||||
totalKillsWithThisKillstreak = level.matchRecorderKillstreakKills[ id ];
|
||||
|
||||
bbPrint( "mpkillstreakuses", "starttime %d endtime %d spawnid %d name %s team %s",
|
||||
level.killstreaks_triggered[ id ][ "starttime" ],
|
||||
level.killstreaks_triggered[ id ][ "endtime" ],
|
||||
level.killstreaks_triggered[ id ][ "spawnid" ],
|
||||
hardpointType,
|
||||
team );
|
||||
|
||||
level.killstreaks_triggered[ id ] = undefined;
|
||||
level.matchRecorderKillstreakKills[ id ] = undefined;
|
||||
|
||||
if( isdefined( level.killstreaks[hardpointType].menuname ) )
|
||||
{
|
||||
recordStreakIndex = level.killstreakindices[level.killstreaks[hardpointType].menuname];
|
||||
if ( isdefined( self ) && isdefined( recordStreakIndex ) && ( !isdefined( self.activatingKillstreak ) || !self.activatingKillstreak ) )
|
||||
{
|
||||
entity = self;
|
||||
if(isDefined(entity.owner) )
|
||||
{
|
||||
entity = entity.owner;
|
||||
}
|
||||
|
||||
entity RecordKillstreakEnd(recordstreakindex, totalkillswiththiskillstreak);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isKillstreakAllowed( hardpointType, team )
|
||||
{
|
||||
/#
|
||||
assert( isdefined( team ), "team needs to be defined" );
|
||||
#/
|
||||
|
||||
assert ( isdefined ( hardpointType ) );
|
||||
|
||||
// general failsafe for all scorestreaks
|
||||
if ( self killstreaks::is_killstreak_start_blocked() )
|
||||
return false;
|
||||
|
||||
isAllowed = true;
|
||||
|
||||
keys = GetArrayKeys( level.killstreaktype[hardpointType] );
|
||||
|
||||
foreach( key in keys )
|
||||
{
|
||||
// Check if killstreak is restricted by this rule
|
||||
if ( !level.killstreaktype[hardpointType][key].checks )
|
||||
continue;
|
||||
|
||||
if ( level.killstreakrules[key].max != 0 )
|
||||
{
|
||||
if (level.killstreakrules[key].cur >= level.killstreakrules[key].max)
|
||||
{
|
||||
/#
|
||||
killstreak_debug_text( "Exceeded " + key + " overall" );
|
||||
#/
|
||||
isAllowed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( level.teambased && level.killstreakrules[key].maxPerTeam != 0 )
|
||||
{
|
||||
if ( !isdefined( level.killstreakrules[key].curTeam[team] ) )
|
||||
level.killstreakrules[key].curTeam[team] = 0;
|
||||
|
||||
if (level.killstreakrules[key].curTeam[team] >= level.killstreakrules[key].maxPerTeam)
|
||||
{
|
||||
isAllowed = false;
|
||||
/#
|
||||
killstreak_debug_text( "Exceeded " + key + " team" );
|
||||
#/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( isdefined( self.lastStand ) && self.lastStand )
|
||||
{
|
||||
/#
|
||||
killstreak_debug_text( "In LastStand" );
|
||||
#/
|
||||
isAllowed = false;
|
||||
}
|
||||
|
||||
isEMPed = false;
|
||||
// should only be needed in case of a hacked client, the client checks the EMP flag prior to switching to the killstreak weapon
|
||||
if ( self IsEMPJammed() )
|
||||
{
|
||||
/#
|
||||
killstreak_debug_text( "EMP active" );
|
||||
#/
|
||||
isAllowed = false;
|
||||
isEMPed = true;
|
||||
if ( self EMP::EnemyEMPActive() )
|
||||
{
|
||||
if ( isdefined( level.empEndTime ) )
|
||||
{
|
||||
secondsLeft = int( ( level.empendtime - getTime() ) / 1000 );
|
||||
if ( secondsLeft > 0 )
|
||||
{
|
||||
self iprintlnbold( &"KILLSTREAK_NOT_AVAILABLE_EMP_ACTIVE", secondsLeft );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( isAllowed == false )
|
||||
{
|
||||
if ( isdefined( level.killstreaks[hardpointType] ) && isdefined( level.killstreaks[hardpointType].notAvailableText ) )
|
||||
{
|
||||
self iprintlnbold( level.killstreaks[hardpointType].notAvailableText );
|
||||
|
||||
if ( !isdefined( self.currentKillstreakDialog ) && level.killstreaks[hardpointType].utilizesAirspace && isEMPed == false )
|
||||
{
|
||||
self globallogic_audio::play_taacom_dialog( "airspaceFull" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isAllowed;
|
||||
}
|
||||
|
||||
function killstreak_debug_text( text )
|
||||
{
|
||||
/#
|
||||
level.killstreak_rule_debug = GetDvarInt( "scr_killstreak_rule_debug", 0 ); // debug mode, draws debugging info on screen
|
||||
|
||||
if ( isdefined( level.killstreak_rule_debug ) )
|
||||
{
|
||||
if ( level.killstreak_rule_debug == 1.0 )
|
||||
{
|
||||
iprintln( "KSR: " + text + "\n" );
|
||||
}
|
||||
else if ( level.killstreak_rule_debug == 2.0 )
|
||||
{
|
||||
iprintlnbold( "KSR: " + text );
|
||||
}
|
||||
}
|
||||
#/
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,348 @@
|
||||
//Killstreak Rules
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Hellfire missile
|
||||
|
||||
|
||||
//Hellfire missile Bomblets
|
||||
|
||||
|
||||
|
||||
//AI_TANK
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//TURRET
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//MICROWAVE TURRET
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//UAV
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//CUAV
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Percentage of minimap coords to generate valid points from
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//SATELLITE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// spawns from an angle relative to map center (min)
|
||||
// spawns from an angle relative to map center (max)
|
||||
// the scale of the distance traveled for DURATION_MS
|
||||
|
||||
//RAPS
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//RAPS HELICOPTER DEPLOY POINT SELECTION
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//RAPS HELICOPTER AVOIDANCE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// RAPS damage/death fx
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//EMP
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//DRONE STRIKE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//HELICOPTER
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//FLAK DRONE
|
||||
//Spawn offset from parent
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//HELICOPTER GUNNER
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//DART
|
||||
|
||||
|
||||
|
||||
//Time in seconds to watch the death of the dart
|
||||
|
||||
|
||||
|
||||
//Offset from qrdrone_height node before out of range notification/shutdown
|
||||
|
||||
|
||||
|
||||
|
||||
//SENTINEL
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//2D distance between sentinel and enemy to begin combat state
|
||||
//Minimum distance between sentinel and enemy during combat
|
||||
//Maximum distance between sentinel and enemy during combat
|
||||
//Time to wait after unsuccessful burst fire attempt ( sight line / distance check )
|
||||
//Min time to wait after reaching goal in unaware state
|
||||
//Max time to wait after reaching goal in unaware state
|
||||
//Minimum radius from player for unaware target pos selection
|
||||
//Maximum radius from player for unaware target pos selection
|
||||
//Minimum spacing between valid target pos points
|
||||
//Height above sentinel owner for unaware target pos selection
|
||||
//Variance +/- in height from SENTINEL_HOVER_HEIGHT
|
||||
//Minimum height for combat position selection
|
||||
//Maximum height for combat position selection
|
||||
//Time to wait before attacking enemy after being shot
|
||||
//When in combat, if the owner exceeds this 2d distance, the sentinel will breakaway from combat
|
||||
//Offset from qrdrone_height node before out of range notification/shutdown
|
||||
//Vertical offset from rcbomb spawn height
|
||||
//Percentage of healthDefault ( set in veh gdt ) that each emp grenade will damage
|
||||
//Number of missiles required to destroy
|
||||
|
||||
//RCBOMB
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//COMBAT ROBOT
|
||||
|
||||
|
||||
|
||||
//HELICOPTER COMLINK
|
||||
|
||||
|
||||
//HIDE COMPASS (aka minimap)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,493 @@
|
||||
#using scripts\codescripts\struct;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
Line truncated
|
||||
|
||||
|
||||
|
||||
#precache( "client_fx", "killstreaks/fx_sg_distortion_cone_ash" );
|
||||
#precache( "client_fx", "killstreaks/fx_sg_distortion_cone_ash_sm" );
|
||||
|
||||
#using_animtree( "mp_microwaveturret" );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#namespace microwave_turret;
|
||||
|
||||
function autoexec __init__sytem__() { system::register("microwave_turret",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
clientfield::register( "vehicle", "turret_microwave_open", 1, 1, "int", µwave_open, !true, !true );
|
||||
clientfield::register( "scriptmover", "turret_microwave_init", 1, 1, "int", µwave_init_anim, !true, !true );
|
||||
clientfield::register( "scriptmover", "turret_microwave_close", 1, 1, "int", µwave_close_anim, !true, !true );
|
||||
}
|
||||
|
||||
function turret_microwave_sounds( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if( newVal == ( 1 ) )
|
||||
{
|
||||
self thread turret_microwave_sound_start( localClientNum );
|
||||
}
|
||||
else if( newVal == ( 0 ) )
|
||||
{
|
||||
self notify( "sound_stop" );
|
||||
}
|
||||
}
|
||||
|
||||
function turret_microwave_sound_start( localClientNum )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
self endon( "sound_stop" );
|
||||
|
||||
if ( ( isdefined( self.sound_loop_enabled ) && self.sound_loop_enabled ) )
|
||||
return;
|
||||
|
||||
self playsound ( 0, "wpn_micro_turret_start");
|
||||
|
||||
wait 0.7; // wait until deploy animation is finished
|
||||
|
||||
origin = self GetTagOrigin( "tag_flash" );
|
||||
angles = self GetTagAngles( "tag_flash" );
|
||||
|
||||
forward = AnglesToForward( angles );
|
||||
forward = VectorScale( forward, 750 );
|
||||
|
||||
trace = BulletTrace( origin, origin + forward, false, self );
|
||||
|
||||
start = origin;
|
||||
end = trace[ "position" ];
|
||||
|
||||
self.microwave_audio_start = start;
|
||||
self.microwave_audio_end = end;
|
||||
self thread turret_microwave_sound_updater();
|
||||
|
||||
if ( !( isdefined( self.sound_loop_enabled ) && self.sound_loop_enabled ) )
|
||||
{
|
||||
self.sound_loop_enabled = true;
|
||||
soundLineEmitter( "wpn_micro_turret_loop", self.microwave_audio_start, self.microwave_audio_end );
|
||||
self thread turret_microwave_sound_off_waiter( localClientNum );
|
||||
}
|
||||
}
|
||||
|
||||
function turret_microwave_sound_off_waiter( localClientNum )
|
||||
{
|
||||
msg = self util::waittill_any( "sound_stop", "entityshutdown" );
|
||||
|
||||
if ( ( msg === "sound_stop" ) )
|
||||
playsound (0, "wpn_micro_turret_stop", self.microwave_audio_start);
|
||||
|
||||
soundStopLineEmitter ( "wpn_micro_turret_loop", self.microwave_audio_start, self.microwave_audio_end );
|
||||
|
||||
if ( isdefined( self ) )
|
||||
{
|
||||
self.sound_loop_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function turret_microwave_sound_updater()
|
||||
{
|
||||
self endon( "beam_stop" );
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
origin = self GetTagOrigin( "tag_flash" );
|
||||
|
||||
if ( origin[0] != self.microwave_audio_start[0] || origin[1] != self.microwave_audio_start[1] || origin[2] != self.microwave_audio_start[2] )
|
||||
{
|
||||
previousStart = self.microwave_audio_start;
|
||||
previousEnd = self.microwave_audio_end;
|
||||
|
||||
angles = self GetTagAngles( "tag_flash" );
|
||||
|
||||
forward = AnglesToForward( angles );
|
||||
forward = VectorScale( forward, 750 );
|
||||
|
||||
trace = BulletTrace( origin, origin + forward, false, self );
|
||||
|
||||
self.microwave_audio_start = origin;
|
||||
self.microwave_audio_end = trace[ "position" ];
|
||||
|
||||
soundUpdateLineEmitter( "wpn_micro_turret_loop", previousStart, previousEnd, self.microwave_audio_start, self.microwave_audio_end );
|
||||
}
|
||||
|
||||
wait 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
function microwave_init_anim( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( !newVal )
|
||||
return;
|
||||
|
||||
self UseAnimTree( #animtree );
|
||||
self SetAnimRestart( %o_turret_guardian_close, 1.0, 0.0, 1.0 );
|
||||
self SetAnimTime( %o_turret_guardian_close, 1.0 );
|
||||
}
|
||||
|
||||
function microwave_open( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( !newVal )
|
||||
{
|
||||
self UseAnimTree( #animtree );
|
||||
self SetAnim( %o_turret_guardian_open, 0.0 ); // stop open anim
|
||||
self SetAnimRestart( %o_turret_guardian_close, 1.0, 0.0, 1.0 );
|
||||
|
||||
self notify( "beam_stop" );
|
||||
self notify( "sound_stop" );
|
||||
return;
|
||||
}
|
||||
|
||||
self UseAnimTree( #animtree );
|
||||
self SetAnim( %o_turret_guardian_close, 0.0 ); // stop close anim
|
||||
self SetAnimRestart( %o_turret_guardian_open, 1.0, 0.0, 1.0 );
|
||||
|
||||
self thread StartMicrowaveFx(localClientNum);
|
||||
}
|
||||
|
||||
function microwave_close_anim( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( !newVal )
|
||||
return;
|
||||
|
||||
self UseAnimTree( #animtree );
|
||||
self SetAnimRestart( %o_turret_guardian_close, 1.0, 0.0, 1.0 );
|
||||
}
|
||||
|
||||
/#
|
||||
function debug_trace(origin, trace)
|
||||
{
|
||||
if ( trace[ "fraction" ] < 1.0 )
|
||||
{
|
||||
color = ( 0.95, 0.05, 0.05 );
|
||||
}
|
||||
else
|
||||
{
|
||||
color = ( 0.05, 0.95, 0.05 );
|
||||
}
|
||||
|
||||
Sphere( trace[ "position" ], 5, color, 0.75, true, 10, 100 );
|
||||
util::debug_line( origin, trace[ "position" ], color, 100 );
|
||||
}
|
||||
#/
|
||||
|
||||
function StartMicrowaveFx( localClientNum )
|
||||
{
|
||||
turret = self;
|
||||
turret endon( "entityshutdown" );
|
||||
turret endon( "beam_stop" );
|
||||
|
||||
turret.should_update_fx = true;
|
||||
|
||||
self thread turret_microwave_sound_start( localClientNum );
|
||||
|
||||
origin = turret GetTagOrigin( "tag_flash" );
|
||||
angles = turret GetTagAngles( "tag_flash" );
|
||||
microwaveFXEnt = spawn(localClientNum, origin, "script_model");
|
||||
microwaveFXEnt SetModel("tag_microwavefx");
|
||||
microwaveFXEnt.angles = angles;
|
||||
microwaveFXEnt linkto(turret, "tag_flash");
|
||||
|
||||
microwaveFXEnt.fxHandles = [];
|
||||
microwaveFXEnt.fxNames = [];
|
||||
microwaveFXEnt.fxHashs = [];
|
||||
|
||||
self thread UpdateMicrowaveAim( microwaveFXEnt );
|
||||
self thread CleanupFx( localClientNum, microwaveFXEnt );
|
||||
wait 0.3;
|
||||
|
||||
while( true )
|
||||
{
|
||||
/#
|
||||
if ( GetDvarInt( "scr_microwave_turret_fx_debug" ) )
|
||||
{
|
||||
turret.should_update_fx = true;
|
||||
microwaveFXEnt.fxHashs["center"] = 0;
|
||||
}
|
||||
#/
|
||||
if ( turret.should_update_fx == false )
|
||||
{
|
||||
wait ( 1.0 );
|
||||
continue;
|
||||
}
|
||||
|
||||
// limit traces per frame when there are multiple microwave turrets on the field
|
||||
if ( isdefined( level.last_microwave_turret_fx_trace ) && level.last_microwave_turret_fx_trace == GetTime() )
|
||||
{
|
||||
wait(0.05);
|
||||
|
||||
// /# IPrintLnBold( "Delaying microwave turret fx! Time: " + GetTime() ); #/
|
||||
continue;
|
||||
}
|
||||
|
||||
angles = turret GetTagAngles( "tag_flash" );
|
||||
origin = turret GetTagOrigin( "tag_flash" );
|
||||
forward = AnglesToForward( angles );
|
||||
forward = VectorScale( forward, ( ( 750 ) + 40 ) );
|
||||
forwardRight = AnglesToForward( angles - (0, ( 55 ) / 3, 0) );
|
||||
forwardRight = VectorScale( forwardRight, ( ( 750 ) + 40 ) );
|
||||
forwardLeft = AnglesToForward( angles + (0, ( 55 ) / 3, 0) );
|
||||
forwardLeft = VectorScale( forwardLeft, ( ( 750 ) + 40 ) );
|
||||
|
||||
trace = BulletTrace( origin, origin + forward, false, turret );
|
||||
traceRight = BulletTrace( origin, origin + forwardRight, false, turret );
|
||||
traceLeft = BulletTrace( origin, origin + forwardLeft, false, turret );
|
||||
|
||||
/#
|
||||
if ( GetDvarInt( "scr_microwave_turret_fx_debug" ) )
|
||||
{
|
||||
debug_trace( origin, trace );
|
||||
debug_trace( origin, traceRight );
|
||||
debug_trace( origin, traceLeft );
|
||||
}
|
||||
#/
|
||||
|
||||
need_to_rebuild = microwaveFXEnt MicrowaveFxHash( trace, origin, "center" );
|
||||
need_to_rebuild |= microwaveFXEnt MicrowaveFxHash( traceRight, origin, "right" );
|
||||
need_to_rebuild |= microwaveFXEnt MicrowaveFxHash( traceLeft, origin, "left" );
|
||||
|
||||
level.last_microwave_turret_fx_trace = getTime();
|
||||
|
||||
if( !need_to_rebuild )
|
||||
{
|
||||
wait ( 1.0 );
|
||||
continue;
|
||||
}
|
||||
|
||||
wait( 0.1 );
|
||||
|
||||
microwaveFXEnt PlayMicrowaveFx( localClientNum, trace, traceRight, TraceLeft, origin );
|
||||
|
||||
turret.should_update_fx = false;
|
||||
wait ( 1.0 );
|
||||
}
|
||||
}
|
||||
|
||||
function UpdateMicrowaveAim( microwaveFXEnt )
|
||||
{
|
||||
turret = self;
|
||||
turret endon( "entityshutdown" );
|
||||
turret endon( "beam_stop" );
|
||||
|
||||
last_angles = turret GetTagAngles( "tag_flash" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
angles = turret GetTagAngles( "tag_flash" );
|
||||
|
||||
if ( last_angles != angles )
|
||||
{
|
||||
turret.should_update_fx = true;
|
||||
last_angles = angles;
|
||||
}
|
||||
|
||||
wait 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
function MicrowaveFxHash( trace, origin, name )
|
||||
{
|
||||
hash = 0;
|
||||
counter = 2;
|
||||
for ( i = 0; i < 5; i++ )
|
||||
{
|
||||
endOfHalfFxSq = ( (( i * ( 150 ) ) + ( 125 )) * (( i * ( 150 ) ) + ( 125 )) );
|
||||
endOfFullFxSq = ( (( i * ( 150 ) ) + ( 200 )) * (( i * ( 150 ) ) + ( 200 )) );
|
||||
|
||||
traceDistSq = DistanceSquared( origin, trace[ "position" ] );
|
||||
if( traceDistSq >= endOfHalfFxSq || i == 0 )
|
||||
{
|
||||
if ( traceDistSq < endOfFullFxSq )
|
||||
{
|
||||
hash += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
hash += counter;
|
||||
}
|
||||
}
|
||||
|
||||
counter *= 2;
|
||||
}
|
||||
|
||||
if ( !isDefined( self.fxHashs[name] ) )
|
||||
self.fxHashs[name] = 0;
|
||||
|
||||
last_hash = self.fxHashs[name];
|
||||
|
||||
self.fxHashs[name] = hash;
|
||||
|
||||
return last_hash != hash;
|
||||
}
|
||||
|
||||
function CleanupFx( localClientNum, microwaveFXEnt )
|
||||
{
|
||||
self util::waittill_any( "entityshutdown", "beam_stop" );
|
||||
|
||||
foreach ( handle in microwaveFXEnt.fxHandles )
|
||||
{
|
||||
if ( isdefined( handle ) )
|
||||
{
|
||||
StopFx( localClientNum, handle );
|
||||
}
|
||||
}
|
||||
|
||||
microwaveFXEnt delete();
|
||||
}
|
||||
|
||||
function play_fx_on_tag( localClientNum, fxName, tag )
|
||||
{
|
||||
if ( !isdefined( self.fxHandles[tag] ) || fxName != self.fxNames[tag] )
|
||||
{
|
||||
stop_fx_on_tag( localClientNum, fxName, tag );
|
||||
|
||||
self.fxNames[tag] = fxName;
|
||||
self.fxHandles[tag] = PlayFxOnTag( localCLientNum, fxName, self, tag );
|
||||
}
|
||||
}
|
||||
|
||||
function stop_fx_on_tag( localClientNum, fxName, tag )
|
||||
{
|
||||
if ( isdefined( self.fxHandles[tag] ) )
|
||||
{
|
||||
StopFx( localClientNum, self.fxHandles[tag] );
|
||||
|
||||
self.fxHandles[tag] = undefined;
|
||||
self.fxNames[tag] = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/#
|
||||
function render_debug_sphere( tag, color, fxName )
|
||||
{
|
||||
if ( GetDvarInt( "scr_microwave_turret_fx_debug" ) )
|
||||
{
|
||||
origin = self GetTagOrigin( tag );
|
||||
|
||||
Sphere( origin, 2, color, 0.75, true, 10, 100 );
|
||||
}
|
||||
}
|
||||
#/
|
||||
|
||||
function stop_or_start_fx( localClientNum, fxName, tag, start )
|
||||
{
|
||||
if ( start )
|
||||
{
|
||||
self play_fx_on_tag( localClientNum, fxName, tag );
|
||||
/#
|
||||
if ( fxName == "killstreaks/fx_sg_distortion_cone_ash_sm" )
|
||||
{
|
||||
render_debug_sphere( tag, ( 0.5, 0.5, 0 ), fxName );
|
||||
}
|
||||
else
|
||||
{
|
||||
render_debug_sphere( tag, ( 0, 1, 0 ), fxName );
|
||||
}
|
||||
#/
|
||||
}
|
||||
else
|
||||
{
|
||||
stop_fx_on_tag( localClientNum, fxName, tag );
|
||||
/#
|
||||
render_debug_sphere( tag, ( 1, 0, 0 ), fxName );
|
||||
#/
|
||||
}
|
||||
}
|
||||
|
||||
function PlayMicrowaveFx( localCLientNum, trace, traceRight, traceLeft, origin )
|
||||
{
|
||||
rows = 5;
|
||||
|
||||
// /# IPrintLnBold( "Playing Microwave Fx: " + GetTime() ); #/
|
||||
|
||||
for ( i = 0; i < rows; i++ )
|
||||
{
|
||||
endOfHalfFxSq = ( (( i * ( 150 ) ) + ( 125 )) * (( i * ( 150 ) ) + ( 125 )) );
|
||||
endOfFullFxSq = ( (( i * ( 150 ) ) + ( 200 )) * (( i * ( 150 ) ) + ( 200 )) );
|
||||
|
||||
traceDistSq = DistanceSquared( origin, trace[ "position" ] );
|
||||
|
||||
startFx = traceDistSq >= endOfHalfFxSq || i == 0;
|
||||
fxName = ( ( traceDistSq < endOfFullFxSq ) ? "killstreaks/fx_sg_distortion_cone_ash_sm" : "killstreaks/fx_sg_distortion_cone_ash" );
|
||||
|
||||
switch ( i )
|
||||
{
|
||||
case 0:
|
||||
// we always want this one to play
|
||||
self play_fx_on_tag( localCLientNum, fxName, "tag_fx11" );
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx32", startFx );
|
||||
break;
|
||||
case 3:
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx42", startFx );
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx43", startFx );
|
||||
break;
|
||||
case 4:
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx53", startFx );
|
||||
break;
|
||||
}
|
||||
|
||||
traceDistSq = DistanceSquared( origin, traceLeft[ "position" ] );
|
||||
|
||||
startFx = traceDistSq >= endOfHalfFxSq;
|
||||
fxName = ( ( traceDistSq < endOfFullFxSq ) ? "killstreaks/fx_sg_distortion_cone_ash_sm" : "killstreaks/fx_sg_distortion_cone_ash" );
|
||||
|
||||
switch ( i )
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx22", startFx );
|
||||
break;
|
||||
case 2:
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx33", startFx );
|
||||
break;
|
||||
case 3:
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx44", startFx );
|
||||
break;
|
||||
case 4:
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx54", startFx );
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx55", startFx );
|
||||
break;
|
||||
}
|
||||
|
||||
traceDistSq = DistanceSquared( origin, traceRight[ "position" ] );
|
||||
|
||||
startFx = traceDistSq >= endOfHalfFxSq;
|
||||
fxName = ( ( traceDistSq < endOfFullFxSq ) ? "killstreaks/fx_sg_distortion_cone_ash_sm" : "killstreaks/fx_sg_distortion_cone_ash" );
|
||||
|
||||
switch ( i )
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx21", startFx );
|
||||
break;
|
||||
case 2:
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx31", startFx );
|
||||
break;
|
||||
case 3:
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx41", startFx );
|
||||
break;
|
||||
case 4:
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx51", startFx );
|
||||
self stop_or_start_fx( localCLientNum, fxName, "tag_fx52", startFx );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// /# IPrintLnBold( "Done playing Microwave Fx: " + GetTime() ); #/
|
||||
}
|
||||
@@ -0,0 +1,710 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\challenges_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\flag_shared;
|
||||
#using scripts\shared\hostmigration_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\popups_shared;
|
||||
#using scripts\shared\scoreevents_shared;
|
||||
#using scripts\shared\turret_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_death_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
#using scripts\shared\weapons\_weaponobjects;
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\gametypes\_globallogic_audio;
|
||||
#using scripts\mp\gametypes\_hostmigration;
|
||||
#using scripts\mp\gametypes\_spawning;
|
||||
#using scripts\mp\killstreaks\_airsupport;
|
||||
#using scripts\mp\killstreaks\_airsupport;
|
||||
#using scripts\mp\killstreaks\_emp;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_killstreak_bundles;
|
||||
#using scripts\mp\killstreaks\_killstreak_hacking;
|
||||
#using scripts\mp\killstreaks\_placeables;
|
||||
#using scripts\mp\killstreaks\_remote_weapons;
|
||||
#using scripts\mp\killstreaks\_turret;
|
||||
#using scripts\mp\teams\_teams;
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#precache( "string", "KILLSTREAK_EARNED_AUTO_TURRET" );
|
||||
#precache( "string", "KILLSTREAK_AUTO_TURRET_NOT_AVAILABLE" );
|
||||
|
||||
#precache( "string", "KILLSTREAK_AUTO_TURRET_CRATE" );
|
||||
#precache( "string", "KILLSTREAK_MICROWAVE_TURRET_CRATE" );
|
||||
#precache( "string", "KILLSTREAK_EARNED_AUTO_TURRET" );
|
||||
#precache( "string", "KILLSTREAK_AUTO_TURRET_NOT_AVAILABLE" );
|
||||
#precache( "string", "KILLSTREAK_AIRSPACE_FULL" );
|
||||
#precache( "string", "KILLSTREAK_EARNED_MICROWAVE_TURRET" );
|
||||
#precache( "string", "KILLSTREAK_MICROWAVE_TURRET_NOT_AVAILABLE" );
|
||||
#precache( "string", "KILLSTREAK_MICROWAVE_TURRET_HACKED" );
|
||||
#precache( "string", "KILLSTREAK_MICROWAVE_TURRET_INBOUND" );
|
||||
#precache( "string", "KILLSTREAK_DESTROYED_MICROWAVE_TURRET" );
|
||||
#precache( "triggerstring", "KILLSTREAK_MICROWAVE_TURRET_PLACE_TURRET_HINT" );
|
||||
#precache( "triggerstring", "KILLSTREAK_MICROWAVE_TURRET_INVALID_TURRET_LOCATION" );
|
||||
#precache( "triggerstring", "KILLSTREAK_MICROWAVE_TURRET_PICKUP" );
|
||||
#precache( "string", "mpl_killstreak_turret" );
|
||||
#precache( "string", "mpl_killstreak_auto_turret" );
|
||||
#precache( "fx", "killstreaks/fx_sentry_emp_stun" );
|
||||
#precache( "fx", "killstreaks/fx_sentry_damage_state" );
|
||||
#precache( "fx", "killstreaks/fx_sentry_death_state" );
|
||||
#precache( "fx", "killstreaks/fx_sentry_exp" );
|
||||
#precache( "fx", "killstreaks/fx_sentry_disabled_spark" );
|
||||
#precache( "fx", "killstreaks/fx_sg_emp_stun" );
|
||||
#precache( "fx", "killstreaks/fx_sg_damage_state" );
|
||||
#precache( "fx", "killstreaks/fx_sg_death_state" );
|
||||
#precache( "fx", "killstreaks/fx_sg_exp" );
|
||||
#precache( "fx", "killstreaks/fx_sg_distortion_cone_ash" );
|
||||
#precache( "fx", "killstreaks/fx_sg_distortion_cone_ash_sm" );
|
||||
#precache( "fx", "explosions/fx_exp_equipment_lg" );
|
||||
#precache( "model", "veh_t7_turret_guardian_red" );
|
||||
#precache( "model", "veh_t7_turret_guardian_yellow" );
|
||||
#precache( "model", "wpn_t7_none_world" );
|
||||
|
||||
#using_animtree( "mp_microwaveturret" );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#namespace microwave_turret;
|
||||
|
||||
function init()
|
||||
{
|
||||
killstreaks::register( "microwave_turret", "microwave_turret_deploy", "killstreak_" + "microwave_turret", "microwave_turret" + "_used", &ActivateMicrowaveTurret, false, true );
|
||||
killstreaks::register_strings( "microwave_turret", &"KILLSTREAK_EARNED_MICROWAVE_TURRET", &"KILLSTREAK_MICROWAVE_TURRET_NOT_AVAILABLE", &"KILLSTREAK_MICROWAVE_TURRET_INBOUND", undefined, &"KILLSTREAK_MICROWAVE_TURRET_HACKED", false );
|
||||
killstreaks::register_dialog( "microwave_turret", "mpl_killstreak_turret", "microwaveTurretDialogBundle", undefined, "friendlyMicrowaveTurret", "enemyMicrowaveTurret", "enemyMicrowaveTurretMultiple", "friendlyMicrowaveTurretHacked", "enemyMicrowaveTurretHacked", "requestMicrowaveTurret", "threatMicrowaveTurret" );
|
||||
killstreaks::register_remote_override_weapon( "microwave_turret", "microwave_turret" );
|
||||
|
||||
level.microwaveOpenAnim = %o_turret_guardian_open;
|
||||
level.microwaveCloseAnim = %o_turret_guardian_close;
|
||||
|
||||
clientfield::register( "vehicle", "turret_microwave_open", 1, 1, "int" );
|
||||
clientfield::register( "scriptmover", "turret_microwave_init", 1, 1, "int" ); // re-export model in close position to save this clientfield
|
||||
clientfield::register( "scriptmover", "turret_microwave_close", 1, 1, "int" );
|
||||
|
||||
vehicle::add_main_callback( "microwave_turret", &InitTurretVehicle );
|
||||
|
||||
callback::on_spawned( &on_player_spawned );
|
||||
callback::on_vehicle_spawned( &on_vehicle_spawned );
|
||||
}
|
||||
|
||||
function InitTurretVehicle()
|
||||
{
|
||||
turretVehicle = self;
|
||||
//turretVehicle.delete_on_death = true;
|
||||
|
||||
turretVehicle killstreaks::setup_health( "microwave_turret" );
|
||||
turretVehicle.damageTaken = 0;
|
||||
turretVehicle.deal_no_crush_damage = true;
|
||||
turretVehicle.health = turretVehicle.maxhealth;
|
||||
|
||||
turretVehicle turret::set_max_target_distance( ( 750 ) * 1.2, 0 );
|
||||
turretVehicle turret::set_on_target_angle( (15), 0 );
|
||||
turretVehicle clientfield::set( "enemyvehicle", 1 );
|
||||
turretVehicle.soundmod = "hpm";
|
||||
|
||||
turretVehicle.overrideVehicleDamage = &OnTurretDamage;
|
||||
turretVehicle.overrideVehicleDeath = &OnTurretDeath;
|
||||
turretVehicle.overrideVehicleDeathPostGame = &OnTurretDeathPostGame;
|
||||
|
||||
turretVehicle.aim_only_no_shooting = true;
|
||||
}
|
||||
|
||||
function on_player_spawned()
|
||||
{
|
||||
// needs to reset this whenever a player spawns, could be switching teams and this var remains defined
|
||||
self reset_being_microwaved();
|
||||
}
|
||||
|
||||
function on_vehicle_spawned()
|
||||
{
|
||||
self reset_being_microwaved();
|
||||
}
|
||||
|
||||
function reset_being_microwaved()
|
||||
{
|
||||
self.lastMicrowavedBy = undefined;
|
||||
self.beingMicrowavedBy = undefined;
|
||||
}
|
||||
|
||||
function ActivateMicrowaveTurret()
|
||||
{
|
||||
player = self;
|
||||
assert( IsPlayer( player ) );
|
||||
|
||||
killstreakId = self killstreakrules::killstreakStart( "microwave_turret", player.team, false, false );
|
||||
if( killstreakId == (-1) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bundle = level.killstreakBundle["microwave_turret"];
|
||||
|
||||
turret = player placeables::SpawnPlaceable( "microwave_turret", killstreakId,
|
||||
&OnPlaceTurret, &OnCancelPlacement, &OnPickupTurret, &OnShutdown, undefined, &OnEMP,
|
||||
"veh_t7_turret_guardian", "veh_t7_turret_guardian_yellow", "veh_t7_turret_guardian_red", true,
|
||||
&"KILLSTREAK_MICROWAVE_TURRET_PICKUP", ( 90 * 1000 ), undefined, ( ( 1800 ) + 1 ),
|
||||
bundle.ksPlaceableHint, bundle.ksPlaceableInvalidLocationHint );
|
||||
turret killstreaks::setup_health( "microwave_turret" );
|
||||
turret.damageTaken = 0;
|
||||
turret.killstreakEndTime = getTime() + ( 90 * 1000 );
|
||||
turret thread WatchKillstreakEnd( killstreakId, player.team );
|
||||
turret thread util::ghost_wait_show_to_player( player );
|
||||
turret.otherModel thread util::ghost_wait_show_to_others( player );
|
||||
turret clientfield::set( "turret_microwave_init", 1 );
|
||||
turret.otherModel clientfield::set( "turret_microwave_init", 1 );
|
||||
|
||||
event = turret util::waittill_any_return( "placed", "cancelled", "death", "disconnect" );
|
||||
if( event != "placed" )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function OnPlaceTurret( turret )
|
||||
{
|
||||
player = self;
|
||||
assert( IsPlayer( player ) );
|
||||
|
||||
if( isdefined( turret.vehicle ) )
|
||||
{
|
||||
turret.vehicle.origin = turret.origin;
|
||||
turret.vehicle.angles = turret.angles;
|
||||
turret.vehicle thread util::ghost_wait_show( 0.05 );
|
||||
//turret.vehicle playsound ("wpn_micro_turret_start");
|
||||
}
|
||||
else
|
||||
{
|
||||
turret.vehicle = SpawnVehicle( "microwave_turret", turret.origin, turret.angles, "dynamic_spawn_ai" );
|
||||
turret.vehicle.owner = player;
|
||||
turret.vehicle SetOwner( player );
|
||||
turret.vehicle.ownerEntNum = player.entNum;
|
||||
turret.vehicle.parentStruct = turret;
|
||||
|
||||
turret.vehicle.team = player.team;
|
||||
turret.vehicle SetTeam( player.team );
|
||||
turret.vehicle turret::set_team( player.team, 0 );
|
||||
turret.vehicle.ignore_vehicle_underneath_splash_scalar = true;
|
||||
turret.vehicle.use_non_teambased_enemy_selection = true;
|
||||
turret.vehicle.turret = turret;
|
||||
|
||||
turret.vehicle thread util::ghost_wait_show( 0.05 );
|
||||
|
||||
level thread popups::DisplayKillstreakTeamMessageToAll( "microwave_turret", player );
|
||||
player AddWeaponStat( GetWeapon( "microwave_turret" ), "used", 1 );
|
||||
|
||||
turret.vehicle killstreaks::configure_team( "microwave_turret", turret.killstreakId, player );
|
||||
turret.vehicle killstreak_hacking::enable_hacking( "microwave_turret", &HackedPreFunction, &HackedPostFunction );
|
||||
player killstreaks::play_killstreak_start_dialog( "microwave_turret", player.pers["team"], turret.killstreakId );
|
||||
}
|
||||
|
||||
turret.vehicle turret::enable( 0, false );
|
||||
Target_Set( turret.vehicle, ( 0, 0, 36 ) );
|
||||
|
||||
turret.vehicle vehicle::disconnect_paths( 0, false );
|
||||
|
||||
turret StartMicrowave();
|
||||
}
|
||||
|
||||
function HackedPreFunction( hacker )
|
||||
{
|
||||
turretVehicle = self;
|
||||
turretvehicle.turret notify( "hacker_delete_placeable_trigger" );
|
||||
turretvehicle.turret StopMicrowave();
|
||||
turretvehicle.turret killstreaks::configure_team( "microwave_turret", turretvehicle.turret.killstreakId, hacker, undefined, undefined, undefined, true );
|
||||
}
|
||||
|
||||
function HackedPostFunction( hacker )
|
||||
{
|
||||
turretVehicle = self;
|
||||
turretvehicle.turret StartMicrowave();
|
||||
}
|
||||
|
||||
function OnCancelPlacement( turret )
|
||||
{
|
||||
turret notify( "microwave_turret_shutdown" );
|
||||
}
|
||||
|
||||
function OnPickupTurret( turret )
|
||||
{
|
||||
turret StopMicrowave();
|
||||
|
||||
turret.vehicle thread GhostAfterWait( 0.05 );
|
||||
turret.vehicle turret::disable( 0 );
|
||||
turret.vehicle LinkTo( turret );
|
||||
Target_Remove( turret.vehicle );
|
||||
|
||||
turret.vehicle vehicle::connect_paths();
|
||||
|
||||
//turret.vehicle playsound ("wpn_micro_turret_stop");
|
||||
}
|
||||
|
||||
function GhostAfterWait( wait_time )
|
||||
{
|
||||
self endon( "death" );
|
||||
|
||||
wait wait_time;
|
||||
self Ghost();
|
||||
}
|
||||
|
||||
function OnEMP( attacker )
|
||||
{
|
||||
turret = self;
|
||||
//TODO: Play Turret EMP FX
|
||||
}
|
||||
|
||||
function OnTurretDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
|
||||
{
|
||||
empDamage = int( iDamage + ( self.healthdefault * ( 1 ) ) + 0.5 );
|
||||
|
||||
iDamage = self killstreaks::OnDamagePerWeapon( "microwave_turret", eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, self.maxhealth, undefined, self.maxhealth*0.4, undefined, empDamage, undefined, true, 1.0 );
|
||||
self.damageTaken += iDamage;
|
||||
return iDamage;
|
||||
}
|
||||
|
||||
function OnTurretDeath( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime )
|
||||
{
|
||||
turretVehicle = self;
|
||||
|
||||
eAttacker = self [[ level.figure_out_attacker ]]( eAttacker );
|
||||
|
||||
if ( isdefined( turretVehicle.parentStruct ) )
|
||||
{
|
||||
turretVehicle.parentStruct placeables::ForceShutdown();
|
||||
|
||||
if ( turretVehicle.parentStruct.killstreakTimedOut === true && isdefined( turretVehicle.owner ) )
|
||||
{
|
||||
turretVehicle.owner globallogic_audio::play_taacom_dialog( "timeout", turretVehicle.parentStruct.killstreakType );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( isdefined( eAttacker ) && IsPlayer( eAttacker ) && isdefined( turretVehicle.owner ) && ( eAttacker != turretVehicle.owner ) )
|
||||
turretVehicle.parentStruct killstreaks::play_destroyed_dialog_on_owner( turretVehicle.parentStruct.killstreakType, turretVehicle.parentStruct.killstreakId );
|
||||
}
|
||||
}
|
||||
|
||||
if( isdefined( eAttacker ) && IsPlayer( eAttacker ) && ( !isdefined( self.owner ) || self.owner util::IsEnemyPlayer( eAttacker ) ) )
|
||||
{
|
||||
scoreevents::processScoreEvent( "destroyed_microwave_turret", eAttacker, self.owner, weapon );
|
||||
eAttacker challenges::destroyScoreStreak( weapon, false, true, false );
|
||||
eAttacker challenges::destroyNonAirScoreStreak_PostStatsLock( weapon );
|
||||
eAttacker AddPlayerStat( "destroy_turret", 1 );
|
||||
eAttacker AddWeaponStat( weapon, "destroy_turret", 1 );
|
||||
LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_MICROWAVE_TURRET", eAttacker.entnum );
|
||||
}
|
||||
|
||||
if ( isdefined( turretVehicle.parentStruct ) )
|
||||
{
|
||||
turretVehicle.parentStruct notify( "microwave_turret_shutdown" );
|
||||
}
|
||||
|
||||
turretVehicle vehicle_death::death_fx();
|
||||
|
||||
wait 0.1;
|
||||
|
||||
turretVehicle delete();
|
||||
}
|
||||
|
||||
function OnTurretDeathPostGame( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime )
|
||||
{
|
||||
turretVehicle = self;
|
||||
|
||||
if ( isdefined( turretVehicle.parentStruct ) )
|
||||
{
|
||||
turretVehicle.parentStruct placeables::ForceShutdown();
|
||||
}
|
||||
if ( isdefined( turretVehicle.parentStruct ) )
|
||||
{
|
||||
turretVehicle.parentStruct notify( "microwave_turret_shutdown" );
|
||||
}
|
||||
|
||||
turretVehicle vehicle_death::death_fx();
|
||||
|
||||
wait 0.1;
|
||||
|
||||
turretVehicle delete();
|
||||
}
|
||||
|
||||
|
||||
function OnShutdown( turret )
|
||||
{
|
||||
turret StopMicrowave();
|
||||
|
||||
if ( isdefined( turret.vehicle ) )
|
||||
{
|
||||
turret.vehicle playsound ("mpl_m_turret_exp");
|
||||
turret.vehicle Kill();
|
||||
}
|
||||
|
||||
turret notify( "microwave_turret_shutdown" );
|
||||
}
|
||||
|
||||
function WatchKillstreakEnd( killstreak_id, team )
|
||||
{
|
||||
turret = self;
|
||||
|
||||
turret waittill( "microwave_turret_shutdown" );
|
||||
|
||||
killstreakrules::killstreakStop( "microwave_turret", team, killstreak_id );
|
||||
}
|
||||
|
||||
function StartMicrowave()
|
||||
{
|
||||
turret = self;
|
||||
if ( isdefined( turret.trigger ) )
|
||||
{
|
||||
turret.trigger delete();
|
||||
}
|
||||
turret.trigger = spawn("trigger_radius", turret.origin + (0,0,-( 750 )), level.aiTriggerSpawnFlags | level.vehicleTriggerSpawnFlags, ( 750 ), ( 750 )*2);
|
||||
turret thread TurretThink();
|
||||
|
||||
turret clientfield::set( "turret_microwave_close", 0 );
|
||||
turret.otherModel clientfield::set( "turret_microwave_close", 0 );
|
||||
|
||||
if ( isdefined( turret.vehicle ))
|
||||
{
|
||||
turret.vehicle clientfield::set( "turret_microwave_open", 1 );
|
||||
}
|
||||
|
||||
turret turret::CreateTurretInfluencer( "turret" );
|
||||
turret turret::CreateTurretInfluencer( "turret_close" );
|
||||
|
||||
/#
|
||||
turret thread TurretDebugWatch();
|
||||
#/
|
||||
}
|
||||
|
||||
function StopMicrowave()
|
||||
{
|
||||
turret = self;
|
||||
turret spawning::remove_influencers();
|
||||
|
||||
if( isdefined( turret ) )
|
||||
{
|
||||
turret clientfield::set( "turret_microwave_close", 1 );
|
||||
turret.otherModel clientfield::set( "turret_microwave_close", 1 );
|
||||
|
||||
if ( isdefined( turret.vehicle ) )
|
||||
{
|
||||
turret.vehicle clientfield::set( "turret_microwave_open", 0 );
|
||||
}
|
||||
|
||||
turret playsound ("mpl_microwave_beam_off");
|
||||
|
||||
if( isdefined( turret.microwaveFXEnt ) )
|
||||
{
|
||||
turret.microwaveFXEnt delete();
|
||||
|
||||
// /# IPrintLnBold( "Deleted Microwave Fx Ent: " + GetTime() ); #/
|
||||
}
|
||||
|
||||
if( isdefined( turret.trigger ) )
|
||||
{
|
||||
turret.trigger notify( "microwave_end_fx" );
|
||||
turret.trigger Delete();
|
||||
}
|
||||
|
||||
/#
|
||||
turret notify( "stop_turret_debug" );
|
||||
#/
|
||||
}
|
||||
}
|
||||
|
||||
function TurretDebugWatch()
|
||||
{
|
||||
turret = self;
|
||||
turret endon( "stop_turret_debug" );
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if ( GetDvarInt( "scr_microwave_turret_debug" ) != 0 )
|
||||
{
|
||||
turret TurretDebug();
|
||||
|
||||
{wait(.05);};
|
||||
}
|
||||
else
|
||||
{
|
||||
wait 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function TurretDebug()
|
||||
{
|
||||
turret = self;
|
||||
|
||||
debug_line_frames = 3;
|
||||
|
||||
angles = turret.vehicle GetTagAngles( "tag_flash" );
|
||||
origin = turret.vehicle GetTagOrigin( "tag_flash" );
|
||||
|
||||
cone_apex = origin;
|
||||
forward = AnglesToForward( angles ) ;
|
||||
dome_apex = cone_apex + VectorScale( forward, ( 750 ) );
|
||||
|
||||
util::debug_spherical_cone( cone_apex, dome_apex, ( 15 ), 16, ( 0.95, 0.1, 0.1 ), 0.3, true, debug_line_frames );
|
||||
}
|
||||
|
||||
|
||||
function TurretThink()
|
||||
{
|
||||
turret = self;
|
||||
turret endon( "microwave_turret_shutdown" );
|
||||
|
||||
turret.trigger endon( "death" );
|
||||
turret.trigger endon( "delete" );
|
||||
|
||||
turret.turret_vehicle_entnum = turret.vehicle GetEntityNumber();
|
||||
|
||||
while( true )
|
||||
{
|
||||
turret.trigger waittill( "trigger", ent );
|
||||
|
||||
if ( ent == turret )
|
||||
continue;
|
||||
|
||||
if ( !isdefined( ent.beingMicrowavedBy ) )
|
||||
{
|
||||
ent.beingMicrowavedBy = [];
|
||||
}
|
||||
|
||||
if( !isdefined( ent.beingMicrowavedBy[ turret.turret_vehicle_entnum ] ) )
|
||||
{
|
||||
turret thread MicrowaveEntity( ent );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function MicrowaveEntityPostShutdownCleanup( entity )
|
||||
{
|
||||
entity endon( "disconnect" );
|
||||
entity endon( "end_MicrowaveEntityPostShutdownCleanup" );
|
||||
|
||||
turret = self;
|
||||
|
||||
turret_vehicle_entnum = turret.turret_vehicle_entnum;
|
||||
|
||||
turret waittill( "microwave_turret_shutdown" );
|
||||
|
||||
if ( isdefined(entity) )
|
||||
{
|
||||
if ( isdefined( entity.beingMicrowavedBy ) && isdefined( entity.beingMicrowavedBy[ turret_vehicle_entnum ] ) )
|
||||
{
|
||||
entity.beingMicrowavedBy[ turret_vehicle_entnum ] = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function MicrowaveEntity( entity )
|
||||
{
|
||||
turret = self;
|
||||
|
||||
turret endon( "microwave_turret_shutdown" );
|
||||
entity endon( "disconnect" );
|
||||
entity endon( "death" );
|
||||
|
||||
if ( IsPlayer( entity ) )
|
||||
{
|
||||
entity endon( "joined_team" );
|
||||
entity endon( "joined_spectators" );
|
||||
}
|
||||
|
||||
turret thread MicrowaveEntityPostShutdownCleanup( entity );
|
||||
|
||||
entity.beingMicrowavedBy[ turret.turret_vehicle_entnum ] = turret.owner;
|
||||
entity.microwaveDamageInitialDelay = true;
|
||||
entity.microwaveEffect = 0;
|
||||
|
||||
shellShockScalar = 1;
|
||||
viewKickScalar = 1;
|
||||
damageScalar = 1;
|
||||
|
||||
if ( IsPlayer( entity ) && entity hasPerk( "specialty_microwaveprotection" ) )
|
||||
{
|
||||
shellShockScalar = getDvarFloat( "specialty_microwaveprotection_shellshock_scalar", 0.5 );
|
||||
viewKickScalar = getDvarFloat( "specialty_microwaveprotection_viewkick_scalar", 0.5 );
|
||||
damageScalar = getDvarFloat( "specialty_microwaveprotection_damage_scalar", 0.5 );
|
||||
}
|
||||
|
||||
turretWeapon = GetWeapon( "microwave_turret" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
if( !isdefined( turret ) || !turret MicrowaveTurretAffectsEntity( entity ) || !isdefined( turret.trigger ) )
|
||||
{
|
||||
if( !isdefined(entity))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
entity.beingMicrowavedBy[ turret.turret_vehicle_entnum ] = undefined;
|
||||
|
||||
if( isdefined( entity.microwavePoisoning ) && entity.microwavePoisoning )
|
||||
{
|
||||
entity.microwavePoisoning = false;
|
||||
}
|
||||
|
||||
entity notify( "end_MicrowaveEntityPostShutdownCleanup" );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
damage = ( 15 ) * damageScalar;
|
||||
|
||||
if ( level.hardcoreMode )
|
||||
{
|
||||
damage = damage / 2;
|
||||
}
|
||||
|
||||
if ( !IsAi( entity ) && entity util::mayApplyScreenEffect() )
|
||||
{
|
||||
if ( !isdefined( entity.microwavePoisoning ) || !entity.microwavePoisoning )
|
||||
{
|
||||
entity.microwavePoisoning = true;
|
||||
entity.microwaveEffect = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// randomly wait a bit before applying intial damage to "stagger" it and prevent performance spikes
|
||||
if ( isdefined( entity.microwaveDamageInitialDelay ) )
|
||||
{
|
||||
wait RandomFloatRange( ( 0.1 ), ( 0.3 ) );
|
||||
entity.microwaveDamageInitialDelay = undefined;
|
||||
}
|
||||
|
||||
entity DoDamage( damage, // iDamage Integer specifying the amount of damage done
|
||||
turret.origin, // vPoint The point the damage is from?
|
||||
turret.owner, // eAttacker The entity that is attacking.
|
||||
turret.vehicle, // eInflictor The entity that causes the damage.(e.g. a turret)
|
||||
0,
|
||||
"MOD_TRIGGER_HURT", // sMeansOfDeath Integer specifying the method of death
|
||||
0, // iDFlags Integer specifying flags that are to be applied to the damage
|
||||
turretWeapon ); // Weapon The weapon used to inflict the damage
|
||||
|
||||
entity.microwaveEffect++;
|
||||
entity.lastMicrowavedBy = turret.owner;
|
||||
time = GetTime();
|
||||
|
||||
if( IsPlayer(entity) && !(entity IsRemoteControlling() ) )
|
||||
{
|
||||
if ( time - (isdefined(entity.microwaveShellshockAndViewKickTime)?entity.microwaveShellshockAndViewKickTime:0) > 950 ) // the time here ties in with the wait 0.5 below and the microwaveEffect % 2
|
||||
{
|
||||
if( entity.microwaveEffect % 2 == 1 )
|
||||
{
|
||||
if ( DistanceSquared( entity.origin, turret.origin ) > (( 750 ) * 2/3) * (( 750 ) * 2/3) )
|
||||
{
|
||||
entity shellshock( "mp_radiation_low", 1.5 * shellShockScalar );
|
||||
entity ViewKick( int( 25 * viewKickScalar ), turret.origin );
|
||||
}
|
||||
else if ( DistanceSquared( entity.origin, turret.origin ) > (( 750 ) * 1/3) * (( 750 ) * 1/3) )
|
||||
{
|
||||
entity shellshock( "mp_radiation_med", 1.5 * shellShockScalar );
|
||||
entity ViewKick( int( 50 * viewKickScalar ), turret.origin );
|
||||
}
|
||||
else
|
||||
{
|
||||
entity shellshock( "mp_radiation_high", 1.5 * shellShockScalar );
|
||||
entity ViewKick( int( 75 * viewKickScalar ), turret.origin );
|
||||
}
|
||||
|
||||
entity.microwaveShellshockAndViewKickTime = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( IsPlayer( entity ) && entity.microwaveEffect % 3 == 2 )
|
||||
{
|
||||
scoreevents::processScoreEvent( "hpm_suppress", turret.owner, entity, turretWeapon );
|
||||
}
|
||||
|
||||
wait 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
function MicrowaveTurretAffectsEntity( entity )
|
||||
{
|
||||
turret = self;
|
||||
|
||||
if( !IsAlive( entity ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !IsPlayer( entity ) && !IsAi( entity ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( entity.ignoreme === true )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if( isdefined( turret.carried ) && turret.carried )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( turret weaponobjects::isStunned() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( isdefined( turret.owner ) && entity == turret.owner )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !weaponobjects::friendlyFireCheck( turret.owner, entity, 0 ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( DistanceSquared( entity.origin, turret.origin ) > ( 750 ) * ( 750 ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
angles = turret.vehicle GetTagAngles( "tag_flash" );
|
||||
origin = turret.vehicle GetTagOrigin( "tag_flash" );
|
||||
|
||||
shoot_at_pos = entity GetShootAtPos( turret );
|
||||
|
||||
entDirection = vectornormalize( shoot_at_pos - origin );
|
||||
forward = AnglesToForward( angles ) ;
|
||||
dot = vectorDot( entDirection, forward );
|
||||
if( dot < cos( ( 15 ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( entity damageConeTrace( origin, turret, forward ) <= 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,534 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\_oob;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_killstreak_detect;
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
#namespace placeables;
|
||||
|
||||
|
||||
|
||||
|
||||
function SpawnPlaceable( killstreakRef, killstreakId,
|
||||
onPlaceCallback, onCancelCallback, onMoveCallback, onShutdownCallback, onDeathCallback, onEmpCallback,
|
||||
model, validModel, invalidModel, spawnsVehicle,
|
||||
pickupString,
|
||||
timeout,
|
||||
health,
|
||||
empDamage,
|
||||
placeHintString,
|
||||
invalidLocationHintString )
|
||||
{
|
||||
player = self;
|
||||
|
||||
self killstreaks::switch_to_last_non_killstreak_weapon();
|
||||
|
||||
placeable = spawn( "script_model", player.origin );
|
||||
placeable.cancelable = true;
|
||||
placeable.held = false;
|
||||
placeable.validModel = validModel;
|
||||
placeable.invalidModel = invalidModel;
|
||||
placeable.killstreakId = killstreakId;
|
||||
placeable.killstreakRef = killstreakRef;
|
||||
placeable.onCancel = onCancelCallback;
|
||||
placeable.onEmp = onEmpCallback;
|
||||
placeable.onMove = onMoveCallback;
|
||||
placeable.onPlace = onPlaceCallback;
|
||||
placeable.onShutdown = onShutdownCallback;
|
||||
placeable.onDeath = onDeathCallback;
|
||||
placeable.owner = player;
|
||||
placeable.originalOwner = player;
|
||||
placeable.ownerEntNum = player.entNum;
|
||||
placeable.originalOwnerEntNum = player.entNum;
|
||||
placeable.pickupString = pickupString;
|
||||
placeable.placedModel = model;
|
||||
placeable.spawnsVehicle = spawnsVehicle;
|
||||
|
||||
placeable.originalTeam = player.team;
|
||||
placeable.timedOut = false;
|
||||
placeable.timeout = timeout;
|
||||
placeable.timeoutStarted = false;
|
||||
placeable.angles = ( 0, player.angles[1], 0 );
|
||||
placeable.placeHintString = placeHintString;
|
||||
placeable.invalidLocationHintString = invalidLocationHintString;
|
||||
|
||||
if(!isdefined(placeable.placeHintString))placeable.placeHintString="";
|
||||
if(!isdefined(placeable.invalidLocationHintString))placeable.invalidLocationHintString="";
|
||||
|
||||
placeable NotSolid();
|
||||
if ( isdefined( placeable.vehicle ) )
|
||||
placeable.vehicle NotSolid();
|
||||
|
||||
placeable.otherModel = spawn( "script_model", player.origin );
|
||||
placeable.otherModel SetModel( placeable.placedModel );
|
||||
placeable.otherModel SetInvisibleToPlayer( player );
|
||||
placeable.otherModel NotSolid();
|
||||
placeable.otherModel clientfield::set( "enemyvehicle", 1 );
|
||||
|
||||
placeable killstreaks::configure_team( killstreakRef, killstreakId, player );
|
||||
|
||||
if( isdefined( health ) && health > 0 )
|
||||
{
|
||||
placeable.health = health;
|
||||
placeable SetCanDamage( false );
|
||||
placeable thread killstreaks::MonitorDamage( killstreakRef, health, &OnDeath, 0, undefined, empDamage, &OnEMP, true );
|
||||
}
|
||||
|
||||
player thread CarryPlaceable( placeable );
|
||||
level thread CancelOnGameEnd( placeable );
|
||||
|
||||
player thread ShutdownOnCancelEvent( placeable );
|
||||
player thread CancelOnPlayerDisconnect( placeable );
|
||||
|
||||
placeable thread WatchOwnerGameEvents();
|
||||
|
||||
return placeable;
|
||||
}
|
||||
|
||||
function UpdatePlacementModels( model, validModel, invalidModel )
|
||||
{
|
||||
placeable = self;
|
||||
placeable.placedModel = model;
|
||||
placeable.validModel = validModel;
|
||||
placeable.invalidModel = invalidModel;
|
||||
}
|
||||
|
||||
function CarryPlaceable( placeable )
|
||||
{
|
||||
player = self;
|
||||
|
||||
placeable Show();
|
||||
placeable NotSolid();
|
||||
if ( isdefined( placeable.vehicle ) )
|
||||
placeable.vehicle NotSolid();
|
||||
|
||||
if ( isdefined( placeable.otherModel ) )
|
||||
{
|
||||
placeable thread util::ghost_wait_show_to_player( player, 0.05, "abort_ghost_wait_show" );
|
||||
placeable.otherModel thread util::ghost_wait_show_to_others( player, 0.05, "abort_ghost_wait_show" );
|
||||
placeable.otherModel NotSolid();
|
||||
}
|
||||
|
||||
placeable.held = true;
|
||||
player.holding_placeable = placeable;
|
||||
|
||||
player CarryTurret( placeable, ( 40, 0, 0 ), ( 0, 0, 0 ) );
|
||||
player util::_disableWeapon();
|
||||
player thread WatchPlacement( placeable );
|
||||
}
|
||||
|
||||
function InNoPlacementTrigger()
|
||||
{
|
||||
placeable = self;
|
||||
|
||||
if( isdefined( level.noTurretPlacementTriggers ) )
|
||||
{
|
||||
for( i = 0; i < level.noTurretPlacementTriggers.size; i++ )
|
||||
{
|
||||
if( placeable IsTouching( level.noTurretPlacementTriggers[i] ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( isdefined( level.fatal_triggers ) )
|
||||
{
|
||||
for( i = 0; i < level.fatal_triggers.size; i++ )
|
||||
{
|
||||
if( placeable IsTouching( level.fatal_triggers[i] ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( placeable oob::IsTouchingAnyOOBTrigger() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function WatchPlacement( placeable )
|
||||
{
|
||||
player = self;
|
||||
|
||||
player endon( "disconnect" );
|
||||
player endon( "death" );
|
||||
placeable endon( "placed" );
|
||||
placeable endon( "cancelled" );
|
||||
|
||||
player thread WatchCarryCancelEvents( placeable );
|
||||
|
||||
lastAttempt = -1;
|
||||
placeable.canBePlaced = false;
|
||||
waitingForAttackButtonRelease = true;
|
||||
|
||||
while( true )
|
||||
{
|
||||
placement = player CanPlayerPlaceTurret();
|
||||
|
||||
placeable.origin = placement["origin"];
|
||||
placeable.angles = placement["angles"];
|
||||
placeable.canBePlaced = placement["result"] && !( placeable InNoPlacementTrigger() );
|
||||
|
||||
if ( player.laststand === true )
|
||||
{
|
||||
placeable.canBePlaced = false;
|
||||
}
|
||||
|
||||
if ( isdefined( placeable.otherModel ) )
|
||||
{
|
||||
placeable.otherModel.origin = placement["origin"];
|
||||
placeable.otherModel.angles = placement["angles"];
|
||||
}
|
||||
|
||||
if( placeable.canBePlaced != lastAttempt )
|
||||
{
|
||||
if( placeable.canBePlaced )
|
||||
{
|
||||
placeable SetModel( placeable.validModel );
|
||||
player SetHintString( IString( placeable.placeHintString ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
placeable SetModel( placeable.invalidModel );
|
||||
player SetHintString( IString( placeable.invalidLocationHintString ) );
|
||||
}
|
||||
|
||||
lastAttempt = placeable.canBePlaced;
|
||||
}
|
||||
|
||||
while( waitingForAttackButtonRelease && !player AttackButtonPressed() )
|
||||
{
|
||||
waitingForAttackButtonRelease = false;
|
||||
}
|
||||
|
||||
if( !waitingForAttackButtonRelease && placeable.canBePlaced && player AttackButtonPressed() )
|
||||
{
|
||||
if( placement["result"] )
|
||||
{
|
||||
placeable.origin = placement["origin"];
|
||||
placeable.angles = placement["angles"];
|
||||
|
||||
player SetHintString( "" );
|
||||
player StopCarryTurret( placeable );
|
||||
|
||||
if( !player util::isWeaponEnabled() )
|
||||
{
|
||||
player util::_enableWeapon();
|
||||
}
|
||||
|
||||
placeable.held = false;
|
||||
player.holding_placeable = undefined;
|
||||
placeable.cancelable = false;
|
||||
|
||||
if( ( isdefined( placeable.health ) && placeable.health ) )
|
||||
{
|
||||
placeable SetCanDamage( true );
|
||||
placeable Solid();
|
||||
}
|
||||
|
||||
if ( isdefined( placeable.vehicle ) )
|
||||
{
|
||||
placeable.vehicle SetCanDamage( true );
|
||||
placeable.vehicle Solid();
|
||||
}
|
||||
|
||||
if( isdefined( placeable.placedModel ) && !placeable.spawnsVehicle )
|
||||
{
|
||||
placeable SetModel( placeable.placedModel );
|
||||
}
|
||||
else
|
||||
{
|
||||
placeable notify( "abort_ghost_wait_show" );
|
||||
placeable.abort_ghost_wait_show_to_player = true;
|
||||
placeable.abort_ghost_wait_show_to_others = true;
|
||||
placeable Ghost(); // need to ghost instead of hide because of resulting issue with client side animations
|
||||
|
||||
if ( isdefined( placeable.otherModel ) )
|
||||
{
|
||||
placeable.otherModel notify( "abort_ghost_wait_show" );
|
||||
placeable.otherModel.abort_ghost_wait_show_to_player = true;
|
||||
placeable.otherModel.abort_ghost_wait_show_to_others = true;
|
||||
placeable.otherModel Ghost(); // need to ghost instead of hide because of resulting issue with client side animations
|
||||
}
|
||||
}
|
||||
|
||||
if( isdefined( placeable.timeout ) )
|
||||
{
|
||||
if( !placeable.timeoutStarted )
|
||||
{
|
||||
placeable.timeoutStarted = true;
|
||||
placeable thread killstreaks::WaitForTimeout( placeable.killstreakRef, placeable.timeout, &OnTimeout, "death", "cancelled" );
|
||||
}
|
||||
else if( placeable.timedOut )
|
||||
{
|
||||
placeable thread killstreaks::WaitForTimeout( placeable.killstreakRef, 5000, &OnTimeout, "cancelled" );
|
||||
}
|
||||
}
|
||||
|
||||
if( isdefined( placeable.onPlace ) )
|
||||
{
|
||||
player [[ placeable.onPlace ]]( placeable );
|
||||
if( isdefined( placeable.onMove ) && !placeable.timedOut )
|
||||
{
|
||||
SpawnMoveTrigger( placeable, player );
|
||||
}
|
||||
}
|
||||
|
||||
placeable notify( "placed" );
|
||||
}
|
||||
}
|
||||
|
||||
if( placeable.cancelable && player ActionSlotFourButtonPressed() )
|
||||
{
|
||||
placeable notify( "cancelled" );
|
||||
}
|
||||
|
||||
{wait(.05);};
|
||||
}
|
||||
}
|
||||
|
||||
function WatchCarryCancelEvents( placeable )
|
||||
{
|
||||
player = self;
|
||||
assert( IsPlayer( player ) );
|
||||
|
||||
placeable endon( "cancelled" );
|
||||
placeable endon( "placed" );
|
||||
|
||||
player util::waittill_any( "death", "emp_jammed", "emp_grenaded", "disconnect", "joined_team" );
|
||||
placeable notify( "cancelled" );
|
||||
}
|
||||
|
||||
function OnTimeout()
|
||||
{
|
||||
placeable = self;
|
||||
if( ( isdefined( placeable.held ) && placeable.held ) )
|
||||
{
|
||||
placeable.timedOut = true;
|
||||
return;
|
||||
}
|
||||
|
||||
placeable notify( "delete_placeable_trigger" );
|
||||
placeable thread killstreaks::WaitForTimeout( placeable.killstreakRef, 5000, &ForceShutdown, "cancelled" );
|
||||
}
|
||||
|
||||
function OnDeath( attacker, weapon )
|
||||
{
|
||||
placeable = self;
|
||||
|
||||
if( isdefined( placeable.onDeath ) )
|
||||
{
|
||||
[[ placeable.onDeath ]]( attacker, weapon );
|
||||
}
|
||||
|
||||
placeable notify( "cancelled" );
|
||||
}
|
||||
|
||||
function OnEMP( attacker )
|
||||
{
|
||||
placeable = self;
|
||||
|
||||
if( isdefined( placeable.onEmp ) )
|
||||
{
|
||||
placeable [[ placeable.onEmp ]]( attacker );
|
||||
}
|
||||
}
|
||||
|
||||
function CancelOnPlayerDisconnect( placeable )
|
||||
{
|
||||
placeable endon( "hacked" );
|
||||
|
||||
player = self;
|
||||
assert( IsPlayer( player ) );
|
||||
|
||||
placeable endon( "cancelled" );
|
||||
placeable endon( "death" );
|
||||
|
||||
player util::waittill_any( "disconnect", "joined_team" );
|
||||
placeable notify( "cancelled" );
|
||||
}
|
||||
|
||||
function CancelOnGameEnd( placeable )
|
||||
{
|
||||
placeable endon( "cancelled" );
|
||||
placeable endon( "death" );
|
||||
|
||||
level waittill( "game_ended" );
|
||||
placeable notify( "cancelled" );
|
||||
}
|
||||
|
||||
function SpawnMoveTrigger( placeable, player )
|
||||
{
|
||||
pos = placeable.origin + ( 0, 0, 15 );
|
||||
placeable.pickupTrigger = spawn( "trigger_radius_use", pos );
|
||||
placeable.pickupTrigger SetCursorHint( "HINT_NOICON", placeable );
|
||||
placeable.pickupTrigger SetHintString( placeable.pickupString );
|
||||
placeable.pickupTrigger SetTeamForTrigger( player.team );
|
||||
|
||||
player ClientClaimTrigger( placeable.pickupTrigger );
|
||||
placeable thread WatchPickup( player);
|
||||
placeable.pickupTrigger thread WatchMoveTriggerShutdown( placeable );
|
||||
}
|
||||
|
||||
function WatchMoveTriggerShutdown( placeable )
|
||||
{
|
||||
trigger = self;
|
||||
placeable util::waittill_any( "cancelled", "picked_up", "death", "delete_placeable_trigger", "hacker_delete_placeable_trigger" );
|
||||
placeable.pickupTrigger delete();
|
||||
}
|
||||
|
||||
function WatchPickup( player )
|
||||
{
|
||||
placeable = self;
|
||||
placeable endon( "death" );
|
||||
placeable endon( "cancelled" );
|
||||
|
||||
assert( isdefined( placeable.pickupTrigger ) );
|
||||
trigger = placeable.pickupTrigger;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
trigger waittill( "trigger", player );
|
||||
|
||||
if( !isAlive( player ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( player isUsingOffhand() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !player isOnGround() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( isdefined( placeable.vehicle ) && ( placeable.vehicle.control_initiated === true ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( isdefined( player.carryObject ) && player.carryObject.disallowPlaceablePickup === true )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( isdefined( trigger.triggerTeam ) && ( player.team != trigger.triggerTeam ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( isdefined( trigger.claimedBy ) && ( player != trigger.claimedBy ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( player useButtonPressed() && !player.throwingGrenade && !player meleeButtonPressed() && !player attackButtonPressed() &&
|
||||
!( isdefined( player.isPlanting ) && player.isPlanting ) && !( isdefined( player.isDefusing ) && player.isDefusing ) && !player IsRemoteControlling() && !isdefined( player.holding_placeable ) )
|
||||
{
|
||||
placeable notify( "picked_up" );
|
||||
placeable.held = true;
|
||||
placeable SetCanDamage( false );
|
||||
assert( isdefined( placeable.onMove ) );
|
||||
player [[ placeable.onMove ]]( placeable );
|
||||
player thread CarryPlaceable( placeable );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ForceShutdown()
|
||||
{
|
||||
placeable = self;
|
||||
placeable.cancelable = false;
|
||||
placeable notify( "cancelled" );
|
||||
}
|
||||
|
||||
function WatchOwnerGameEvents()
|
||||
{
|
||||
self notify("WatchOwnerGameEvents_singleton");
|
||||
self endon ("WatchOwnerGameEvents_singleton");
|
||||
|
||||
placeable = self;
|
||||
placeable endon( "cancelled" );
|
||||
|
||||
placeable.owner util::waittill_any( "joined_team", "disconnect", "joined_spectators" );
|
||||
|
||||
if ( isdefined( placeable ) )
|
||||
{
|
||||
placeable.abandoned = true;
|
||||
placeable ForceShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
function ShutdownOnCancelEvent( placeable )
|
||||
{
|
||||
placeable endon( "hacked" );
|
||||
|
||||
player = self;
|
||||
assert( IsPlayer( player ) );
|
||||
|
||||
placeable util::waittill_any( "cancelled", "death" );
|
||||
|
||||
if( isdefined( player ) && isdefined( placeable ) && ( placeable.held === true ) )
|
||||
{
|
||||
player SetHintString( "" );
|
||||
player StopCarryTurret( placeable );
|
||||
|
||||
if( !player util::isWeaponEnabled() )
|
||||
{
|
||||
player util::_enableWeapon();
|
||||
}
|
||||
}
|
||||
|
||||
if( isdefined( placeable ) )
|
||||
{
|
||||
if( placeable.cancelable )
|
||||
{
|
||||
if( isdefined( placeable.onCancel ) )
|
||||
{
|
||||
[[ placeable.onCancel ]]( placeable );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( isdefined( placeable.onShutdown ) )
|
||||
{
|
||||
[[ placeable.onShutdown ]]( placeable );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isdefined( placeable ) )
|
||||
{
|
||||
if ( isdefined( placeable.vehicle ) )
|
||||
{
|
||||
vehicle_to_kill = placeable.vehicle;
|
||||
vehicle_to_kill.selfDestruct = true;
|
||||
vehicle_to_kill Kill(); // need to kill the vehicle before placeable is deleted
|
||||
placeable.vehicle = undefined;
|
||||
placeable.otherModel delete();
|
||||
placeable delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
placeable.otherModel delete();
|
||||
placeable delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#precache( "client_fx", "killstreaks/fx_ls_exhaust_afterburner" );
|
||||
|
||||
#namespace planemortar;
|
||||
|
||||
function autoexec __init__sytem__() { system::register("planemortar",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
level.planeMortarExhaustFX = "killstreaks/fx_ls_exhaust_afterburner";
|
||||
|
||||
clientfield::register( "scriptmover", "planemortar_contrail", 1, 1, "int",&planemortar_contrail, !true, !true );
|
||||
}
|
||||
|
||||
function planemortar_contrail( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
self endon( "death" );
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
if ( newVal )
|
||||
{
|
||||
self.fx = PlayFXOnTag( localClientNum, level.planeMortarExhaustFX, self, "tag_fx" );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\challenges_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\scoreevents_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
|
||||
#using scripts\mp\_challenges;
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\gametypes\_battlechatter;
|
||||
#using scripts\mp\gametypes\_globallogic_audio;
|
||||
#using scripts\mp\gametypes\_spawning;
|
||||
#using scripts\mp\killstreaks\_airsupport;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_satellite;
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#precache( "locationselector", "map_mortar_selector" );
|
||||
#precache( "locationselector", "map_mortar_selector_done" );
|
||||
#precache( "string", "MP_EARNED_PLANEMORTAR" );
|
||||
#precache( "string", "KILLSTREAK_PLANEMORTAR_NOT_AVAILABLE" );
|
||||
#precache( "string", "MP_WAR_PLANEMORTAR_INBOUND" );
|
||||
#precache( "string", "MP_WAR_PLANEMORTAR_INBOUND_NEAR_YOUR_POSITION" );
|
||||
#precache( "string", "KILLSTREAK_PLANEMORTAR_HACKED" );
|
||||
#precache( "eventstring", "mpl_killstreak_planemortar" );
|
||||
#precache( "fx", "killstreaks/fx_ls_exhaust_afterburner" );
|
||||
|
||||
#namespace planemortar;
|
||||
|
||||
function init()
|
||||
{
|
||||
level.planeMortarExhaustFX = "killstreaks/fx_ls_exhaust_afterburner";
|
||||
clientfield::register( "scriptmover", "planemortar_contrail", 1, 1, "int" );
|
||||
killstreaks::register( "planemortar", "planemortar", "killstreak_planemortar", "planemortar_used",&useKillstreakPlaneMortar, true );
|
||||
killstreaks::register_strings( "planemortar", &"MP_EARNED_PLANEMORTAR", &"KILLSTREAK_PLANEMORTAR_NOT_AVAILABLE", &"MP_WAR_PLANEMORTAR_INBOUND", &"MP_WAR_PLANEMORTAR_INBOUND_NEAR_YOUR_POSITION", &"KILLSTREAK_PLANEMORTAR_HACKED" );
|
||||
killstreaks::register_dialog( "planemortar", "mpl_killstreak_planemortar", "planeMortarDialogBundle", "planeMortarPilotDialogBundle", "friendlyPlaneMortar", "enemyPlaneMortar", "enemyPlaneMortarMultiple", "friendlyPlaneMortarHacked", "enemyPlaneMortarHacked", "requestPlaneMortar" );
|
||||
killstreaks::set_team_kill_penalty_scale( "planemortar", level.teamKillReducedPenalty );
|
||||
}
|
||||
|
||||
function useKillstreakPlaneMortar( hardpointType )
|
||||
{
|
||||
if ( self killstreakrules::isKillstreakAllowed( hardpointType, self.team ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result = self selectPlaneMortarLocation( hardpointType );
|
||||
|
||||
if ( !isdefined( result ) || !result )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function waittill_confirm_location()
|
||||
{
|
||||
self endon( "emp_jammed" );
|
||||
self endon( "emp_grenaded" );
|
||||
|
||||
self waittill( "confirm_location", location );
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
function selectPlaneMortarLocation( hardpointType )
|
||||
{
|
||||
self beginLocationMortarSelection( "map_mortar_selector", 800, "map_mortar_selector_done" );
|
||||
self.selectingLocation = true;
|
||||
|
||||
self thread airsupport::endSelectionThink();
|
||||
|
||||
locations = [];
|
||||
if (!isdefined(self.pers["mortarRadarUsed"]) || !self.pers["mortarRadarUsed"])
|
||||
{
|
||||
self thread singleRadarSweep();
|
||||
|
||||
otherTeam = util::getOtherTeam( self.team );
|
||||
globallogic_audio::leader_dialog( "enemyPlaneMortarUsed", otherTeam );
|
||||
}
|
||||
|
||||
for ( i = 0 ; i < 3 ; i++ )
|
||||
{
|
||||
location = self waittill_confirm_location();
|
||||
|
||||
// if the player gets disconnected, self will be undefined
|
||||
if( !isdefined( self ) )
|
||||
return false;
|
||||
|
||||
if ( !isdefined( location ) )
|
||||
{
|
||||
self.pers["mortarRadarUsed"] = true;
|
||||
self notify("cancel_selection");
|
||||
// selection was canceled
|
||||
return false;
|
||||
}
|
||||
|
||||
locations[i] = location;
|
||||
}
|
||||
|
||||
if ( self killstreakrules::isKillstreakAllowed( hardpointType, self.team ) == false)
|
||||
{
|
||||
self.pers["mortarRadarUsed"] = true;
|
||||
self notify("cancel_selection");
|
||||
return false;
|
||||
}
|
||||
|
||||
self.pers["mortarRadarUsed"] = false;
|
||||
|
||||
return self airsupport::finishHardpointLocationUsage( locations,&usePlaneMortar );
|
||||
}
|
||||
|
||||
function waitPlayBackTime( soundAlias )
|
||||
{
|
||||
self endon ( "death" );
|
||||
self endon ( "disconnect" );
|
||||
|
||||
playbackTime = soundgetplaybacktime ( soundAlias );
|
||||
|
||||
if ( playbackTime >= 0 )
|
||||
{
|
||||
waitTime = playbackTime * .001;
|
||||
|
||||
wait ( waitTime );
|
||||
}
|
||||
else
|
||||
{
|
||||
wait ( 1.0 );
|
||||
}
|
||||
self notify ( soundAlias );
|
||||
}
|
||||
|
||||
function singleRadarSweep()
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
self endon("cancel_selection");
|
||||
|
||||
// give a bit for the map to come up
|
||||
wait(0.5);
|
||||
|
||||
self PlayLocalSound("mpl_killstreak_satellite");
|
||||
|
||||
if ( level.teamBased )
|
||||
{
|
||||
has_satellite = satellite::HasSatellite( self.team );
|
||||
}
|
||||
else
|
||||
{
|
||||
has_satellite = satellite::HasSatellite( self.entnum );
|
||||
}
|
||||
|
||||
if (self.hasSpyplane == 0 && !has_satellite && !level.forceRadar )
|
||||
{
|
||||
self thread doRadarSweep();
|
||||
}
|
||||
}
|
||||
|
||||
function doRadarSweep()
|
||||
{
|
||||
self setClientUIVisibilityFlag( "g_compassShowEnemies", 1 );
|
||||
|
||||
wait ( 0.2 );
|
||||
|
||||
self setClientUIVisibilityFlag( "g_compassShowEnemies", 0 );
|
||||
}
|
||||
|
||||
function usePlaneMortar( positions )
|
||||
{
|
||||
team = self.team;
|
||||
killstreak_id = self killstreakrules::killstreakStart( "planemortar", team, false, true );
|
||||
if ( killstreak_id == -1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
self killstreaks::play_killstreak_start_dialog( "planemortar", team, killstreak_id );
|
||||
|
||||
self.planeMortarPilotIndex = killstreaks::get_random_pilot_index( "planemortar" );
|
||||
self killstreaks::play_pilot_dialog( "arrive", "planemortar", undefined, self.planeMortarPilotIndex );
|
||||
|
||||
self AddWeaponStat( GetWeapon( "planemortar" ), "used", 1 );
|
||||
self thread planeMortar_watchForEndNotify( team, killstreak_id );
|
||||
self thread doPlaneMortar( positions, team, killstreak_id );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function doPlaneMortar( positions, team, killstreak_id )
|
||||
{
|
||||
self endon( "emp_jammed" );
|
||||
self endon( "disconnect" );
|
||||
|
||||
yaw = RandomIntRange( 0,360 );
|
||||
odd = 0;
|
||||
wait ( 1.25 );
|
||||
foreach( position in positions )
|
||||
{
|
||||
level spawning::create_enemy_influencer( "artillery", position, team );
|
||||
self thread doBombRun( position, yaw, team );
|
||||
|
||||
if (odd == 0)
|
||||
{
|
||||
yaw = ( yaw + 35 ) % 360;
|
||||
}
|
||||
else
|
||||
{
|
||||
yaw = ( yaw + 290 ) % 360;
|
||||
}
|
||||
odd = ( odd + 1 ) % 2;
|
||||
|
||||
wait 0.8;
|
||||
}
|
||||
|
||||
self notify( "planemortarcomplete" );
|
||||
wait ( 1 );
|
||||
self thread plane_mortar_bda_dialog();
|
||||
}
|
||||
|
||||
function plane_mortar_bda_dialog()
|
||||
{
|
||||
if ( isdefined( self.planeMortarBda ) )
|
||||
{
|
||||
if (self.planeMortarBda === 1)
|
||||
{
|
||||
bdaDialog = "kill1";
|
||||
}
|
||||
else if (self.planeMortarBda === 2)
|
||||
{
|
||||
bdaDialog = "kill2";
|
||||
}
|
||||
else if (self.planeMortarBda === 3)
|
||||
{
|
||||
bdaDialog = "kill3";
|
||||
}
|
||||
else if (isdefined( self.planeMortarBda ) && self.planeMortarBda > 3)
|
||||
{
|
||||
bdaDialog = "killMultiple";
|
||||
}
|
||||
|
||||
self killstreaks::play_pilot_dialog( bdaDialog, "planemortar", undefined, self.planeMortarPilotIndex );
|
||||
|
||||
if ( battlechatter::dialog_chance( "taacomPilotKillConfirmChance" ) )
|
||||
{
|
||||
self killstreaks::play_taacom_dialog_response( "killConfirmed", "planemortar", undefined, self.planeMortarPilotIndex );
|
||||
}
|
||||
else
|
||||
{
|
||||
self globallogic_audio::play_taacom_dialog( "confirmHit" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
killstreaks::play_pilot_dialog( "killNone", "planemortar", undefined, self.planeMortarPilotIndex );
|
||||
globallogic_audio::play_taacom_dialog( "confirmMiss" );
|
||||
}
|
||||
|
||||
self.planeMortarBda = undefined;
|
||||
}
|
||||
|
||||
function planeMortar_watchForEndNotify( team, killstreak_id )
|
||||
{
|
||||
self util::waittill_any( "disconnect", "joined_team", "joined_spectators", "planemortarcomplete", "emp_jammed" );
|
||||
|
||||
planeMortar_killstreakStop( team, killstreak_id );
|
||||
}
|
||||
|
||||
function planeMortar_killstreakStop( team, killstreak_id )
|
||||
{
|
||||
killstreakrules::killstreakStop( "planemortar", team, killstreak_id );
|
||||
}
|
||||
|
||||
|
||||
function doBombRun( position, yaw, team )
|
||||
{
|
||||
self endon( "emp_jammed" );
|
||||
player = self;
|
||||
|
||||
angles = (0,yaw,0);
|
||||
direction = AnglesToForward( angles );
|
||||
|
||||
height = airsupport::getMinimumFlyHeight() + 2000;
|
||||
position = ( position[0], position[1], height );
|
||||
startPoint = position + VectorScale( direction, -1 * 12000 );
|
||||
endPoint = position + VectorScale( direction, 12000 * 1.5 );
|
||||
height = airsupport::getNoFlyZoneHeightCrossed( startPoint, endPoint, height );
|
||||
startPoint = ( startPoint[0], startPoint[1], height );
|
||||
position = ( position[0], position[1], height );
|
||||
endPoint = ( endPoint[0], endPoint[1], height );
|
||||
|
||||
plane = SpawnPlane( self, "script_model", startPoint );
|
||||
plane.team = team;
|
||||
plane.targetname = "plane_mortar";
|
||||
plane.owner = self;
|
||||
|
||||
plane endon( "delete" );
|
||||
plane endon( "death" );
|
||||
|
||||
plane thread planeWatchForEmp( self );
|
||||
|
||||
plane.angles = angles;
|
||||
plane SetModel( "veh_t7_mil_vtol_fighter_mp" );
|
||||
plane SetEnemyModel( "veh_t7_mil_vtol_fighter_mp_dark" );
|
||||
plane clientfield::set( "planemortar_contrail", 1 );
|
||||
plane clientfield::set( "enemyvehicle", 1 );
|
||||
plane playsound( "mpl_lightning_flyover_boom" );
|
||||
plane SetDrawInfrared( true );
|
||||
|
||||
plane.killcamEnt = spawn( "script_model", plane.origin+(0,0,700)+VectorScale( direction, -1 * 1500 ) );
|
||||
plane.killcamEnt util::deleteAfterTime( ( 12000 * 2 / 12000 ) * 3 );
|
||||
plane.killcamEnt.angles = (15,yaw,0);
|
||||
plane.killcamEnt.startTime = gettime();
|
||||
plane.killcamEnt LinkTo( plane );
|
||||
start = (position[0], position[1], plane.origin[2]);
|
||||
impact = BulletTrace( start, start + (0,0,-100000), true, plane);
|
||||
|
||||
plane MoveTo( endpoint, ( 12000 * 2 / 12000 ) * 5/4, 0, 0 );
|
||||
|
||||
plane.killcamEnt thread followBomb( plane, position, direction, impact, player );
|
||||
|
||||
wait ( ( 12000 * 2 / 12000 ) /2 );
|
||||
if ( isdefined ( self ) )
|
||||
{
|
||||
self thread dropBomb( plane, position );
|
||||
}
|
||||
|
||||
wait ( ( 12000 * 2 / 12000 ) * 3/4 );
|
||||
plane Plane_CleanUpOnDeath();
|
||||
}
|
||||
|
||||
function followBomb( plane, position, direction, impact, player )
|
||||
{
|
||||
player endon( "emp_jammed" );
|
||||
|
||||
wait ( ( 12000 * 2 / 12000 ) * 5 / 12 );
|
||||
plane.killcamEnt Unlink();
|
||||
plane.killcamEnt MoveTo( impact["position"] + (0,0,1000) + VectorScale( direction, -1 * 600 ), 0.8, 0, 0.2);
|
||||
}
|
||||
|
||||
function lookAtExplosion( bomb )
|
||||
{
|
||||
while (isdefined(self) && isdefined( bomb ))
|
||||
{
|
||||
angles = vectorToAngles( VectorNormalize( bomb.origin - self.origin ));
|
||||
self.angles = ( max(angles[0], 15), angles[1], angles[2] );
|
||||
{wait(.05);};
|
||||
}
|
||||
}
|
||||
|
||||
function planeWatchForEmp( owner )
|
||||
{
|
||||
self endon( "delete" );
|
||||
self endon( "death" );
|
||||
|
||||
self waittill( "emp_deployed", attacker );
|
||||
|
||||
thread planeAwardScoreEvent( attacker, self );
|
||||
|
||||
// possibly play destroyed effect
|
||||
self Plane_CleanUpOnDeath();
|
||||
}
|
||||
|
||||
|
||||
function planeAwardScoreEvent( attacker, plane )
|
||||
{
|
||||
attacker endon( "disconnect" );
|
||||
attacker notify( "planeAwardScoreEvent_singleton" );
|
||||
attacker endon( "planeAwardScoreEvent_singleton" );
|
||||
waittillframeend;
|
||||
|
||||
|
||||
if( isdefined( attacker ) && ( !isdefined( plane.owner ) || plane.owner util::IsEnemyPlayer( attacker ) ) )
|
||||
{
|
||||
challenges::destroyedAircraft( attacker, GetWeapon( "emp" ), false );
|
||||
scoreevents::processScoreEvent( "destroyed_plane_mortar", attacker, plane.owner, GetWeapon( "emp" ) );
|
||||
attacker challenges::addFlySwatterStat( GetWeapon( "emp" ), plane );
|
||||
}
|
||||
}
|
||||
|
||||
function Plane_CleanUpOnDeath()
|
||||
{
|
||||
self Delete();
|
||||
}
|
||||
|
||||
|
||||
function dropBomb( plane, bombPosition )
|
||||
{
|
||||
if ( !isdefined( plane.owner ) )
|
||||
return;
|
||||
|
||||
targets = getplayers();
|
||||
foreach( target in targets )
|
||||
{
|
||||
if( plane.owner util::IsEnemyPlayer(target) && Distance2DSquared( target.origin, bombPosition ) < 250000 )
|
||||
{
|
||||
if( BulletTracePassed( (target.origin[0], target.origin[1], plane.origin[2]), target.origin, false, plane) )
|
||||
{
|
||||
bombPosition = target.origin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bombPosition = (bombPosition[0],bombPosition[1],plane.origin[2]);
|
||||
bomb = self LaunchBomb( GetWeapon( "planemortar" ), bombPosition, (0,0,-5000) );
|
||||
bomb.soundmod = "heli";
|
||||
bomb playsound( "mpl_lightning_bomb_incoming" );
|
||||
bomb.killcamEnt = plane.killcamEnt;
|
||||
plane.killcamEnt thread lookAtExplosion( bomb );
|
||||
}
|
||||
@@ -0,0 +1,515 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\_vehicle;
|
||||
|
||||
|
||||
|
||||
// _qrdrone.csc
|
||||
// Sets up clientside behavior for the qrdrone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#precache( "client_fx", "killstreaks/fx_drgnfire_light_red_3p" );
|
||||
#precache( "client_fx", "killstreaks/fx_drgnfire_light_green_3p" );
|
||||
#precache( "client_fx", "killstreaks/fx_drgnfire_light_green_1p" );
|
||||
|
||||
#namespace qrdrone;
|
||||
|
||||
function autoexec __init__sytem__() { system::register("qrdrone",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
type = "qrdrone_mp";
|
||||
|
||||
clientfield::register( "helicopter", "qrdrone_state", 1, 3, "int",&stateChange, !true, !true );
|
||||
clientfield::register( "vehicle", "qrdrone_state", 1, 3, "int",&stateChange, !true, !true );
|
||||
|
||||
level._effect["qrdrone_enemy_light"] = "killstreaks/fx_drgnfire_light_red_3p";
|
||||
level._effect["qrdrone_friendly_light"] = "killstreaks/fx_drgnfire_light_green_3p";
|
||||
level._effect["qrdrone_viewmodel_light"] = "killstreaks/fx_drgnfire_light_green_1p";
|
||||
|
||||
// vehicle flags
|
||||
clientfield::register( "helicopter", "qrdrone_countdown", 1, 1, "int", &start_blink, !true, !true );
|
||||
clientfield::register( "helicopter", "qrdrone_timeout", 1, 1, "int", &final_blink, !true, !true );
|
||||
|
||||
clientfield::register( "vehicle", "qrdrone_countdown", 1, 1, "int", &start_blink, !true, !true );
|
||||
clientfield::register( "vehicle", "qrdrone_timeout", 1, 1, "int", &final_blink, !true, !true );
|
||||
clientfield::register( "vehicle", "qrdrone_out_of_range", 1, 1, "int", &out_of_range_update, !true, !true );
|
||||
|
||||
vehicle::add_vehicletype_callback( "qrdrone_mp",&spawned );
|
||||
}
|
||||
|
||||
function spawned( localClientNum ) // self == qrdrone
|
||||
{
|
||||
self util::waittill_dobj( localClientNum );
|
||||
|
||||
self thread restartFX( localClientNum, 0 );
|
||||
|
||||
self thread collisionHandler(localClientNum);
|
||||
self thread engineStutterHandler(localClientNum);
|
||||
self thread QRDrone_watch_distance();
|
||||
}
|
||||
|
||||
//******************************************************************
|
||||
// *
|
||||
// *
|
||||
//******************************************************************
|
||||
function stateChange( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
self endon("entityshutdown");
|
||||
self util::waittill_dobj( localClientNum );
|
||||
|
||||
self restartFX( localClientNum, newVal );
|
||||
}
|
||||
|
||||
//******************************************************************
|
||||
// *
|
||||
// *
|
||||
//******************************************************************
|
||||
function restartFX( localClientNum, blinkStage ) // self == qrdrone
|
||||
{
|
||||
self notify( "restart_fx" );
|
||||
|
||||
/#println( "Restart QRDrone FX: stage " + blinkStage );#/
|
||||
|
||||
switch( blinkStage )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
self spawn_solid_fx( localClientNum );
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
self.fx_interval = 1.0;
|
||||
self spawn_blinking_fx( localClientNum );
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
self.fx_interval = .133;
|
||||
self spawn_blinking_fx( localClientNum );
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
self notify( "stopfx" );
|
||||
self notify( "fx_death" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self thread watchRestartFX( localClientNum );
|
||||
}
|
||||
|
||||
//******************************************************************
|
||||
// *
|
||||
// *
|
||||
//******************************************************************
|
||||
function watchRestartFX( localClientNum )
|
||||
{
|
||||
self endon("entityshutdown");
|
||||
|
||||
level util::waittill_any( "demo_jump", "player_switch", "killcam_begin", "killcam_end" );
|
||||
|
||||
self restartFX( localClientNum, clientfield::get( "qrdrone_state" ));
|
||||
}
|
||||
|
||||
//******************************************************************
|
||||
// *
|
||||
// *
|
||||
//******************************************************************
|
||||
function spawn_solid_fx( localClientNum ) // self == qrdrone
|
||||
{
|
||||
if ( self IsLocalClientDriver( localClientNum ) )
|
||||
{
|
||||
fx_handle = playfxontag( localClientNum, level._effect["qrdrone_viewmodel_light"], self, "tag_body" );
|
||||
}
|
||||
else if ( self util::friend_not_foe( localClientNum ) )
|
||||
{
|
||||
fx_handle = playfxontag( localClientNum, level._effect["qrdrone_friendly_light"], self, "tag_body" );
|
||||
}
|
||||
else
|
||||
{
|
||||
fx_handle = playfxontag( localClientNum, level._effect["qrdrone_enemy_light"], self, "tag_body" );
|
||||
}
|
||||
|
||||
self thread cleanupFX( localClientNum, fx_handle );
|
||||
}
|
||||
|
||||
//******************************************************************
|
||||
// *
|
||||
// *
|
||||
//******************************************************************
|
||||
function spawn_blinking_fx( localClientNum )
|
||||
{
|
||||
self thread blink_fx_and_sound( localClientNum, "wpn_qr_alert" );
|
||||
}
|
||||
|
||||
//******************************************************************
|
||||
// *
|
||||
// *
|
||||
//******************************************************************
|
||||
function blink_fx_and_sound( localClientNum, soundAlias )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
self endon( "restart_fx" );
|
||||
self endon( "fx_death" );
|
||||
|
||||
if ( !isdefined( self.interval ) )
|
||||
{
|
||||
self.interval = 1.0;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
self PlaySound( localClientNum, soundAlias );
|
||||
|
||||
self spawn_solid_fx( localClientNum );
|
||||
util::server_wait( localClientNum, self.interval / 2);
|
||||
|
||||
self notify( "stopfx" );
|
||||
|
||||
util::server_wait( localClientNum, self.interval / 2);
|
||||
self.interval = (self.interval / 1.17);
|
||||
|
||||
if (self.interval < .1)
|
||||
{
|
||||
self.interval = .1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//******************************************************************
|
||||
// *
|
||||
// *
|
||||
//******************************************************************
|
||||
function cleanupFX( localClientNum, handle )
|
||||
{
|
||||
self util::waittill_any( "entityshutdown", "blink", "stopfx", "restart_fx" );
|
||||
stopfx( localClientNum, handle );
|
||||
}
|
||||
|
||||
function start_blink( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if (!newVal)
|
||||
return;
|
||||
|
||||
self notify("blink");
|
||||
}
|
||||
|
||||
// this second state is necessary so killcams show the appropriate "fast blink" state
|
||||
function final_blink( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if (!newVal)
|
||||
return;
|
||||
|
||||
self.interval = .133;
|
||||
}
|
||||
|
||||
function out_of_range_update( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
model = GetUIModel( GetUIModelForController( localClientNum ), "vehicle.outOfRange" );
|
||||
if ( isdefined( model ) )
|
||||
{
|
||||
SetUIModelValue( model, newVal );
|
||||
}
|
||||
}
|
||||
|
||||
function loop_local_sound( localClientNum, alias, interval, fx )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
self endon( "stopfx" );
|
||||
|
||||
level endon( "demo_jump" );
|
||||
level endon( "player_switch" );
|
||||
|
||||
// also playing the blinking light fx with the sound
|
||||
|
||||
if ( !isdefined( self.interval ) )
|
||||
{
|
||||
self.interval = interval;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
self PlaySound( localClientNum, alias );
|
||||
|
||||
self spawn_solid_fx( localClientNum );
|
||||
util::server_wait( localClientNum, self.interval / 2);
|
||||
|
||||
self notify( "stopfx" );
|
||||
|
||||
util::server_wait( localClientNum, self.interval / 2);
|
||||
self.interval = (self.interval / 1.17);
|
||||
|
||||
if (self.interval < .1)
|
||||
{
|
||||
self.interval = .1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function check_for_player_switch_or_time_jump( localClientNum )
|
||||
{
|
||||
self endon("entityshutdown");
|
||||
|
||||
level util::waittill_any( "demo_jump", "player_switch", "killcam_begin" );
|
||||
self notify( "stopfx" );
|
||||
|
||||
waittillframeend;
|
||||
|
||||
self thread blink_light( localClientNum );
|
||||
|
||||
if ( isdefined( self.blinkStartTime ) && self.blinkStartTime <= level.serverTime )
|
||||
{
|
||||
self.interval = 1;
|
||||
self thread start_blink( localClientNum, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
self spawn_solid_fx( localClientNum );
|
||||
}
|
||||
|
||||
self thread check_for_player_switch_or_time_jump( localClientNum );
|
||||
}
|
||||
|
||||
function blink_light( localClientNum )
|
||||
{
|
||||
self endon("entityshutdown");
|
||||
level endon( "demo_jump" );
|
||||
level endon( "player_switch" );
|
||||
level endon( "killcam_begin" );
|
||||
|
||||
self waittill("blink");
|
||||
|
||||
if ( !isdefined( self.blinkStartTime ) )
|
||||
{
|
||||
self.blinkStartTime = level.serverTime;
|
||||
}
|
||||
|
||||
if ( self IsLocalClientDriver( localClientNum ) )
|
||||
{
|
||||
self thread loop_local_sound( localClientNum, "wpn_qr_alert", 1, level._effect["qrdrone_viewmodel_light"] );
|
||||
}
|
||||
else if ( self util::friend_not_foe( localClientNum ) )
|
||||
{
|
||||
self thread loop_local_sound( localClientNum, "wpn_qr_alert", 1, level._effect["qrdrone_friendly_light"] );
|
||||
}
|
||||
else
|
||||
{
|
||||
self thread loop_local_sound( localClientNum, "wpn_qr_alert", 1, level._effect["qrdrone_enemy_light"] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function collisionHandler( localClientNum )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
self waittill( "veh_collision", hip, hitn, hit_intensity );
|
||||
|
||||
driver_local_client = self GetLocalClientDriver();
|
||||
|
||||
if( isdefined( driver_local_client ) )
|
||||
{
|
||||
//println( "veh_collision " + hit_intensity );
|
||||
player = getlocalplayer( driver_local_client );
|
||||
|
||||
if( isdefined( player ) )
|
||||
{
|
||||
// todo - play sound here also
|
||||
if( hit_intensity > 15 )
|
||||
{
|
||||
player PlayRumbleOnEntity( driver_local_client, "damage_heavy" );
|
||||
}
|
||||
else
|
||||
{
|
||||
player PlayRumbleOnEntity( driver_local_client, "damage_light" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function engineStutterHandler( localClientNum )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
self waittill( "veh_engine_stutter" );
|
||||
if ( self IsLocalClientDriver( localClientNum ) )
|
||||
{
|
||||
player = getlocalplayer( localClientNum );
|
||||
|
||||
if( isdefined( player ) )
|
||||
{
|
||||
player PlayRumbleOnEntity( localClientNum, "rcbomb_engine_stutter" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getMinimumFlyHeight()
|
||||
{
|
||||
if ( !isdefined( level.airsupportHeightScale ) )
|
||||
level.airsupportHeightScale = 1;
|
||||
|
||||
airsupport_height = struct::get( "air_support_height", "targetname");
|
||||
if ( isdefined(airsupport_height) )
|
||||
{
|
||||
planeFlyHeight = airsupport_height.origin[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
/#
|
||||
PrintLn("WARNING: Missing air_support_height entity in the map. Using default height.");
|
||||
#/
|
||||
// original system
|
||||
planeFlyHeight = 850;
|
||||
|
||||
if ( isdefined( level.airsupportHeightScale ) )
|
||||
{
|
||||
level.airsupportHeightScale = GetDvarInt( "scr_airsupportHeightScale", level.airsupportHeightScale );
|
||||
planeFlyHeight *= GetDvarInt( "scr_airsupportHeightScale", level.airsupportHeightScale );
|
||||
}
|
||||
|
||||
if ( isdefined( level.forceAirsupportMapHeight ) )
|
||||
{
|
||||
planeFlyHeight += level.forceAirsupportMapHeight;
|
||||
}
|
||||
}
|
||||
|
||||
return planeFlyHeight;
|
||||
}
|
||||
|
||||
function QRDrone_watch_distance()
|
||||
{
|
||||
self endon ("entityshutdown" );
|
||||
|
||||
qrdrone_height = struct::get( "qrdrone_height", "targetname");
|
||||
if ( isdefined(qrdrone_height) )
|
||||
{
|
||||
self.maxHeight = qrdrone_height.origin[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
self.maxHeight = int(getMinimumFlyHeight());
|
||||
}
|
||||
|
||||
self.maxDistance = 12800;
|
||||
|
||||
level.mapCenter = GetMapCenter();
|
||||
|
||||
self.minHeight = level.mapCenter[2] - 800;
|
||||
|
||||
// shouldn't be possible to start out of range, but just in case
|
||||
inRangePos = self.origin;
|
||||
|
||||
soundent = spawn (0, self.origin, "script_origin" );
|
||||
soundent linkto(self);
|
||||
|
||||
// end static on vehicle death
|
||||
self thread QRDrone_staticStopOnDeath( soundent );
|
||||
|
||||
// loop
|
||||
while ( true )
|
||||
{
|
||||
if ( !self QRDrone_in_range() )
|
||||
{
|
||||
// increase static with distance from exit point or distance to heli in proximity
|
||||
staticAlpha = 0;
|
||||
while ( !self QRDrone_in_range() )
|
||||
{
|
||||
if ( isdefined( self.heliInProximity ) )
|
||||
{
|
||||
dist = distance( self.origin, self.heliInProximity.origin );
|
||||
staticAlpha = 1 - ( (dist-150) / (300-150) );
|
||||
}
|
||||
else
|
||||
{
|
||||
dist = distance( self.origin, inRangePos );
|
||||
staticAlpha = min( 1, dist/200 );
|
||||
}
|
||||
|
||||
|
||||
// SOUND: put sound code here to change the volume of the static while the player is
|
||||
// in static. staticAlpha will be 0 - 1. 0 being no static, 1 being full static.
|
||||
|
||||
|
||||
sid = soundent playloopsound ( "veh_qrdrone_static_lp", .2 );
|
||||
self vehicle::set_static_amount( staticAlpha * 2 );
|
||||
|
||||
wait ( 0.05 );
|
||||
}
|
||||
|
||||
|
||||
// fade out static
|
||||
self thread QRDrone_staticFade( staticAlpha, soundent, sid );
|
||||
|
||||
}
|
||||
inRangePos = self.origin;
|
||||
wait ( 0.05 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function QRDrone_in_range()
|
||||
{
|
||||
if ( self.origin[2] < self.maxHeight && self.origin[2] > self.minHeight )
|
||||
{
|
||||
if ( self isInsideHeightLock() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function QRDrone_staticFade( staticAlpha, sndent, sid )
|
||||
{
|
||||
self endon ( "entityshutdown" );
|
||||
while( self QRDrone_in_range() )
|
||||
{
|
||||
staticAlpha -= 0.05;
|
||||
if ( staticAlpha <= 0 )
|
||||
{
|
||||
// SOUND: Put call here to completely turn static sound off
|
||||
sndent StopAllLoopSounds (.5);
|
||||
//delete sid;
|
||||
self vehicle::set_static_amount( 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
// SOUND: Put call here to change volume of static based on staticAlpha
|
||||
setsoundvolumerate( sid, .6 );
|
||||
setsoundvolume( sid, staticAlpha );
|
||||
|
||||
self vehicle::set_static_amount( staticAlpha * 2 );
|
||||
|
||||
|
||||
wait( 0.05 );
|
||||
}
|
||||
}
|
||||
|
||||
function QRDrone_staticStopOnDeath( sndent )
|
||||
{
|
||||
self waittill ( "entityshutdown" );
|
||||
sndent StopAllLoopSounds (.1);
|
||||
sndent delete();
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,121 @@
|
||||
Line truncated
|
||||
|
||||
|
||||
#using scripts\codescripts\struct;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\vehicles\_raps;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
|
||||
|
||||
|
||||
#precache( "client_fx", "killstreaks/fx_heli_raps_exp_trail" );
|
||||
|
||||
#namespace raps_mp;
|
||||
|
||||
|
||||
|
||||
|
||||
function autoexec __init__sytem__() { system::register("raps_mp",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
clientfield::register( "vehicle", "monitor_raps_drop_landing", 1, 1, "int", &monitor__drop_landing_changed, !true, !true );
|
||||
clientfield::register( "vehicle", "raps_heli_low_health", 1, 1, "int", &heli_low_health_fx, !true, !true );
|
||||
clientfield::register( "vehicle", "raps_heli_extra_low_health", 1, 1, "int", &heli_extra_low_health_fx, !true, !true );
|
||||
}
|
||||
|
||||
|
||||
function heli_low_health_fx( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( newVal == 0 )
|
||||
return;
|
||||
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
vehicle::wait_for_DObj( localClientNum );
|
||||
|
||||
PlayFxOnTag( localClientNum, "killstreaks/fx_heli_raps_exp_trail", self, "tag_fx_engine_left_front" );
|
||||
}
|
||||
|
||||
function heli_extra_low_health_fx( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( newVal == 0 )
|
||||
return;
|
||||
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
vehicle::wait_for_DObj( localClientNum );
|
||||
|
||||
PlayFxOnTag( localClientNum, "killstreaks/fx_heli_raps_exp_trail", self, "tag_fx_engine_right_back" );
|
||||
}
|
||||
|
||||
function monitor__drop_landing_changed( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( !newVal )
|
||||
return;
|
||||
|
||||
self thread monitor_drop_landing( localClientNum );
|
||||
}
|
||||
|
||||
function monitor_drop_landing( localClientNum )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
self notify( "monitor_drop_landing_entity_singleton" );
|
||||
self endon( "monitor_drop_landing_entity_singleton" );
|
||||
|
||||
a_trace = BulletTrace( self.origin + ( 0, 0, -200 ), self.origin + ( 0, 0, -5000 ), false, self, true );
|
||||
v_ground = a_trace[ "position" ];
|
||||
|
||||
wait 0.5; // gain some speed
|
||||
whoosh_distance = 0;
|
||||
|
||||
if( isdefined( v_ground ) )
|
||||
{
|
||||
// there is a "whoosh" sound just before the actual impact, so we need to detect the distance
|
||||
not_close_enough_to_ground = true;
|
||||
|
||||
while( not_close_enough_to_ground )
|
||||
{
|
||||
velocity = self GetVelocity();
|
||||
whoosh_distance = max( whoosh_distance, ( Abs( velocity[2] ) * ( 0.15 ) ) + ( 386.088 / 2.0 ) * ( 0.15 ) * ( 0.15 ) );
|
||||
whoosh_distance_squared = whoosh_distance * whoosh_distance;
|
||||
|
||||
distance_squared = DistanceSquared( self.origin, v_ground );
|
||||
|
||||
not_close_enough_to_ground = ( distance_squared > whoosh_distance_squared );
|
||||
|
||||
if ( not_close_enough_to_ground )
|
||||
{
|
||||
wait ( ( distance_squared > whoosh_distance_squared * 4 ) ? 0.1 : 0.05 );
|
||||
}
|
||||
}
|
||||
|
||||
self playsound( localClientNum, "veh_raps_first_land" );
|
||||
}
|
||||
|
||||
// wait close enough to play fx, and rumble ( or z velocity hits zero )
|
||||
while( ( DistanceSquared( self.origin, v_ground ) > 24 * 24 ) || ( velocity[2] <= 0.0 ) )
|
||||
{
|
||||
velocity = self GetVelocity();
|
||||
{wait(.016);};
|
||||
}
|
||||
|
||||
bundle = struct::get_script_bundle( "killstreak", "killstreak_" + "raps" );
|
||||
|
||||
if ( isdefined( bundle ) && isdefined( bundle.ksDropDeployLandSurfaceFxTable ) && isdefined( a_trace[ "surfacetype" ] ) )
|
||||
{
|
||||
fx_to_play = GetFXFromSurfaceTable( bundle.ksDropDeployLandSurfaceFxTable, a_trace[ "surfacetype" ] );
|
||||
if ( isdefined( fx_to_play ) )
|
||||
{
|
||||
PlayFX( localClientNum, fx_to_play, self.origin );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isdefined( bundle ) && isdefined( bundle.ksDropDeployLandFx ) )
|
||||
PlayFX( localClientNum, bundle.ksDropDeployLandFx, self.origin );
|
||||
|
||||
PlayRumbleOnPosition( localClientNum, "raps_land", self.origin );
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,303 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\math_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
#using scripts\shared\vehicles\_driving_fx;
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#using scripts\mp\_callbacks;
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\_vehicle;
|
||||
|
||||
// _rcbomb.csc
|
||||
// Sets up clientside behavior for the rcbomb
|
||||
|
||||
#precache( "client_fx", "killstreaks/fx_rcxd_lights_blinky" );
|
||||
#precache( "client_fx", "killstreaks/fx_rcxd_lights_solid" );
|
||||
#precache( "client_fx", "killstreaks/fx_rcxd_lights_red" );
|
||||
#precache( "client_fx", "killstreaks/fx_rcxd_lights_grn" );
|
||||
#precache( "client_fx", "_t6/weapon/grenade/fx_spark_disabled_rc_car" );
|
||||
|
||||
#namespace rcbomb;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function autoexec __init__sytem__() { system::register("rcbomb",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
level._effect["rcbomb_enemy_light"] = "killstreaks/fx_rcxd_lights_blinky";
|
||||
level._effect["rcbomb_friendly_light"] = "killstreaks/fx_rcxd_lights_solid";
|
||||
level._effect["rcbomb_enemy_light_blink"] = "killstreaks/fx_rcxd_lights_red";
|
||||
level._effect["rcbomb_friendly_light_blink"] = "killstreaks/fx_rcxd_lights_grn";
|
||||
level._effect["rcbomb_stunned"] = "_t6/weapon/grenade/fx_spark_disabled_rc_car";
|
||||
|
||||
level.rcBombBundle = struct::get_script_bundle( "killstreak", "killstreak_rcbomb" );
|
||||
|
||||
// vehicle flags
|
||||
clientfield::register( "vehicle", "rcbomb_stunned", 1, 1, "int", &callback::callback_stunned, !true, !true );
|
||||
|
||||
vehicle::add_vehicletype_callback( "rc_car_mp",&spawned );
|
||||
}
|
||||
|
||||
function spawned(localClientNum)
|
||||
{
|
||||
self thread demo_think( localClientNum );
|
||||
self thread stunnedHandler(localClientNum);
|
||||
self thread boost_think( localClientNum );
|
||||
self thread shutdown_think( localClientNum );
|
||||
|
||||
self.driving_fx_collision_override = &OnDrivingFxCollision;
|
||||
self.driving_fx_jump_landing_override = &OnDrivingFxJumpLanding;
|
||||
|
||||
self.killstreakBundle = level.rcBombBundle;
|
||||
}
|
||||
|
||||
function demo_think( localClientNum )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
if ( !IsDemoPlaying() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
level util::waittill_any( "demo_jump", "demo_player_switch" );
|
||||
self vehicle::lights_off( localClientNum );
|
||||
}
|
||||
}
|
||||
|
||||
function boost_blur( localClientNum )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
if ( isdefined( self.owner ) && self.owner isLocalPlayer() )
|
||||
{
|
||||
EnableSpeedBlur( localClientNum, GetDvarFloat( "scr_rcbomb_amount", 0.1 ), GetDvarFloat( "scr_rcbomb_inner_radius", 0.5 ), GetDvarFloat( "scr_rcbomb_outer_radius", 0.75 ), false, 0 );
|
||||
|
||||
wait( GetDvarFloat( "scr_rcbomb_duration", 1.0 ) );
|
||||
|
||||
DisableSpeedBlur( localClientNum );
|
||||
}
|
||||
}
|
||||
|
||||
function boost_think( localClientNum )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
self waittill( "veh_boost" );
|
||||
self boost_blur( localClientNum );
|
||||
}
|
||||
}
|
||||
|
||||
function shutdown_think( localClientNum )
|
||||
{
|
||||
self waittill( "entityshutdown" );
|
||||
DisableSpeedBlur( localClientNum );
|
||||
}
|
||||
|
||||
function play_screen_fx_dirt(localClientNum)
|
||||
{
|
||||
// support for this has been removed with the .menu system
|
||||
/*
|
||||
pick_one = RandomIntRange(0,4);
|
||||
if ( pick_one == 0 )
|
||||
{
|
||||
AnimateUI( localClientNum, "fullscreen_dirt", "dirt", "in", 0 );
|
||||
}
|
||||
else if ( pick_one == 1 )
|
||||
{
|
||||
AnimateUI( localClientNum, "fullscreen_dirt", "dirt_right_splash", "in", 0 );
|
||||
}
|
||||
else if ( pick_one == 2 )
|
||||
{
|
||||
AnimateUI( localClientNum, "fullscreen_dirt", "dirt_left_splash", "in", 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
AnimateUI( localClientNum, "fullscreen_dirt", "blurred_dirt_random", "in", 0 );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
function play_screen_fx_dust(localClientNum)
|
||||
{
|
||||
// support for this has been removed with the .menu system
|
||||
/*
|
||||
pick_one = RandomIntRange(0,4);
|
||||
if ( pick_one == 0 )
|
||||
{
|
||||
AnimateUI( localClientNum, "fullscreen_dust", "dust", "in", 0 );
|
||||
}
|
||||
else if ( pick_one == 1 )
|
||||
{
|
||||
AnimateUI( localClientNum, "fullscreen_dust", "dust_right_splash", "in", 0 );
|
||||
}
|
||||
else if ( pick_one == 2 )
|
||||
{
|
||||
AnimateUI( localClientNum, "fullscreen_dust", "dust_left_splash", "in", 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
AnimateUI( localClientNum, "fullscreen_dust", "blurred_dust_random", "in", 0 );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
function play_driving_screen_fx( localClientNum )
|
||||
{
|
||||
speed_fraction = 0;
|
||||
|
||||
while(1)
|
||||
{
|
||||
speed = self getspeed();
|
||||
maxspeed = self getmaxspeed();
|
||||
|
||||
if ( speed < 0 )
|
||||
{
|
||||
maxspeed = self getmaxreversespeed();
|
||||
}
|
||||
|
||||
if ( maxspeed > 0 )
|
||||
{
|
||||
speed_fraction = Abs(speed) / maxspeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
speed_fraction = 0;
|
||||
}
|
||||
if ( self iswheelcolliding( "back_left" ) || self iswheelcolliding( "back_right" ) )
|
||||
{
|
||||
// probably need to fix this to work on spectators
|
||||
if ( self IsLocalClientDriver( localClientNum ) )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function play_boost_fx( localClientNum )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
speed = self GetSpeed();
|
||||
|
||||
if ( speed > 400 )
|
||||
{
|
||||
self PlaySound( localClientNum, "mpl_veh_rc_boost" );
|
||||
return;
|
||||
}
|
||||
|
||||
util::server_wait( localClientNum, 0.1 );
|
||||
}
|
||||
}
|
||||
|
||||
function stunnedHandler( localClientNum )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
self thread engineStutterHandler( localClientNum );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
self waittill( "stunned" );
|
||||
///#
|
||||
// PrintLn( "CLIENT ***************** stunned" );
|
||||
//#/
|
||||
|
||||
self setstunned( true );
|
||||
|
||||
self thread notStunnedHandler( localClientNum );
|
||||
|
||||
self thread play_stunned_fx_handler( localClientNum );
|
||||
}
|
||||
}
|
||||
|
||||
function notStunnedHandler( localClientNum )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
self endon( "stunned" );
|
||||
|
||||
self waittill( "not_stunned" );
|
||||
///#
|
||||
// PrintLn( "CLIENT ***************** not stunned" );
|
||||
//#/
|
||||
|
||||
self setstunned( false );
|
||||
}
|
||||
|
||||
function play_stunned_fx_handler( localClientNum ) // self == rc car
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
self endon( "stunned" );
|
||||
self endon( "not_stunned" );
|
||||
|
||||
// we need this so we can continue to play fx if being stunned by the jammer
|
||||
while( true )
|
||||
{
|
||||
playfxontag( localClientNum, level._effect["rcbomb_stunned"], self, "tag_origin" );
|
||||
wait( 0.5 );
|
||||
}
|
||||
}
|
||||
|
||||
function engineStutterHandler( localClientNum )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
self waittill( "veh_engine_stutter" );
|
||||
if ( self IsLocalClientDriver( localClientNum ) )
|
||||
{
|
||||
player = getlocalplayer( localClientNum );
|
||||
|
||||
if( isdefined( player ) )
|
||||
{
|
||||
player PlayRumbleOnEntity( localClientNum, "rcbomb_engine_stutter" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function OnDrivingFxCollision( localClientNum, player, hip, hitn, hit_intensity )
|
||||
{
|
||||
if( isdefined( hit_intensity ) && hit_intensity > 15 )
|
||||
{
|
||||
volume = driving_fx::get_impact_vol_from_speed();
|
||||
|
||||
if (isdefined (self.sounddef))
|
||||
{
|
||||
alias = self.sounddef + "_suspension_lg_hd";
|
||||
}
|
||||
else
|
||||
{
|
||||
alias = "veh_default_suspension_lg_hd";
|
||||
}
|
||||
|
||||
id = PlaySound( 0, alias, self.origin, volume);
|
||||
player Earthquake( 0.7, 0.25, player.origin, 1500 );
|
||||
player PlayRumbleOnEntity( localClientNum, "damage_heavy" );
|
||||
}
|
||||
}
|
||||
|
||||
function OnDrivingFxJumpLanding( localClientNum, player )
|
||||
{
|
||||
// do nothing for now
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,681 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\_oob;
|
||||
#using scripts\shared\array_shared;
|
||||
#using scripts\shared\audio_shared;
|
||||
#using scripts\shared\challenges_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\hostmigration_shared;
|
||||
#using scripts\shared\hud_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\popups_shared;
|
||||
#using scripts\shared\scoreevents_shared;
|
||||
#using scripts\shared\tweakables_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\weapons\_flashgrenades;
|
||||
#using scripts\shared\weapons\_weaponobjects;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
#using scripts\shared\vehicle_death_shared;
|
||||
|
||||
#using scripts\mp\_challenges;
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\gametypes\_globallogic_audio;
|
||||
#using scripts\mp\gametypes\_globallogic_utils;
|
||||
#using scripts\mp\gametypes\_hostmigration;
|
||||
#using scripts\mp\gametypes\_shellshock;
|
||||
#using scripts\mp\gametypes\_spawning;
|
||||
#using scripts\mp\killstreaks\_emp;
|
||||
#using scripts\mp\killstreaks\_killstreak_bundles;
|
||||
#using scripts\mp\killstreaks\_killstreak_detect;
|
||||
#using scripts\mp\killstreaks\_killstreak_hacking;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_remote_weapons;
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#precache( "string", "KILLSTREAK_EARNED_RCBOMB" );
|
||||
#precache( "string", "KILLSTREAK_RCBOMB_NOT_AVAILABLE" );
|
||||
#precache( "string", "KILLSTREAK_RCBOMB_INBOUND" );
|
||||
#precache( "string", "KILLSTREAK_RCBOMB_HACKED" );
|
||||
#precache( "string", "KILLSTREAK_DESTROYED_RCBOMB" );
|
||||
#precache( "string", "mpl_killstreak_rcbomb" );
|
||||
#precache( "fx", "_t6/weapon/grenade/fx_spark_disabled_rc_car" );
|
||||
#precache( "fx", "killstreaks/fx_rcxd_lights_grn" );
|
||||
#precache( "fx", "killstreaks/fx_rcxd_lights_red" );
|
||||
#precache( "fx", "killstreaks/fx_rcxd_exp" );
|
||||
|
||||
#namespace rcbomb;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function init()
|
||||
{
|
||||
level._effect["rcbombexplosion"] = "killstreaks/fx_rcxd_exp";
|
||||
|
||||
killstreaks::register( "rcbomb", "rcbomb", "killstreak_rcbomb", "rcbomb_used",&ActivateRCBomb );
|
||||
killstreaks::register_strings( "rcbomb", &"KILLSTREAK_EARNED_RCBOMB", &"KILLSTREAK_RCBOMB_NOT_AVAILABLE", &"KILLSTREAK_RCBOMB_INBOUND", undefined, &"KILLSTREAK_RCBOMB_HACKED", false );
|
||||
killstreaks::register_dialog( "rcbomb", "mpl_killstreak_rcbomb", "rcBombDialogBundle", undefined, "friendlyRcBomb", "enemyRcBomb", "enemyRcBombMultiple", "friendlyRcBombHacked", "enemyRcBombHacked", "requestRcBomb" );
|
||||
killstreaks::allow_assists( "rcbomb", true);
|
||||
killstreaks::register_alt_weapon( "rcbomb", "killstreak_remote" );
|
||||
killstreaks::register_alt_weapon( "rcbomb", "rcbomb_turret" );
|
||||
remote_weapons::RegisterRemoteWeapon( "rcbomb", &"", &StartRemoteControl, &EndRemoteControl, false );
|
||||
|
||||
vehicle::add_main_callback( "rc_car_mp", &InitRCBomb );
|
||||
|
||||
clientfield::register( "vehicle", "rcbomb_stunned", 1, 1, "int" );
|
||||
}
|
||||
|
||||
function InitRCBomb()
|
||||
{
|
||||
rcbomb = self;
|
||||
|
||||
rcbomb clientfield::set( "enemyvehicle", 1 );
|
||||
rcbomb.allowFriendlyFireDamageOverride = &RCCarAllowFriendlyFireDamage;
|
||||
rcbomb EnableAimAssist();
|
||||
rcbomb SetDrawInfrared( true );
|
||||
rcbomb.delete_on_death = true;
|
||||
rcbomb.death_enter_cb = &waitRemoteControl;
|
||||
rcbomb.disableRemoteWeaponSwitch = true;
|
||||
rcbomb.overrideVehicleDamage = &OnDamage;
|
||||
rcbomb.overrideVehicleDeath = &OnDeath;
|
||||
//rcbomb.remoteWeaponShutdownDelay = RCBOMB_SHUTDOWN_DELAY;
|
||||
rcbomb.watch_remote_weapon_death = true;
|
||||
rcbomb.watch_remote_weapon_death_duration = ( 0.3 );
|
||||
|
||||
if ( IsSentient( rcbomb ) == false )
|
||||
rcbomb MakeSentient(); // so other sentients will consider this as a potential enemy
|
||||
}
|
||||
|
||||
|
||||
function waitRemoteControl()
|
||||
{
|
||||
remote_controlled = ( isdefined( self.control_initiated ) && self.control_initiated ) || ( isdefined( self.controlled ) && self.controlled );
|
||||
|
||||
if( remote_controlled )
|
||||
{
|
||||
notifyString = self util::waittill_any_return( "remote_weapon_end", "rcbomb_shutdown" );
|
||||
if( notifyString == "remote_weapon_end" )
|
||||
self waittill( "rcbomb_shutdown" );
|
||||
else
|
||||
self waittill( "remote_weapon_end" );
|
||||
}
|
||||
else
|
||||
self waittill( "rcbomb_shutdown" );
|
||||
}
|
||||
|
||||
function toggleLightsOnAfterTime( time )
|
||||
{
|
||||
self notify("toggleLightsOnAfterTime_singleton");
|
||||
self endon ("toggleLightsOnAfterTime_singleton");
|
||||
|
||||
rcbomb = self;
|
||||
rcbomb endon( "death" );
|
||||
wait( time );
|
||||
rcbomb clientfield::set( "toggle_lights", 0 );
|
||||
}
|
||||
|
||||
function HackedPreFunction( hacker )
|
||||
{
|
||||
rcbomb = self;
|
||||
rcbomb clientfield::set( "toggle_lights", 1 );
|
||||
rcbomb.owner unlink();
|
||||
rcbomb clientfield::set( "vehicletransition", 0 );
|
||||
rcbomb.owner killstreaks::clear_using_remote();
|
||||
rcbomb MakeVehicleUnusable();
|
||||
}
|
||||
|
||||
function HackedPostFunction( hacker )
|
||||
{
|
||||
rcbomb = self;
|
||||
hacker remote_weapons::UseRemoteWeapon( rcbomb, "rcbomb", true, false );
|
||||
rcbomb MakeVehicleUnusable();
|
||||
hacker killstreaks::set_killstreak_delay_killcam( "rcbomb" );
|
||||
hacker killstreak_hacking::set_vehicle_drivable_time_starting_now( rcbomb );
|
||||
}
|
||||
|
||||
function ConfigureTeamPost( owner, isHacked )
|
||||
{
|
||||
rcbomb = self;
|
||||
rcbomb thread WatchOwnerGameEvents();
|
||||
}
|
||||
|
||||
|
||||
function ActivateRCBomb( hardpointType )
|
||||
{
|
||||
assert( IsPlayer( self ) );
|
||||
player = self;
|
||||
|
||||
if( !player killstreakrules::isKillstreakAllowed( hardpointType, player.team ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( player UseButtonPressed() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
placement = CalculateSpawnOrigin( self.origin, self.angles );
|
||||
if( !isdefined( placement ) || !self IsOnGround() || self util::isUsingRemote() || killstreaks::is_interacting_with_object() || self oob::IsTouchingAnyOOBTrigger() || self killstreaks::is_killstreak_start_blocked() )
|
||||
{
|
||||
self iPrintLnBold( &"KILLSTREAK_RCBOMB_NOT_PLACEABLE" );
|
||||
return false;
|
||||
}
|
||||
|
||||
killstreak_id = player killstreakrules::killstreakStart( "rcbomb", player.team, false, true );
|
||||
if( killstreak_id == (-1) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rcbomb = SpawnVehicle( "rc_car_mp", placement.origin, placement.angles, "rcbomb" );
|
||||
|
||||
rcbomb killstreaks::configure_team( "rcbomb", killstreak_id, player, "small_vehicle", undefined, &ConfigureTeamPost );
|
||||
rcbomb killstreak_hacking::enable_hacking( "rcbomb", &HackedPreFunction, &HackedPostFunction );
|
||||
rcbomb.damageTaken = 0;
|
||||
rcbomb.abandoned = false;
|
||||
rcbomb.killstreak_id = killstreak_id;
|
||||
rcbomb.activatingKillstreak = true;
|
||||
rcbomb SetInvisibleToAll();
|
||||
|
||||
rcbomb thread WatchShutdown();
|
||||
rcbomb.health = killstreak_bundles::get_max_health( hardpointType );
|
||||
rcbomb.maxhealth = killstreak_bundles::get_max_health( hardpointType );
|
||||
rcbomb.hackedhealth = killstreak_bundles::get_hacked_health( hardpointType );
|
||||
rcbomb.hackedHealthUpdateCallback = &rcbomb_hacked_health_update;
|
||||
rcbomb.ignore_vehicle_underneath_splash_scalar = true;
|
||||
|
||||
self thread killstreaks::play_killstreak_start_dialog( "rcbomb", self.team, killstreak_id );
|
||||
self AddWeaponStat( GetWeapon( "rcbomb" ) , "used", 1 );
|
||||
|
||||
remote_weapons::UseRemoteWeapon( rcbomb, "rcbomb", true, false );
|
||||
|
||||
if ( !isdefined( player ) || !isAlive( player ) || ( isdefined( player.laststand ) && player.laststand ) || player IsEMPJammed() )
|
||||
{
|
||||
if ( isdefined( rcbomb ) )
|
||||
{
|
||||
rcbomb notify( "remote_weapon_shutdown" );
|
||||
rcbomb notify( "rcbomb_shutdown" );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
rcbomb SetVisibleToAll();
|
||||
rcbomb.activatingKillstreak = false;
|
||||
Target_Set( rcbomb );
|
||||
|
||||
rcbomb thread WatchGameEnded();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function rcbomb_hacked_health_update( hacker )
|
||||
{
|
||||
rcbomb = self;
|
||||
if ( rcbomb.health > rcbomb.hackedhealth )
|
||||
{
|
||||
rcbomb.health = rcbomb.hackedhealth;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function StartRemoteControl( rcbomb )
|
||||
{
|
||||
player = self;
|
||||
|
||||
rcbomb UseVehicle( player, 0 );
|
||||
rcbomb clientfield::set( "vehicletransition", 1 );
|
||||
|
||||
rcbomb thread audio::sndUpdateVehicleContext(true);
|
||||
|
||||
rcbomb thread WatchTimeout();
|
||||
rcbomb thread WatchDetonation();
|
||||
rcbomb thread WatchHurtTriggers();
|
||||
rcbomb thread WatchWater();
|
||||
|
||||
player vehicle::set_vehicle_drivable_time_starting_now( ( 40 * 1000 ) );
|
||||
}
|
||||
|
||||
function EndRemoteControl( rcbomb, exitRequestedByOwner )
|
||||
{
|
||||
if ( exitrequestedbyowner == false )
|
||||
{
|
||||
rcbomb notify( "rcbomb_shutdown" );
|
||||
rcbomb thread audio::sndUpdateVehicleContext(false);
|
||||
}
|
||||
rcbomb clientfield::set( "vehicletransition", 0 );
|
||||
}
|
||||
|
||||
function WatchDetonation()
|
||||
{
|
||||
rcbomb = self;
|
||||
rcbomb endon( "rcbomb_shutdown" );
|
||||
rcbomb endon( "death" );
|
||||
|
||||
while( !rcbomb.owner attackbuttonpressed() )
|
||||
{
|
||||
{wait(.05);};
|
||||
}
|
||||
|
||||
rcbomb notify( "rcbomb_shutdown" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function WatchWater()
|
||||
{
|
||||
self endon( "rcbomb_shutdown" );
|
||||
|
||||
inWater = false;
|
||||
while( !inWater )
|
||||
{
|
||||
wait ( 0.5 );
|
||||
trace = physicstrace( self.origin + ( 0, 0, 10 ), self.origin + ( 0, 0, 6 ), ( -2, -2, -2 ), ( 2, 2, 2 ), self, ( (1 << 2) ));
|
||||
inWater = trace["fraction"] < 1.0;
|
||||
}
|
||||
|
||||
self.abandoned = true;
|
||||
self notify( "rcbomb_shutdown" );
|
||||
}
|
||||
|
||||
function WatchOwnerGameEvents()
|
||||
{
|
||||
self notify("WatchOwnerGameEvents_singleton");
|
||||
self endon ("WatchOwnerGameEvents_singleton");
|
||||
|
||||
rcbomb = self;
|
||||
rcbomb endon( "rcbomb_shutdown" );
|
||||
|
||||
rcbomb.owner util::waittill_any( "joined_team", "disconnect", "joined_spectators" );
|
||||
|
||||
rcbomb.abandoned = true;
|
||||
rcbomb notify( "rcbomb_shutdown" );
|
||||
}
|
||||
|
||||
function WatchTimeout()
|
||||
{
|
||||
rcbomb = self;
|
||||
rcbomb thread killstreaks::WaitForTimeout( "rcbomb", ( 40 * 1000 ), &rc_shutdown, "rcbomb_shutdown" );
|
||||
}
|
||||
|
||||
function rc_shutdown()
|
||||
{
|
||||
rcbomb = self;
|
||||
rcbomb notify( "rcbomb_shutdown" );
|
||||
}
|
||||
|
||||
function WatchShutdown()
|
||||
{
|
||||
rcbomb = self;
|
||||
rcbomb endon( "death" );
|
||||
|
||||
rcbomb waittill( "rcbomb_shutdown" );
|
||||
|
||||
if ( isdefined( rcbomb.activatingKillstreak ) && rcbomb.activatingKillstreak )
|
||||
{
|
||||
// we can delete since it should not have been made visible yet
|
||||
killstreakrules::killstreakStop( "rcbomb", rcbomb.originalteam, rcbomb.killstreak_id );
|
||||
rcbomb notify( "rcbomb_shutdown" );
|
||||
rcbomb delete(); // still need to delete here
|
||||
}
|
||||
else
|
||||
{
|
||||
attacker = ( isdefined( rcbomb.owner ) ? rcbomb.owner : undefined );
|
||||
rcbomb DoDamage( rcbomb.health + 1, rcbomb.origin + (0, 0, 10), attacker, attacker, "none", "MOD_EXPLOSIVE", 0 );
|
||||
}
|
||||
}
|
||||
|
||||
function WatchHurtTriggers()
|
||||
{
|
||||
rcbomb = self;
|
||||
rcbomb endon( "rcbomb_shutdown" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
rcbomb waittill ( "touch", ent );
|
||||
if( isdefined( ent.classname ) && ( ent.classname == "trigger_hurt" || ent.classname == "trigger_out_of_bounds" ) )
|
||||
{
|
||||
rcbomb notify( "rcbomb_shutdown" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function OnDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
|
||||
{
|
||||
if ( self.activatingKillstreak )
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if ( !isdefined( eAttacker ) || eAttacker != self.owner )
|
||||
{
|
||||
iDamage = killstreaks::OnDamagePerWeapon( "rcbomb", eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, self.maxhealth, undefined, self.maxhealth*0.4, undefined, 0, undefined, true, 1.0 );
|
||||
}
|
||||
|
||||
if( isdefined( eAttacker ) && isdefined( eAttacker.team ) && eAttacker.team != self.team )
|
||||
{
|
||||
if( weapon.isEmp )
|
||||
{
|
||||
self.damage_on_death = false;
|
||||
self.died_by_emp = true;
|
||||
iDamage = self.health + 1; // destroy if hit by emp
|
||||
//thread remote_weapons::do_static_fx();
|
||||
}
|
||||
}
|
||||
|
||||
// C4 destroys the HC-XD with any damage (TODO: consider creating a more robust solution if need be)
|
||||
if ( weapon.name == "satchel_charge" && sMeansOfDeath == "MOD_EXPLOSIVE" )
|
||||
{
|
||||
iDamage = self.health + 1;
|
||||
}
|
||||
|
||||
return iDamage;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function OnDeath( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime )
|
||||
{
|
||||
rcbomb = self;
|
||||
player = rcbomb.owner;
|
||||
|
||||
player endon( "disconnect" );
|
||||
player endon( "joined_team" );
|
||||
player endon( "joined_spectators" );
|
||||
|
||||
killstreakrules::killstreakStop( "rcbomb", rcbomb.originalTeam, rcbomb.killstreak_id );
|
||||
|
||||
rcbomb clientfield::set( "enemyvehicle", 0 );
|
||||
|
||||
//if( isdefined( player ) && ( !isdefined( eAttacker ) || ( eAttacker.team != rcbomb.team ) ) && !level.gameEnded )
|
||||
//rcbomb remote_weapons::do_static_fx();
|
||||
|
||||
rcbomb Explode( eAttacker, weapon );
|
||||
|
||||
hide_after_wait_time = ( ( rcbomb.died_by_emp === true ) ? ( 0.2 ) : ( 0.1 ) );
|
||||
if( isdefined( player ) )
|
||||
{
|
||||
player util::freeze_player_controls( true );
|
||||
rcbomb thread HideAfterWait( hide_after_wait_time );
|
||||
//rcbomb util::DeleteAfterTime( RCBOMB_SHUTDOWN_DELAY );
|
||||
wait( ( 0.2 ) );
|
||||
player util::freeze_player_controls( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
rcbomb thread HideAfterWait( hide_after_wait_time );
|
||||
//rcbomb util::DeleteAfterTime( RCBOMB_SHUTDOWN_DELAY_ABANDONED );
|
||||
}
|
||||
|
||||
if ( isdefined( rcbomb ) )
|
||||
rcbomb notify( "rcbomb_shutdown" );
|
||||
}
|
||||
|
||||
function WatchGameEnded()
|
||||
{
|
||||
rcbomb = self;
|
||||
rcbomb endon( "death" );
|
||||
|
||||
level waittill("game_ended");
|
||||
|
||||
rcbomb.abandoned = true;
|
||||
rcbomb.selfDestruct = true;
|
||||
rcbomb notify( "rcbomb_shutdown" );
|
||||
}
|
||||
|
||||
function HideAfterWait( waitTime )
|
||||
{
|
||||
self endon( "death" );
|
||||
|
||||
wait waitTime;
|
||||
self SetInvisibleToAll();
|
||||
}
|
||||
|
||||
function Explode( attacker, weapon )
|
||||
{
|
||||
self endon ("death");
|
||||
owner = self.owner;
|
||||
|
||||
if ( !isdefined( attacker ) && isdefined( self.owner ) )
|
||||
{
|
||||
attacker = self.owner;
|
||||
}
|
||||
|
||||
self vehicle_death::death_fx();
|
||||
self thread vehicle_death::death_radius_damage();
|
||||
self thread vehicle_death::set_death_model( self.deathmodel, self.modelswapdelay );
|
||||
|
||||
self vehicle::toggle_tread_fx( false );
|
||||
self vehicle::toggle_exhaust_fx( false );
|
||||
self vehicle::toggle_sounds( false );
|
||||
self vehicle::lights_off();
|
||||
|
||||
self PlayRumbleOnEntity( "rcbomb_explosion" );
|
||||
|
||||
if ( !self.abandoned && attacker != self.owner && isPlayer( attacker ) )
|
||||
{
|
||||
attacker challenges::destroyRCBomb( weapon );
|
||||
if ( self.owner util::IsEnemyPlayer( attacker ) )
|
||||
{
|
||||
scoreevents::processScoreEvent( "destroyed_hover_rcxd", attacker, self.owner, weapon );
|
||||
LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_RCBOMB", attacker.entnum );
|
||||
if ( isdefined( weapon ) && weapon.isValid )
|
||||
{
|
||||
weaponStatName = "destroyed";
|
||||
level.globalKillstreaksDestroyed++;
|
||||
// increment the destroyed stat for this, we aren't using the weaponStatName variable from above because it could be "kills" and we don't want that
|
||||
weapon_rcbomb = GetWeapon( "rcbomb" );
|
||||
attacker AddWeaponStat( weapon_rcbomb, "destroyed", 1 );
|
||||
attacker AddWeaponStat( weapon, "destroyed_controlled_killstreak", 1 );
|
||||
}
|
||||
|
||||
self killstreaks::play_destroyed_dialog_on_owner( "rcbomb", self.killstreak_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function RCCarAllowFriendlyFireDamage( eInflictor, eAttacker, sMeansOfDeath, weapon )
|
||||
{
|
||||
if ( isdefined( eAttacker ) && eAttacker == self.owner )
|
||||
return true;
|
||||
|
||||
if ( isdefined( eInflictor ) && eInflictor islinkedto( self ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function GetPlacementStartHeight()
|
||||
{
|
||||
startheight = ( 50 );
|
||||
|
||||
switch( self GetStance() )
|
||||
{
|
||||
case "crouch":
|
||||
startheight = ( 30 );
|
||||
break;
|
||||
case "prone":
|
||||
startheight = ( 15 );
|
||||
break;
|
||||
}
|
||||
return startheight;
|
||||
}
|
||||
|
||||
function CalculateSpawnOrigin( origin, angles )
|
||||
{
|
||||
startheight = GetPlacementStartHeight();
|
||||
|
||||
mins = (-5,-5,0); // keep the min z 0 so the return point is the exact height of the collision
|
||||
maxs = (5,5,10);
|
||||
|
||||
startPoints = [];
|
||||
startAngles = [];
|
||||
wheelCounts = [];
|
||||
testCheck = [];
|
||||
largestCount = 0;
|
||||
largestCountIndex = 0;
|
||||
|
||||
testangles = [];
|
||||
testangles[0] = (0,0,0);
|
||||
testangles[1] = (0,20,0);
|
||||
testangles[2] = (0,-20,0);
|
||||
testangles[3] = (0,45,0);
|
||||
testangles[4] = (0,-45,0);
|
||||
|
||||
heightoffset = 5;
|
||||
|
||||
for (i = 0; i < testangles.size; i++ )
|
||||
{
|
||||
testCheck[i] = false;
|
||||
|
||||
startAngles[i] = ( 0, angles[1], 0 );
|
||||
startPoint = origin + VectorScale( anglestoforward( startAngles[i] + testangles[i]), ( 70 ) );
|
||||
endPoint = startPoint - (0,0,100);
|
||||
startPoint = startPoint + (0,0,startheight);
|
||||
|
||||
// ignore water on this one
|
||||
mask = (1 << 0) | (1 << 1);
|
||||
|
||||
// using physicstrace so we dont slip through small cracks
|
||||
trace = physicstrace( startPoint, endPoint, mins, maxs, self, mask);
|
||||
|
||||
// if any player intersection then skip
|
||||
if ( isdefined(trace["entity"]) && IsPlayer(trace["entity"]))
|
||||
{
|
||||
wheelCounts[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
startPoints[i] = trace["position"] + (0,0,heightoffset);
|
||||
wheelCounts[i] = TestWheelLocations(startPoints[i],startAngles[i],heightoffset);
|
||||
|
||||
if ( positionWouldTelefrag( startPoints[i] ) )
|
||||
continue;
|
||||
|
||||
if ( largestCount < wheelCounts[i] )
|
||||
{
|
||||
largestCount = wheelCounts[i];
|
||||
largestCountIndex = i;
|
||||
}
|
||||
|
||||
// going to early out on the first I find with valid tire positions
|
||||
if ( wheelCounts[i] >= 3 )
|
||||
{
|
||||
testCheck[i] = true;
|
||||
|
||||
if ( TestSpawnOrigin( startPoints[i], startAngles[i] ) )
|
||||
{
|
||||
placement = SpawnStruct();
|
||||
placement.origin = startPoints[i];
|
||||
placement.angles = startAngles[i];
|
||||
return placement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < testangles.size; i++ )
|
||||
{
|
||||
if ( !testCheck[i] )
|
||||
{
|
||||
if ( wheelCounts[i] >= 2 )
|
||||
{
|
||||
if ( TestSpawnOrigin( startPoints[i], startAngles[i] ) )
|
||||
{
|
||||
placement = SpawnStruct();
|
||||
placement.origin = startPoints[i];
|
||||
placement.angles = startAngles[i];
|
||||
return placement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function TestWheelLocations( origin, angles, heightoffset )
|
||||
{
|
||||
forward = 13;
|
||||
side = 10;
|
||||
|
||||
wheels = [];
|
||||
wheels[0] = ( forward, side, 0 );
|
||||
wheels[1] = ( forward, -1 * side, 0 );
|
||||
wheels[2] = ( -1 * forward, -1 * side, 0 );
|
||||
wheels[3] = ( -1 * forward, side, 0 );
|
||||
|
||||
height = 5;
|
||||
touchCount = 0;
|
||||
|
||||
yawangles = (0,angles[1],0);
|
||||
|
||||
for (i = 0; i < 4; i++ )
|
||||
{
|
||||
wheel = RotatePoint( wheels[i], yawangles );
|
||||
startPoint = origin + wheel;
|
||||
endPoint = startPoint + (0,0,(-1 * height) - heightoffset);
|
||||
startPoint = startPoint + (0,0,height - heightoffset) ;
|
||||
|
||||
trace = bulletTrace( startPoint, endPoint, false, self );
|
||||
if ( trace["fraction"] < 1 )
|
||||
{
|
||||
touchCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return touchCount;
|
||||
}
|
||||
|
||||
function TestSpawnOrigin( origin, angles )
|
||||
{
|
||||
liftedorigin = origin + (0,0,5);
|
||||
size = 12;
|
||||
height = 15;
|
||||
mins = (-1 * size,-1 * size,0 );
|
||||
maxs = ( size,size,height );
|
||||
absmins = liftedorigin + mins;
|
||||
absmaxs = liftedorigin + maxs;
|
||||
|
||||
if( BoundsWouldTelefrag( absmins, absmaxs ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
startheight = getPlacementStartHeight();
|
||||
|
||||
mask = (1 << 0) | (1 << 1) | (1 << 2);
|
||||
|
||||
// test the volume where we are going to place the car
|
||||
// note that this physics trace is not an oriented box.
|
||||
trace = physicstrace( liftedorigin, (origin +(0,0,1)), mins, maxs, self, mask);
|
||||
|
||||
if ( trace["fraction"] < 1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// swept trace of a small bounding box from head height to where we are placing the car
|
||||
// to make sure there is no wall between us and the car
|
||||
size = 2.5;
|
||||
height = size * 2;
|
||||
mins = (-1 * size,-1 * size,0 );
|
||||
maxs = ( size,size,height );
|
||||
|
||||
sweeptrace = physicstrace( (self.origin + (0,0,startheight)), liftedorigin, mins, maxs, self, mask);
|
||||
|
||||
if ( sweeptrace["fraction"] < 1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,529 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\hud_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
Line truncated
|
||||
#using scripts\shared\lui_shared;
|
||||
#using scripts\mp\killstreaks\_qrdrone;
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\killstreaks\_ai_tank;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_turret;
|
||||
|
||||
|
||||
|
||||
// Manager for all weapons that can be remotely controlled with the tablet
|
||||
|
||||
|
||||
#namespace remote_weapons;
|
||||
|
||||
function init()
|
||||
{
|
||||
level.remoteWeapons = [];
|
||||
level.remoteExitHint = &"MP_REMOTE_EXIT";
|
||||
callback::on_spawned( &on_player_spawned );
|
||||
}
|
||||
|
||||
function on_player_spawned()
|
||||
{
|
||||
self endon("disconnect");
|
||||
|
||||
self AssignRemoteControlTrigger();
|
||||
}
|
||||
|
||||
function RemoveAndAssignNewRemoteControlTrigger( remoteControlTrigger ) // player = self
|
||||
{
|
||||
ArrayRemoveValue( self.activeRemoteControlTriggers, remoteControlTrigger );
|
||||
self AssignRemoteControlTrigger( true );
|
||||
}
|
||||
|
||||
function AssignRemoteControlTrigger( force_new_assignment = false ) // player = self
|
||||
{
|
||||
if ( !isdefined( self.activeRemoteControlTriggers ) )
|
||||
self.activeRemoteControlTriggers = [];
|
||||
|
||||
ArrayRemoveValue( self.activeRemoteControlTriggers, undefined );
|
||||
|
||||
if ( ( !isdefined( self.remoteControlTrigger ) || force_new_assignment ) && self.activeRemoteControlTriggers.size > 0 )
|
||||
{
|
||||
self.remoteControlTrigger = self.activeRemoteControlTriggers[ self.activeRemoteControlTriggers.size - 1 ];
|
||||
}
|
||||
|
||||
if ( isdefined( self.remoteControlTrigger ) )
|
||||
{
|
||||
self.remoteControlTrigger.origin = self.origin;
|
||||
self.remoteControlTrigger LinkTo( self );
|
||||
}
|
||||
}
|
||||
|
||||
function RegisterRemoteWeapon( weaponName, hintString, useCallback, endUseCallback, hideCompassOnUse = true )
|
||||
{
|
||||
assert( isdefined( level.remoteWeapons ) );
|
||||
|
||||
level.remoteWeapons[ weaponName ] = SpawnStruct();
|
||||
level.remoteWeapons[ weaponName ].hintString = hintString;
|
||||
level.remoteWeapons[ weaponName ].useCallback = useCallback;
|
||||
level.remoteWeapons[ weaponName ].endUseCallback = endUseCallback;
|
||||
level.remoteWeapons[ weaponName ].hideCompassOnUse = hideCompassOnUse;
|
||||
}
|
||||
|
||||
function UseRemoteWeapon( weapon, weaponName, immediate, allowManualDeactivation = true, always_allow_ride = false )
|
||||
{
|
||||
player = self;
|
||||
assert( IsPlayer( player ) );
|
||||
|
||||
weapon.remoteOwner = player;
|
||||
weapon.initTime = GetTime();
|
||||
weapon.remoteName = weaponName;
|
||||
weapon.remoteWeaponAllowManualDeactivation = allowManualDeactivation;
|
||||
|
||||
weapon thread WatchRemoveRemoteControlledWeapon();
|
||||
|
||||
if( !immediate )
|
||||
{
|
||||
weapon CreateRemoteWeaponTrigger();
|
||||
}
|
||||
else
|
||||
{
|
||||
weapon thread WatchOwnerDisconnect();
|
||||
weapon UseRemoteControlWeapon( allowManualDeactivation, always_allow_ride );
|
||||
}
|
||||
}
|
||||
|
||||
function WatchForHack()
|
||||
{
|
||||
weapon = self;
|
||||
weapon endon( "death" );
|
||||
|
||||
weapon waittill( "killstreak_hacked", hacker );
|
||||
|
||||
if ( isdefined( weapon.remoteWeaponAllowManualDeactivation ) && weapon.remoteWeaponAllowManualDeactivation == true )
|
||||
{
|
||||
weapon thread WatchRemoteControlDeactivate();
|
||||
}
|
||||
weapon.remoteOwner = hacker;
|
||||
}
|
||||
|
||||
function WatchRemoveRemoteControlledWeapon()
|
||||
{
|
||||
weapon = self;
|
||||
weapon endon( "remote_weapon_end" );
|
||||
weapon util::waittill_any( "death", "remote_weapon_shutdown" );
|
||||
|
||||
weapon EndRemoteControlWeaponUse( false );
|
||||
|
||||
while( isdefined( weapon ) )
|
||||
{
|
||||
{wait(.05);}; // Wait until any death animations and any other waits are finished
|
||||
}
|
||||
|
||||
//Check for queued remote weapon
|
||||
}
|
||||
|
||||
function CreateRemoteWeaponTrigger()
|
||||
{
|
||||
weapon = self;
|
||||
player = weapon.remoteOwner;
|
||||
|
||||
if ( isdefined( weapon.useTrigger ) )
|
||||
{
|
||||
weapon.useTrigger delete();
|
||||
}
|
||||
|
||||
weapon.useTrigger = spawn( "trigger_radius_use", player.origin, 32, 32 );
|
||||
weapon.useTrigger EnableLinkTo();
|
||||
weapon.useTrigger LinkTo( player );
|
||||
weapon.useTrigger SetHintLowPriority( true );
|
||||
weapon.useTrigger SetCursorHint( "HINT_NOICON" );
|
||||
weapon.useTrigger SetHintString( level.remoteWeapons[ weapon.remoteName ].hintString );
|
||||
|
||||
weapon.useTrigger SetTeamForTrigger( player.team );
|
||||
weapon.useTrigger.team = player.team;
|
||||
|
||||
player ClientClaimTrigger( weapon.useTrigger );
|
||||
player.remoteControlTrigger = weapon.useTrigger;
|
||||
player.activeRemoteControlTriggers[ player.activeRemoteControlTriggers.size ] = weapon.useTrigger;
|
||||
weapon.useTrigger.ClaimedBy = player;
|
||||
|
||||
weapon thread WatchWeaponDeath();
|
||||
weapon thread WatchOwnerDisconnect();
|
||||
weapon thread WatchRemoteTriggerUse();
|
||||
weapon thread WatchRemoteTriggerDisable();
|
||||
}
|
||||
|
||||
function WatchWeaponDeath()
|
||||
{
|
||||
weapon = self;
|
||||
weapon.useTrigger endon( "death" );
|
||||
|
||||
weapon util::waittill_any( "death", "remote_weapon_end" );
|
||||
|
||||
if ( isdefined( weapon.remoteOwner ) )
|
||||
{
|
||||
weapon.remoteOwner RemoveAndAssignNewRemoteControlTrigger( weapon.useTrigger );
|
||||
}
|
||||
|
||||
weapon.useTrigger delete();
|
||||
}
|
||||
|
||||
function WatchOwnerDisconnect()
|
||||
{
|
||||
weapon = self;
|
||||
weapon endon( "remote_weapon_end" );
|
||||
weapon endon( "remote_weapon_shutdown" );
|
||||
|
||||
if( isdefined( weapon.useTrigger ) )
|
||||
weapon.useTrigger endon( "death" );
|
||||
|
||||
weapon.remoteOwner util::waittill_any( "joined_team", "disconnect", "joined_spectators" );
|
||||
|
||||
EndRemoteControlWeaponUse( false );
|
||||
|
||||
if( isdefined( weapon ) && isdefined( weapon.useTrigger ) )
|
||||
weapon.useTrigger delete();
|
||||
}
|
||||
|
||||
function WatchRemoteTriggerDisable()
|
||||
{
|
||||
weapon = self;
|
||||
weapon endon( "remote_weapon_end" );
|
||||
weapon endon( "remote_weapon_shutdown" );
|
||||
weapon.useTrigger endon( "death" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
weapon.useTrigger TriggerEnable( !( weapon.remoteOwner IsWallRunning() ) );
|
||||
wait( 0.1 );
|
||||
}
|
||||
}
|
||||
|
||||
function AllowRemoteStart()
|
||||
{
|
||||
player = self;
|
||||
if( player useButtonPressed() && !player.throwingGrenade && !player meleeButtonPressed() && !player util::isUsingRemote() && !( isdefined( player.carryObject ) && ( isdefined( player.carryObject.disallowRemoteControl ) && player.carryObject.disallowRemoteControl ) ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function WatchRemoteTriggerUse()
|
||||
{
|
||||
weapon = self;
|
||||
weapon endon( "death" );
|
||||
weapon endon( "remote_weapon_end" );
|
||||
|
||||
if( weapon.remoteOwner util::is_bot() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while( true )
|
||||
{
|
||||
weapon.useTrigger waittill( "trigger", player );
|
||||
|
||||
if( weapon.remoteOwner IsUsingOffhand() || weapon.remoteOwner IsWallRunning() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( isdefined( weapon.hackertrigger ) && isdefined( weapon.hackertrigger.progressbar ) )
|
||||
{
|
||||
if( weapon.remoteName == "killstreak_remote_turret" )
|
||||
{
|
||||
weapon.remoteOwner iPrintLnBold( &"KILLSTREAK_AUTO_TURRET_NOT_AVAILABLE" );
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if( weapon.remoteOwner AllowRemoteStart() )
|
||||
{
|
||||
UseRemoteControlWeapon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function UseRemoteControlWeapon( allowManualDeactivation = true, always_allow_ride = false )
|
||||
{
|
||||
self endon( "death" );
|
||||
|
||||
weapon = self;
|
||||
|
||||
assert( isdefined( weapon.remoteOwner ) );
|
||||
|
||||
weapon.control_initiated = true;
|
||||
weapon.endRemoteControlWeapon = false;
|
||||
|
||||
weapon.remoteOwner endon( "disconnect" );
|
||||
weapon.remoteOwner endon( "joined_team" );
|
||||
|
||||
weapon.remoteOwner DisableOffhandWeapons();
|
||||
weapon.remoteOwner DisableWeaponCycling();
|
||||
|
||||
weapon.remoteOwner.dofutz = false;
|
||||
|
||||
if( !isdefined( weapon.disableRemoteWeaponSwitch ) )
|
||||
{
|
||||
remoteWeapon = GetWeapon( "killstreak_remote" );
|
||||
weapon.remoteOwner giveWeapon( remoteWeapon );
|
||||
weapon.remoteOwner switchToWeapon( remoteWeapon );
|
||||
|
||||
if ( always_allow_ride )
|
||||
{
|
||||
weapon.remoteOwner util::waittill_any( "weapon_change", "death" );
|
||||
}
|
||||
else
|
||||
{
|
||||
weapon.remoteOwner waittill( "weapon_change", newWeapon );
|
||||
}
|
||||
}
|
||||
|
||||
if( isdefined( newweapon ) )
|
||||
{
|
||||
if( newweapon != remoteWeapon )
|
||||
{
|
||||
weapon.remoteOwner killstreaks::clear_using_remote( true, true );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
weapon.remoteOwner thread killstreaks::watch_for_remove_remote_weapon();
|
||||
|
||||
weapon.remoteOwner util::setUsingRemote( weapon.remoteName );
|
||||
weapon.remoteOwner util::freeze_player_controls( true );
|
||||
|
||||
result = weapon.remoteOwner killstreaks::init_ride_killstreak( weapon.remoteName, always_allow_ride );
|
||||
|
||||
if( result != "success" )
|
||||
{
|
||||
if( result != "disconnect" )
|
||||
{
|
||||
weapon.remoteOwner killstreaks::clear_using_remote();
|
||||
weapon thread ResetControlInitiatedUponOwnerRespawn();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
weapon.controlled = true;
|
||||
weapon.killCamEnt = self;
|
||||
weapon notify("remote_start"); // shuts down the AI scripts for this weapon
|
||||
|
||||
if ( allowManualDeactivation )
|
||||
{
|
||||
weapon thread watchRemoteControlDeactivate();
|
||||
}
|
||||
|
||||
weapon.remoteOwner thread [[level.remoteWeapons[ weapon.remoteName ].useCallback]]( weapon );
|
||||
|
||||
if ( level.remoteWeapons[ weapon.remoteName ].hideCompassOnUse )
|
||||
{
|
||||
weapon.remoteOwner killstreaks::hide_compass();
|
||||
}
|
||||
}
|
||||
|
||||
weapon.remoteOwner util::freeze_player_controls( false );
|
||||
}
|
||||
|
||||
function ResetControlInitiatedUponOwnerRespawn()
|
||||
{
|
||||
self endon( "death" );
|
||||
|
||||
self.remoteOwner waittill( "spawned" );
|
||||
|
||||
self.control_initiated = false;
|
||||
}
|
||||
|
||||
function WatchRemoteControlDeactivate()
|
||||
{
|
||||
self notify("WatchRemoteControlDeactivate_remoteWeapons");
|
||||
self endon ("WatchRemoteControlDeactivate_remoteWeapons");
|
||||
weapon = self;
|
||||
weapon endon( "remote_weapon_end" );
|
||||
weapon endon( "death" );
|
||||
weapon.remoteOwner endon( "disconnect" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
timeUsed = 0;
|
||||
while( weapon.remoteOwner UseButtonPressed() )
|
||||
{
|
||||
timeUsed += 0.05;
|
||||
if ( timeUsed > 0.25 )
|
||||
{
|
||||
weapon thread EndRemoteControlWeaponUse( true );
|
||||
return;
|
||||
}
|
||||
{wait(.05);};
|
||||
}
|
||||
{wait(.05);};
|
||||
}
|
||||
}
|
||||
|
||||
function EndRemoteControlWeaponUse( exitRequestedByOwner )
|
||||
{
|
||||
weapon = self;
|
||||
|
||||
if( !isdefined( weapon ) || ( isdefined( weapon.endRemoteControlWeapon ) && weapon.endRemoteControlWeapon ) )
|
||||
return;
|
||||
|
||||
weapon.endRemoteControlWeapon = true;
|
||||
|
||||
remote_controlled = ( isdefined( weapon.control_initiated ) && weapon.control_initiated ) || ( isdefined( weapon.controlled ) && weapon.controlled );
|
||||
|
||||
while ( isdefined( weapon ) && ( weapon.forceWaitRemoteControl === true ) && ( remote_controlled == false ) )
|
||||
{
|
||||
remote_controlled = ( ( isdefined( weapon.control_initiated ) && weapon.control_initiated ) || ( isdefined( weapon.controlled ) && weapon.controlled ) );
|
||||
{wait(.05);};
|
||||
}
|
||||
|
||||
if ( !isdefined( weapon ) )
|
||||
return;
|
||||
|
||||
if( isdefined( weapon.remoteOwner ) && remote_controlled )
|
||||
{
|
||||
|
||||
if( isdefined( weapon.remoteWeaponShutdownDelay ) ) //when changing teams or disconnect, we can skip this
|
||||
{
|
||||
wait( weapon.remoteWeaponShutdownDelay );
|
||||
}
|
||||
|
||||
player = weapon.remoteOwner;
|
||||
|
||||
if( player.dofutz === true )
|
||||
{
|
||||
|
||||
player clientfield::set_to_player( "static_postfx", 1 );
|
||||
|
||||
wait 1;
|
||||
|
||||
if( isdefined( player ) )
|
||||
{
|
||||
player clientfield::set_to_player( "static_postfx", 0 );
|
||||
player.dofutz = false;
|
||||
}
|
||||
}
|
||||
else if ( !exitRequestedByOwner && weapon.watch_remote_weapon_death === true && !IsAlive( weapon ) )
|
||||
{
|
||||
wait ( isdefined( weapon.watch_remote_weapon_death_duration ) ? weapon.watch_remote_weapon_death_duration : 1.0 );
|
||||
}
|
||||
|
||||
if( isdefined( player ) )
|
||||
{
|
||||
player thread FadeToBlackAndBackIn();
|
||||
player waittill( "fade2black" ); // we the prev call to be blocking, in the same time we dont want to be left with black screen if smth external kills this thread.
|
||||
if( remote_controlled )
|
||||
player unlink();
|
||||
player killstreaks::clear_using_remote( true ); // must come before the end use callback, its notify clears all the AI threads on the remote weapons
|
||||
cleared_killstreak_delay = 1;
|
||||
player EnableUsability(); // there are cases where the typical path to enable usability is not called, (because of some endon)
|
||||
}
|
||||
}
|
||||
|
||||
if( isdefined( weapon ) && isdefined( weapon.remoteName ) )
|
||||
{
|
||||
self [[ level.remoteWeapons[ weapon.remoteName ].endUseCallback]]( weapon, exitRequestedByOwner );
|
||||
}
|
||||
|
||||
if( isdefined( weapon ))
|
||||
{
|
||||
weapon.killCamEnt = weapon;
|
||||
|
||||
if( isdefined( weapon.remoteOwner ) )
|
||||
{
|
||||
if ( remote_controlled )
|
||||
{
|
||||
weapon.remoteOwner unlink();
|
||||
if( !( isdefined( cleared_killstreak_delay ) && cleared_killstreak_delay ) )
|
||||
weapon.remoteOwner killstreaks::reset_killstreak_delay_killcam();
|
||||
weapon.remoteOwner util::clientNotify( "nofutz" );
|
||||
}
|
||||
|
||||
if( isdefined( level.gameEnded ) && level.gameEnded )
|
||||
{
|
||||
weapon.remoteOwner util::freeze_player_controls( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( isdefined( weapon ) )
|
||||
{
|
||||
weapon.control_initiated = false;
|
||||
weapon.controlled = false;
|
||||
if( isdefined( weapon.remoteOwner ) )
|
||||
weapon.remoteOwner killstreaks::unhide_compass();
|
||||
|
||||
if( !exitRequestedByOwner || ( isdefined( weapon.one_remote_use ) && weapon.one_remote_use ) )
|
||||
weapon notify( "remote_weapon_end" );
|
||||
}
|
||||
}
|
||||
|
||||
function FadeToBlackAndBackIn()
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
// self endon( "death" ); // never end on death as it may never fade back in
|
||||
|
||||
lui::screen_fade_out( 0.1 );
|
||||
|
||||
self qrdrone::destroyHud();
|
||||
|
||||
{wait(.05);};
|
||||
|
||||
self notify( "fade2black" );
|
||||
|
||||
lui::screen_fade_in( .2 );
|
||||
}
|
||||
|
||||
function stunStaticFX( duration )
|
||||
{
|
||||
self endon( "remove_remote_weapon" );
|
||||
self.fullscreen_static.alpha = 0.65;
|
||||
wait ( duration - 0.5 );
|
||||
time = duration - 0.5;
|
||||
while ( time < duration )
|
||||
{
|
||||
{wait(.05);};
|
||||
time += 0.05;
|
||||
self.fullscreen_static.alpha -= 0.05;
|
||||
}
|
||||
self.fullscreen_static.alpha = 0.15;
|
||||
}
|
||||
|
||||
function destroyRemoteHUD()
|
||||
{
|
||||
self UseServerVisionset( false );
|
||||
self SetInfraredVision( false );
|
||||
if ( isdefined(self.fullscreen_static) )
|
||||
{
|
||||
self.fullscreen_static destroy();
|
||||
}
|
||||
|
||||
if ( isdefined( self.hud_prompt_exit ))
|
||||
{
|
||||
self.hud_prompt_exit destroy();
|
||||
}
|
||||
}
|
||||
|
||||
function set_static( val )
|
||||
{
|
||||
owner = self.owner;
|
||||
if( isdefined( owner ) && owner.usingvehicle && isdefined( owner.viewlockedentity ) && ( owner.viewlockedentity == self ) )
|
||||
{
|
||||
owner clientfield::set_to_player( "static_postfx", val );
|
||||
}
|
||||
}
|
||||
|
||||
function do_static_fx()
|
||||
{
|
||||
self endon( "death" );
|
||||
self set_static( 1 );
|
||||
wait 2;
|
||||
self set_static( 0 );
|
||||
self notify( "static_fx_done" );
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#using scripts\mp\_util;
|
||||
|
||||
|
||||
|
||||
|
||||
#namespace remotemissile;
|
||||
|
||||
function autoexec __init__sytem__() { system::register("remotemissile",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
clientfield::register( "missile", "remote_missile_bomblet_fired", 1, 1, "int",&bomblets_deployed, !true, !true );
|
||||
clientfield::register( "missile", "remote_missile_fired", 1, 2, "int",&missile_fired, !true, !true );
|
||||
}
|
||||
|
||||
function missile_fired( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if( newVal == ( 1 ) )
|
||||
{
|
||||
player = getlocalplayer( localClientNum );
|
||||
owner = self GetOwner( localClientNum );
|
||||
|
||||
clientObjID = util::getNextObjID( localClientNum );
|
||||
|
||||
objective_add( localClientNum, clientObjID, "invisible", self.origin, self.team, owner );
|
||||
Objective_OnEntity( localClientNum, clientObjID, self, true, false, true );
|
||||
self.hellfireObjId = clientObjID;
|
||||
self thread destruction_watcher( localClientNum, clientObjID );
|
||||
|
||||
|
||||
objective_state( localClientNum, clientObjID, "active" );
|
||||
if( player hasPerk( localClientNum, "specialty_showenemyequipment" ) || self.team == player.team )
|
||||
{
|
||||
objective_SetIcon( localClientNum, clientObjID, "remotemissile_target" );
|
||||
objective_SetIconSize( localClientNum, clientObjID, 50 );
|
||||
}
|
||||
|
||||
self thread hud_update( localClientNum );
|
||||
}
|
||||
else if ( newVal == ( 2 ) )
|
||||
{
|
||||
if( isdefined( self.hellfireObjId ) )
|
||||
{
|
||||
self notify( "hellfire_detonated" );
|
||||
objective_delete( localClientNum, self.hellfireObjId );
|
||||
util::releaseObjID( localClientNum, self.hellfireObjId );
|
||||
}
|
||||
}
|
||||
else
|
||||
self notify( "cleanup_objectives" );
|
||||
|
||||
|
||||
ammo_ui_data_model = GetUIModel( GetUIModelForController( localClientNum ), "vehicle.ammo" );
|
||||
if ( isdefined( ammo_ui_data_model ) )
|
||||
SetUIModelValue( ammo_ui_data_model, 1 );
|
||||
}
|
||||
|
||||
function bomblets_deployed( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( bNewEnt && oldVal == newVal )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( newVal == ( 1 ) )
|
||||
{
|
||||
player = getlocalplayer( localClientNum );
|
||||
owner = self GetOwner( localClientNum );
|
||||
|
||||
clientObjID = util::getNextObjID( localClientNum );
|
||||
|
||||
objective_add( localClientNum, clientObjID, "invisible", self.origin, self.team, owner );
|
||||
Objective_OnEntity( localClientNum, clientObjID, self, true, false, true );
|
||||
self thread destruction_watcher( localClientNum, clientObjID );
|
||||
|
||||
|
||||
objective_state( localClientNum, clientObjID, "active" );
|
||||
if( player hasPerk( localClientNum, "specialty_showenemyequipment" ) || player.team == self.team )
|
||||
objective_SetIcon( localClientNum, clientObjID, "remotemissile_target" );
|
||||
}
|
||||
else
|
||||
self notify( "cleanup_objectives" );
|
||||
|
||||
ammo_ui_data_model = GetUIModel( GetUIModelForController( localClientNum ), "vehicle.ammo" );
|
||||
if ( isdefined( ammo_ui_data_model ) )
|
||||
SetUIModelValue( ammo_ui_data_model, 0 );
|
||||
}
|
||||
|
||||
function destruction_watcher( localClientNum, clientObjID )
|
||||
{
|
||||
self util::waittill_any( "death", "entityshutdown", "cleanup_objectives" );
|
||||
wait( 0.1 );
|
||||
if( isdefined( clientObjID ) )
|
||||
{
|
||||
objective_delete( localClientNum, clientObjID );
|
||||
util::releaseObjID( localClientNum, clientObjID );
|
||||
}
|
||||
}
|
||||
|
||||
function hud_update( localClientNum )
|
||||
{
|
||||
self endon( "entityshutdown" );
|
||||
self notify( "remote_missile_singeton");
|
||||
self endon( "remote_missile_singeton");
|
||||
missile = self;
|
||||
|
||||
altitude_ui_data_model = GetUIModel( GetUIModelForController( localClientNum ), "vehicle.altitude" );
|
||||
speed_ui_data_model = GetUIModel( GetUIModelForController( localClientNum ), "vehicle.speed" );
|
||||
|
||||
if( !isdefined( altitude_ui_data_model ) || !isdefined( speed_ui_data_model ) )
|
||||
return;
|
||||
|
||||
prev_z = missile.origin[2];
|
||||
|
||||
fps = 20.0;
|
||||
delay = 1.0 / fps;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
cur_z = missile.origin[2];
|
||||
SetUIModelValue( altitude_ui_data_model, cur_z );
|
||||
|
||||
dist = ( prev_z - cur_z ) * fps;
|
||||
val = dist / 17.6;
|
||||
SetUIModelValue( speed_ui_data_model, val );
|
||||
|
||||
prev_z = cur_z;
|
||||
|
||||
wait ( delay );
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,372 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\challenges_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\hostmigration_shared;
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\tweakables_shared;
|
||||
#using scripts\shared\weapons\_heatseekingmissile;
|
||||
#using scripts\shared\weapons\_weaponobjects;
|
||||
#using scripts\shared\damagefeedback_shared;
|
||||
#using scripts\shared\scoreevents_shared;
|
||||
#using scripts\shared\math_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
|
||||
#using scripts\mp\gametypes\_battlechatter;
|
||||
#using scripts\mp\gametypes\_globallogic_audio;
|
||||
#using scripts\mp\killstreaks\_airsupport;
|
||||
#using scripts\mp\killstreaks\_killstreak_bundles;
|
||||
#using scripts\mp\killstreaks\_killstreak_hacking;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\teams\_teams;
|
||||
#using scripts\mp\_util;
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#namespace satellite;
|
||||
|
||||
|
||||
|
||||
|
||||
#precache( "string", "mpl_killstreak_satellite" );
|
||||
#precache( "string", "KILLSTREAK_EARNED_SATELLITE" );
|
||||
#precache( "string", "KILLSTREAK_SATELLITE_INBOUND" );
|
||||
#precache( "string", "KILLSTREAK_DESTROYED_SATELLITE" );
|
||||
#precache( "string", "KILLSTREAK_SATELLITE_NOT_AVAILABLE" );
|
||||
#precache( "string", "KILLSTREAK_SATELLITE_HACKED" );
|
||||
|
||||
function init()
|
||||
{
|
||||
if ( level.teamBased )
|
||||
{
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
level.activeSatellites[ team ] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
level.activeSatellites = [];
|
||||
}
|
||||
|
||||
level.activePlayerSatellites = [];
|
||||
|
||||
if ( tweakables::getTweakableValue( "killstreak", "allowradardirection" ) )
|
||||
{
|
||||
killstreaks::register( "satellite", "satellite", "killstreak_satellite", "uav_used", &ActivateSatellite );
|
||||
killstreaks::register_strings( "satellite", &"KILLSTREAK_EARNED_SATELLITE", &"KILLSTREAK_SATELLITE_NOT_AVAILABLE", &"KILLSTREAK_SATELLITE_INBOUND", undefined, &"KILLSTREAK_SATELLITE_HACKED" );
|
||||
killstreaks::register_dialog( "satellite", "mpl_killstreak_satellite", "satelliteDialogBundle", undefined, "friendlySatellite", "enemySatellite", "enemySatelliteMultiple", "friendlySatelliteHacked", "enemySatelliteHacked", "requestSatellite", "threatSatellite" );
|
||||
}
|
||||
|
||||
callback::on_connect( &OnPlayerConnect );
|
||||
callback::on_spawned( &OnPlayerSpawned );
|
||||
|
||||
level thread SatelliteTracker();
|
||||
}
|
||||
|
||||
function OnPlayerConnect()
|
||||
{
|
||||
self.entnum = self getEntityNumber();
|
||||
|
||||
if ( !level.teamBased )
|
||||
{
|
||||
level.activeSatellites[ self.entnum ] = 0;
|
||||
}
|
||||
|
||||
level.activePlayerSatellites[ self.entnum ] = 0; // needed for satellite-related kill scores
|
||||
}
|
||||
|
||||
function OnPlayerSpawned( local_client_num )
|
||||
{
|
||||
if ( !level.teambased )
|
||||
{
|
||||
UpdatePlayerSatelliteForDM( self );
|
||||
}
|
||||
}
|
||||
|
||||
function ActivateSatellite()
|
||||
{
|
||||
if( self killstreakrules::isKillstreakAllowed( "satellite", self.team ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
killstreak_id = self killstreakrules::killstreakStart( "satellite", self.team );
|
||||
if( killstreak_id == -1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
minFlyHeight = int( airsupport::getMinimumFlyHeight() );
|
||||
zOffset = minFlyHeight + ( 5500 );
|
||||
|
||||
// pick a random start point from map center
|
||||
travelAngle = RandomFloatRange( (isdefined(level.satellite_spawn_from_angle_min)?level.satellite_spawn_from_angle_min:( 90.0 )), (isdefined(level.satellite_spawn_from_angle_max)?level.satellite_spawn_from_angle_max:( 180.0 )) );
|
||||
travelRadius = airsupport::GetMaxMapWidth() * ( 1.5 );
|
||||
xOffset = sin( travelAngle ) * travelRadius;
|
||||
yOffset = cos( travelAngle ) * travelRadius;
|
||||
|
||||
satellite = spawn( "script_model", airsupport::GetMapCenter() + ( xOffset, yOffset, zOffset ));
|
||||
satellite setModel( "veh_t7_drone_srv_blimp" );
|
||||
satellite SetScale( ( 1 ) );
|
||||
|
||||
satellite.killstreak_id = killstreak_id;
|
||||
satellite.owner = self;
|
||||
satellite.ownerEntNum = self GetEntityNumber();
|
||||
satellite.team = self.team;
|
||||
satellite setTeam( self.team );
|
||||
satellite setOwner( self );
|
||||
satellite killstreaks::configure_team( "satellite", killstreak_id, self, undefined, undefined, &ConfigureTeamPost );
|
||||
satellite killstreak_hacking::enable_hacking( "satellite", &HackedPreFunction, undefined );
|
||||
satellite.targetname = "satellite";
|
||||
satellite.maxhealth = ( 700 );
|
||||
satellite.lowhealth = ( ( 700 ) * 0.5 );
|
||||
satellite.health = 99999;
|
||||
satellite.leaving = false;
|
||||
|
||||
satellite SetCanDamage( true );
|
||||
satellite thread killstreaks::MonitorDamage( "satellite", satellite.maxhealth, &DestroySatellite, satellite.lowhealth, &OnLowHealth, 0, undefined, false );
|
||||
satellite thread killstreaks::WaitTillEMP( &DestroySatelliteByEMP );
|
||||
// satellite.overrideVehicleDamage = &SatelliteDamageOverride; // satellite is not a vehicle right now
|
||||
satellite.killstreakDamageModifier = &killstreakDamageModifier;
|
||||
|
||||
satellite.rocketDamage = ( satellite.maxhealth / ( 3 ) ) + 1;
|
||||
|
||||
/#
|
||||
//Box( airsupport::GetMapCenter() + ( xOffset, yOffset, zOffset ), (-4, -4, 0 ), ( 4, 4, 5000 ), 0, ( 1, 0, 0 ), 0.6, false, 2000 );
|
||||
//Box( airsupport::GetMapCenter() + ( -xOffset, -yoffset, zOffset ), (-4, -4, 0 ), ( 4, 4, 5000 ), 0, ( 0, 1, 0 ), 0.6, false, 2000 );
|
||||
#/
|
||||
|
||||
satellite MoveTo( airsupport::GetMapCenter() + ( -xOffset, -yoffset, zOffset ), ( 40000 ) * 0.001 );
|
||||
|
||||
Target_Set( satellite );
|
||||
|
||||
satellite clientfield::set( "enemyvehicle", 1 );
|
||||
|
||||
satellite thread killstreaks::WaitForTimeout( "satellite", ( 40000 ), &OnTimeout, "death", "crashing" );
|
||||
|
||||
satellite thread heatseekingmissile::MissileTarget_ProximityDetonateIncomingMissile( "death", undefined, true );
|
||||
|
||||
satellite thread Rotate( ( 10 ) );
|
||||
|
||||
self killstreaks::play_killstreak_start_dialog( "satellite", self.team, killstreak_id );
|
||||
satellite thread killstreaks::player_killstreak_threat_tracking( "satellite" );
|
||||
self AddWeaponStat( GetWeapon( "satellite" ), "used", 1 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function HackedPreFunction( hacker )
|
||||
{
|
||||
satellite = self;
|
||||
satellite ResetActiveSatellite();
|
||||
}
|
||||
|
||||
function ConfigureTeamPost( owner, isHacked )
|
||||
{
|
||||
satellite = self;
|
||||
|
||||
satellite thread teams::WaitUntilTeamChangeSingleTon( owner, "Satellite_watch_team_change", &OnTeamChange, self.entNum, "delete", "death", "leaving" );
|
||||
if ( isHacked == false )
|
||||
{
|
||||
satellite teams::HideToSameTeam();
|
||||
}
|
||||
else
|
||||
{
|
||||
satellite SetVisibleToAll();
|
||||
}
|
||||
satellite AddActiveSatellite();
|
||||
}
|
||||
|
||||
function Rotate( duration )
|
||||
{
|
||||
self endon( "death" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
self rotateyaw( -360, duration );
|
||||
wait( duration );
|
||||
}
|
||||
}
|
||||
|
||||
function OnLowHealth( attacker, weapon )
|
||||
{
|
||||
}
|
||||
|
||||
function OnTeamChange( entNum, event )
|
||||
{
|
||||
DestroySatellite( undefined, undefined );
|
||||
}
|
||||
|
||||
function OnTimeout()
|
||||
{
|
||||
self killstreaks::play_pilot_dialog_on_owner( "timeout", "satellite" );
|
||||
|
||||
self.leaving = true;
|
||||
self RemoveActiveSatellite();
|
||||
|
||||
airsupport::Leave( ( 10 ) );
|
||||
wait( ( 10 ) );
|
||||
|
||||
if( Target_IsTarget( self ) )
|
||||
Target_Remove( self );
|
||||
|
||||
self delete();
|
||||
}
|
||||
|
||||
function DestroySatelliteByEMP( attacker, arg )
|
||||
{
|
||||
DestroySatellite( attacker, GetWeapon( "emp" ) );
|
||||
}
|
||||
|
||||
function DestroySatellite( attacker = undefined, weapon = undefined )
|
||||
{
|
||||
attacker = self [[ level.figure_out_attacker ]]( attacker );
|
||||
if ( isdefined( attacker ) && ( !isdefined( self.owner ) || self.owner util::IsEnemyPlayer( attacker ) ) )
|
||||
{
|
||||
challenges::destroyedAircraft( attacker, weapon, false );
|
||||
scoreevents::processScoreEvent( "destroyed_satellite", attacker, self.owner, weapon );
|
||||
attacker challenges::addFlySwatterStat( weapon, self );
|
||||
LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_SATELLITE", attacker.entnum );
|
||||
if( !self.leaving )
|
||||
self killstreaks::play_destroyed_dialog_on_owner( "satellite", self.killstreak_id );
|
||||
}
|
||||
|
||||
self notify( "crashing" );
|
||||
|
||||
params = level.killstreakBundle["satellite"];
|
||||
if( isdefined( params.ksExplosionFX ) )
|
||||
PlayFXOnTag( params.ksExplosionFX, self, "tag_origin" );
|
||||
|
||||
self setModel( "tag_origin" );
|
||||
if( Target_IsTarget( self ) )
|
||||
Target_Remove( self );
|
||||
|
||||
wait( 0.5 );
|
||||
|
||||
if( !self.leaving )
|
||||
self RemoveActiveSatellite();
|
||||
|
||||
self delete();
|
||||
}
|
||||
|
||||
function HasSatellite( team_or_entnum )
|
||||
{
|
||||
return level.activeSatellites[ team_or_entnum ] > 0;
|
||||
}
|
||||
|
||||
function AddActiveSatellite()
|
||||
{
|
||||
if ( level.teamBased )
|
||||
{
|
||||
level.activeSatellites[ self.team ]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
level.activeSatellites[ self.ownerEntNum ]++;
|
||||
}
|
||||
|
||||
level.activePlayerSatellites[ self.ownerEntNum ]++;
|
||||
|
||||
level notify( "satellite_update" );
|
||||
}
|
||||
|
||||
function RemoveActiveSatellite()
|
||||
{
|
||||
self ResetActiveSatellite();
|
||||
|
||||
killstreakrules::killstreakStop( "satellite", self.originalteam, self.killstreak_id );
|
||||
}
|
||||
|
||||
function ResetActiveSatellite()
|
||||
{
|
||||
if( level.teamBased )
|
||||
{
|
||||
level.activeSatellites[ self.team ]--;
|
||||
|
||||
assert( level.activeSatellites[ self.team ] >= 0 );
|
||||
if( level.activeSatellites[ self.team ] < 0 )
|
||||
{
|
||||
level.activeSatellites[ self.team ] = 0;
|
||||
}
|
||||
}
|
||||
else if ( isdefined( self.ownerEntNum ) )
|
||||
{
|
||||
level.activeSatellites[ self.ownerEntNum ]--;
|
||||
|
||||
assert( level.activeSatellites[ self.ownerEntNum ] >= 0 );
|
||||
if( level.activeSatellites[ self.ownerEntNum ] < 0 )
|
||||
{
|
||||
level.activeSatellites[ self.ownerEntNum ] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
assert( isdefined( self.ownerEntNum ) );
|
||||
level.activePlayerSatellites[ self.ownerEntNum ]--;
|
||||
assert( level.activePlayerSatellites[ self.ownerEntNum ] >= 0 );
|
||||
|
||||
level notify( "satellite_update" );
|
||||
}
|
||||
|
||||
function SatelliteTracker()
|
||||
{
|
||||
level endon ( "game_ended" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
level waittill ( "satellite_update" );
|
||||
|
||||
// intentionally keeping both teambased and non-teambased logic for now
|
||||
// TODO: one "might" be able to change it to teambased only; when trying to do so, watch for knock-on effects
|
||||
|
||||
if( level.teamBased )
|
||||
{
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
activeSatellites = level.activeSatellites[ team ];
|
||||
activeSatellitesAndUAVs = activeSatellites + ( ( isdefined( level.activeUAVs ) ) ? level.activeUAVs[ team ] : 0 );
|
||||
|
||||
SetTeamSatellite( team, ( activeSatellites > 0 ) );
|
||||
util::set_team_radar( team, ( activeSatellitesAndUAVs > 0 ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < level.players.size; i++ )
|
||||
{
|
||||
UpdatePlayerSatelliteForDM( level.players[ i ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function UpdatePlayerSatelliteForDM( player )
|
||||
{
|
||||
if( !isdefined( player.entnum ) )
|
||||
{
|
||||
player.entnum = player getEntityNumber();
|
||||
}
|
||||
|
||||
activeSatellites = level.activeSatellites[ player.entnum ];
|
||||
activeSatellitesAndUAVs = activeSatellites + ( ( isdefined( level.activeUAVs ) ) ? level.activeUAVs[ player.entnum ] : 0 );
|
||||
|
||||
player SetClientUIVisibilityFlag( "radar_client", ( activeSatellitesAndUAVs > 0 ) );
|
||||
player.hasSatellite = ( activeSatellites > 0 );
|
||||
}
|
||||
|
||||
function killstreakDamageModifier( damage, attacker, direction, point, sMeansOfDeath, tagName, modelName, partname, weapon, flags, inflictor, chargeLevel )
|
||||
{
|
||||
if( ( sMeansOfDeath == "MOD_PISTOL_BULLET" ) || ( sMeansOfDeath == "MOD_RIFLE_BULLET" ) )
|
||||
return 0;
|
||||
|
||||
if ( sMeansOfDeath == "MOD_PROJECTILE_SPLASH" )
|
||||
return 0;
|
||||
|
||||
return damage;
|
||||
}
|
||||
@@ -0,0 +1,588 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\array_shared;
|
||||
#using scripts\shared\audio_shared;
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\challenges_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\math_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\statemachine_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\turret_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\vehicle_ai_shared;
|
||||
#using scripts\shared\vehicle_death_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
#using scripts\shared\vehicles\_wasp;
|
||||
#using scripts\shared\visionset_mgr_shared;
|
||||
#using scripts\shared\scoreevents_shared;
|
||||
#using scripts\shared\weapons\_heatseekingmissile;
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\gametypes\_shellshock;
|
||||
#using scripts\mp\gametypes\_spawning;
|
||||
#using scripts\mp\killstreaks\_airsupport;
|
||||
#using scripts\mp\killstreaks\_helicopter;
|
||||
#using scripts\mp\killstreaks\_killstreak_bundles;
|
||||
#using scripts\mp\killstreaks\_killstreak_detect;
|
||||
#using scripts\mp\killstreaks\_killstreak_hacking;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_qrdrone;
|
||||
#using scripts\mp\killstreaks\_rcbomb;
|
||||
#using scripts\mp\killstreaks\_remote_weapons;
|
||||
#using scripts\mp\teams\_teams;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
|
||||
#precache( "string", "mpl_killstreak_sentinel_strt" );
|
||||
#precache( "string", "KILLSTREAK_SENTINEL_HACKED" );
|
||||
#precache( "string", "KILLSTREAK_SENTINEL_INBOUND" );
|
||||
#precache( "string", "KILLSTREAK_SENTINEL_NOT_AVAILABLE" );
|
||||
#precache( "string", "KILLSTREAK_SENTINEL_EARNED" );
|
||||
#precache( "string", "KILLSTREAK_SENTINEL_NOT_PLACEABLE" );
|
||||
#precache( "string", "KILLSTREAK_DESTROYED_SENTINEL" );
|
||||
|
||||
#precache( "triggerstring", "KILLSTREAK_SENTINEL_USE_REMOTE" );
|
||||
|
||||
#namespace sentinel;
|
||||
|
||||
|
||||
|
||||
|
||||
function init()
|
||||
{
|
||||
killstreaks::register( "sentinel", "sentinel", "killstreak_" + "sentinel", "sentinel" + "_used", &ActivateSentinel, true );
|
||||
killstreaks::register_strings( "sentinel", &"KILLSTREAK_SENTINEL_EARNED", &"KILLSTREAK_SENTINEL_NOT_AVAILABLE", &"KILLSTREAK_SENTINEL_INBOUND", undefined, &"KILLSTREAK_SENTINEL_HACKED" );
|
||||
killstreaks::register_dialog( "sentinel", "mpl_killstreak_sentinel_strt", "sentinelDialogBundle", "sentinelPilotDialogBundle", "friendlySentinel", "enemySentinel", "enemySentinelMultiple", "friendlySentinelHacked", "enemySentinelHacked", "requestSentinel", "threatSentinel" );
|
||||
killstreaks::register_alt_weapon( "sentinel", "killstreak_remote" );
|
||||
killstreaks::register_alt_weapon( "sentinel", "sentinel_turret" );
|
||||
remote_weapons::RegisterRemoteWeapon( "sentinel", &"KILLSTREAK_SENTINEL_USE_REMOTE", &StartSentinelRemoteControl, &EndSentinelRemoteControl, false );
|
||||
|
||||
// TODO: Move to killstreak data
|
||||
level.killstreaks["sentinel"].threatOnKill = true;
|
||||
|
||||
vehicle::add_main_callback( "veh_sentinel_mp", &InitSentinel );
|
||||
|
||||
visionset_mgr::register_info( "visionset", "sentinel_visionset", 1, 100, 16, true, &visionset_mgr::ramp_in_out_thread_per_player_death_shutdown, false );
|
||||
}
|
||||
|
||||
function InitSentinel()
|
||||
{
|
||||
self.settings = struct::get_script_bundle( "vehiclecustomsettings", self.scriptbundlesettings );
|
||||
Target_Set( self, ( 0, 0, 0 ) );
|
||||
self.health = self.healthdefault;
|
||||
self.numFlares = 1;
|
||||
self.damageTaken = 0;
|
||||
self vehicle::friendly_fire_shield();
|
||||
self EnableAimAssist();
|
||||
self SetNearGoalNotifyDist( ( 40 ) );
|
||||
self SetHoverParams( ( 50.0 ), ( 100.0 ), ( 100.0 ) );
|
||||
self.fovcosine = 0; // +/-90 degrees = 180
|
||||
self.fovcosinebusy = 0; //+/- 55 degrees = 110 fov
|
||||
self.vehAirCraftCollisionEnabled = true;
|
||||
|
||||
self thread vehicle_ai::nudge_collision();
|
||||
self thread heatseekingmissile::MissileTarget_ProximityDetonateIncomingMissile( "explode", "death" ); // fires chaff if needed
|
||||
self thread helicopter::create_flare_ent( (0,0,-20) );
|
||||
self thread audio::vehicleSpawnContext();
|
||||
self.do_scripted_crash = false;
|
||||
|
||||
self.overrideVehicleDamage = &SentinelDamageOverride;
|
||||
self.selfDestruct = false;
|
||||
|
||||
self.enable_target_laser = true;
|
||||
self.aggresive_navvolume_recover = true;
|
||||
|
||||
self vehicle_ai::init_state_machine_for_role( "default" );
|
||||
self vehicle_ai::get_state_callbacks( "combat" ).enter_func = &wasp::state_combat_enter;
|
||||
self vehicle_ai::get_state_callbacks( "combat" ).update_func = &wasp::state_combat_update;
|
||||
self vehicle_ai::get_state_callbacks( "death" ).update_func = &wasp::state_death_update;
|
||||
self vehicle_ai::get_state_callbacks( "driving" ).enter_func = &driving_enter;
|
||||
|
||||
wasp::init_guard_points();
|
||||
self vehicle_ai::add_state( "guard",
|
||||
&wasp::state_guard_enter,
|
||||
&wasp::state_guard_update,
|
||||
&wasp::state_guard_exit );
|
||||
|
||||
vehicle_ai::add_utility_connection( "combat", "guard", &wasp::state_guard_can_enter );
|
||||
vehicle_ai::add_utility_connection( "guard", "combat" );
|
||||
vehicle_ai::add_interrupt_connection( "guard", "emped", "emped" );
|
||||
vehicle_ai::add_interrupt_connection( "guard", "surge", "surge" );
|
||||
vehicle_ai::add_interrupt_connection( "guard", "off", "shut_off" );
|
||||
vehicle_ai::add_interrupt_connection( "guard", "pain", "pain" );
|
||||
vehicle_ai::add_interrupt_connection( "guard", "driving", "enter_vehicle" );
|
||||
|
||||
self vehicle_ai::StartInitialState( "combat" );
|
||||
}
|
||||
|
||||
function driving_enter( params )
|
||||
{
|
||||
vehicle_ai::defaultstate_driving_enter( params );
|
||||
}
|
||||
|
||||
function drone_pain_for_time( time, stablizeParam, restoreLookPoint, weapon )
|
||||
{
|
||||
self endon( "death" );
|
||||
|
||||
self.painStartTime = GetTime();
|
||||
|
||||
if ( !( isdefined( self.inpain ) && self.inpain ) && isdefined( self.health ) && self.health > 0 )
|
||||
{
|
||||
self.inpain = true;
|
||||
|
||||
|
||||
while ( GetTime() < self.painStartTime + time * 1000 )
|
||||
{
|
||||
self SetVehVelocity( self.velocity * stablizeParam );
|
||||
self SetAngularVelocity( self GetAngularVelocity() * stablizeParam );
|
||||
wait 0.1;
|
||||
}
|
||||
|
||||
if ( isdefined( restoreLookPoint ) && isdefined( self.health ) && self.health > 0 )
|
||||
{
|
||||
restoreLookEnt = Spawn( "script_model", restoreLookPoint );
|
||||
restoreLookEnt SetModel( "tag_origin" );
|
||||
|
||||
self ClearLookAtEnt();
|
||||
self SetLookAtEnt( restoreLookEnt );
|
||||
self setTurretTargetEnt( restoreLookEnt );
|
||||
wait 1.5;
|
||||
|
||||
self ClearLookAtEnt();
|
||||
self ClearTurretTarget();
|
||||
restoreLookEnt delete();
|
||||
}
|
||||
|
||||
if( weapon.isEmp ) remote_weapons::set_static( 0 );
|
||||
|
||||
self.inpain = false;
|
||||
}
|
||||
}
|
||||
|
||||
function drone_pain( eAttacker, damageType, hitPoint, hitDirection, hitLocationInfo, partName, weapon )
|
||||
{
|
||||
if ( !( isdefined( self.inpain ) && self.inpain ) )
|
||||
{
|
||||
yaw_vel = math::randomSign() * RandomFloatRange( 280, 320 );
|
||||
|
||||
ang_vel = self GetAngularVelocity();
|
||||
ang_vel += ( RandomFloatRange( -120, -100 ), yaw_vel, RandomFloatRange( -200, 200 ) );
|
||||
self SetAngularVelocity( ang_vel );
|
||||
|
||||
self thread drone_pain_for_time( 0.8, 0.7, undefined, weapon );
|
||||
}
|
||||
}
|
||||
|
||||
function SentinelDamageOverride( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
|
||||
{
|
||||
if( sMeansOfDeath == "MOD_TRIGGER_HURT" )
|
||||
return 0;
|
||||
|
||||
emp_damage = self.healthdefault * ( 0.5 ) + 0.5;
|
||||
|
||||
iDamage = killstreaks::OnDamagePerWeapon( "sentinel", eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, self.maxhealth, &destroyed_cb, self.maxhealth*0.4, &low_health_cb, emp_damage, undefined, true, 1.0 );
|
||||
|
||||
if( isdefined( eAttacker ) && isdefined( eAttacker.team ) && eAttacker.team != self.team )
|
||||
{
|
||||
drone_pain( eAttacker, sMeansOfDeath, vPoint, vDir, sHitLoc, partName, weapon );
|
||||
}
|
||||
self.damageTaken += iDamage;
|
||||
return iDamage;
|
||||
}
|
||||
|
||||
function destroyed_cb( attacker, weapon )
|
||||
{
|
||||
if( isdefined( attacker ) && isdefined( attacker.team ) && attacker.team != self.team )
|
||||
self.owner.dofutz = true;
|
||||
}
|
||||
|
||||
function low_health_cb( attacker, weapon )
|
||||
{
|
||||
if( self.playedDamaged == false )
|
||||
{
|
||||
self killstreaks::play_pilot_dialog_on_owner( "damaged", "sentinel", self.killstreak_id );
|
||||
self.playedDamaged = true;
|
||||
}
|
||||
}
|
||||
|
||||
function CalcSpawnOrigin( origin, angles )
|
||||
{
|
||||
heightOffset = rcbomb::GetPlacementStartHeight();
|
||||
|
||||
mins = ( -5, -5, 0 );
|
||||
maxs = ( 5, 5, 10 );
|
||||
|
||||
startPoints = [];
|
||||
testangles = [];
|
||||
|
||||
testangles[0] = ( 0, 0, 0 );
|
||||
testangles[1] = ( 0, 30, 0 );
|
||||
testangles[2] = ( 0, -30, 0 );
|
||||
testangles[3] = ( 0, 60, 0 );
|
||||
testangles[4] = ( 0, -60, 0 );
|
||||
testangles[3] = ( 0, 90, 0 );
|
||||
testangles[4] = ( 0, -90, 0 );
|
||||
|
||||
bestOrigin = origin;
|
||||
bestAngles = angles;
|
||||
bestFrac = 0;
|
||||
|
||||
for( i = 0; i < testangles.size; i++ )
|
||||
{
|
||||
startPoint = origin + ( 0, 0, heightOffset );
|
||||
endPoint = startPoint + VectorScale( anglestoforward( ( 0, angles[1], 0 ) + testangles[i] ), ( 70 ) );
|
||||
|
||||
mask = (1 << 0) | (1 << 1);
|
||||
trace = physicstrace( startPoint, endPoint, mins, maxs, self, mask );
|
||||
|
||||
if( isdefined( trace["entity"] ) && IsPlayer( trace["entity"] ) )
|
||||
continue;
|
||||
|
||||
if( trace["fraction"] > bestFrac )
|
||||
{
|
||||
bestFrac = trace["fraction"];
|
||||
bestOrigin = trace["position"];
|
||||
bestAngles = ( 0, angles[1], 0 ) + testangles[i];
|
||||
if( bestFrac == 1 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( bestFrac > 0 )
|
||||
{
|
||||
if( Distance2DSquared( origin, bestOrigin ) < 20 * 20 )
|
||||
return undefined;
|
||||
|
||||
trace = physicstrace( bestOrigin, bestOrigin + ( 0, 0, ( 25 ) ), mins, maxs, self, mask );
|
||||
|
||||
placement = SpawnStruct();
|
||||
placement.origin = trace["position"];
|
||||
placement.angles = bestAngles;
|
||||
return placement;
|
||||
}
|
||||
else
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function ActivateSentinel( killstreakType )
|
||||
{
|
||||
assert( IsPlayer( self ) );
|
||||
player = self;
|
||||
|
||||
if( !IsNavVolumeLoaded() )
|
||||
{
|
||||
/# IPrintLnBold( "Error: NavVolume Not Loaded" ); #/
|
||||
self iPrintLnBold( &"KILLSTREAK_SENTINEL_NOT_AVAILABLE" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( player IsPlayerSwimming() )
|
||||
{
|
||||
self iPrintLnBold( &"KILLSTREAK_SENTINEL_NOT_PLACEABLE" );
|
||||
return false;
|
||||
}
|
||||
|
||||
spawnPos = CalcSpawnOrigin( player.origin, player.angles );
|
||||
if( !isdefined( spawnPos ) )
|
||||
{
|
||||
self iPrintLnBold( &"KILLSTREAK_SENTINEL_NOT_PLACEABLE" );
|
||||
return false;
|
||||
}
|
||||
|
||||
killstreak_id = player killstreakrules::killstreakStart( "sentinel", player.team, false, true );
|
||||
if( killstreak_id == (-1) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
player AddWeaponStat( GetWeapon( "sentinel" ), "used", 1 );
|
||||
|
||||
sentinel = SpawnVehicle( "veh_sentinel_mp", spawnPos.origin, spawnPos.angles, "dynamic_spawn_ai" );
|
||||
|
||||
sentinel killstreaks::configure_team( "sentinel", killstreak_id, player, "small_vehicle", undefined, &ConfigureTeamPost );
|
||||
sentinel killstreak_hacking::enable_hacking( "sentinel", &HackedCallbackPre, &HackedCallbackPost );
|
||||
sentinel.killstreak_id = killstreak_id;
|
||||
sentinel.killstreak_end_time = GetTime() + ( 60000 );
|
||||
sentinel.original_vehicle_type = sentinel.vehicletype;
|
||||
sentinel.ignore_vehicle_underneath_splash_scalar = true;
|
||||
|
||||
sentinel clientfield::set( "enemyvehicle", 1 );
|
||||
sentinel.hardpointType = "sentinel";
|
||||
sentinel.soundmod = "player";
|
||||
|
||||
sentinel.maxhealth = killstreak_bundles::get_max_health( "sentinel" );
|
||||
sentinel.lowhealth = killstreak_bundles::get_low_health( "sentinel" );
|
||||
sentinel.health = sentinel.maxhealth;
|
||||
sentinel.hackedhealth = killstreak_bundles::get_hacked_health( "sentinel" );
|
||||
sentinel.rocketDamage = ( sentinel.maxhealth / ( 1 ) ) + 1;
|
||||
sentinel.playedDamaged = false;
|
||||
sentinel.treat_owner_damage_as_friendly_fire = true;
|
||||
sentinel.ignore_team_kills = true;
|
||||
sentinel thread HealthMonitor();
|
||||
|
||||
sentinel.goalradius = ( 1200 );
|
||||
sentinel.goalHeight = 500;
|
||||
//sentinel SetGoal( player, false, sentinel.goalRadius, sentinel.goalHeight );
|
||||
sentinel.enable_guard = true;
|
||||
sentinel.always_face_enemy = true;
|
||||
|
||||
sentinel thread killstreaks::WaitForTimeout( "sentinel", ( 60000 ), &OnTimeout, "sentinel_shutdown" );
|
||||
sentinel thread WatchWater();
|
||||
sentinel thread WatchDeath();
|
||||
sentinel thread WatchShutdown();
|
||||
|
||||
player remote_weapons::UseRemoteWeapon( sentinel, "sentinel", false );
|
||||
|
||||
sentinel killstreaks::play_pilot_dialog_on_owner( "arrive", "sentinel", killstreak_id );
|
||||
|
||||
sentinel vehicle::init_target_group();
|
||||
sentinel vehicle::add_to_target_group( sentinel );
|
||||
|
||||
self killstreaks::play_killstreak_start_dialog( "sentinel", self.team, killstreak_id );
|
||||
|
||||
sentinel thread WatchGameEnded();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function HackedCallbackPre( hacker )
|
||||
{
|
||||
sentinel = self;
|
||||
sentinel.owner unlink();
|
||||
sentinel clientfield::set( "vehicletransition", 0 );
|
||||
if( sentinel.controlled === true )
|
||||
visionset_mgr::deactivate( "visionset", "sentinel_visionset", sentinel.owner );
|
||||
sentinel.owner remote_weapons::RemoveAndAssignNewRemoteControlTrigger( sentinel.useTrigger );
|
||||
sentinel remote_weapons::EndRemoteControlWeaponUse( true );
|
||||
EndSentinelRemoteControl( sentinel, true );
|
||||
}
|
||||
|
||||
function HackedCallbackPost( hacker )
|
||||
{
|
||||
sentinel = self;
|
||||
|
||||
hacker remote_weapons::UseRemoteWeapon( sentinel, "sentinel", false );
|
||||
sentinel notify("WatchRemoteControlDeactivate_remoteWeapons");
|
||||
sentinel.killstreak_end_time = hacker killstreak_hacking::set_vehicle_drivable_time_starting_now( sentinel );
|
||||
}
|
||||
|
||||
function ConfigureTeamPost( owner, isHacked )
|
||||
{
|
||||
sentinel = self;
|
||||
sentinel thread WatchTeamChange();
|
||||
}
|
||||
|
||||
function WatchGameEnded()
|
||||
{
|
||||
sentinel = self;
|
||||
sentinel endon( "death" );
|
||||
|
||||
level waittill("game_ended");
|
||||
|
||||
sentinel.abandoned = true;
|
||||
sentinel.selfDestruct = true;
|
||||
sentinel notify( "sentinel_shutdown" );
|
||||
}
|
||||
|
||||
function StartSentinelRemoteControl( sentinel )
|
||||
{
|
||||
player = self;
|
||||
assert( IsPlayer( player ) );
|
||||
|
||||
sentinel UseVehicle( player, 0 );
|
||||
|
||||
sentinel clientfield::set( "vehicletransition", 1 );
|
||||
sentinel thread audio::sndUpdateVehicleContext(true);
|
||||
sentinel thread vehicle::monitor_missiles_locked_on_to_me( player );
|
||||
|
||||
sentinel.inHeliProximity = false;
|
||||
sentinel.treat_owner_damage_as_friendly_fire = false;
|
||||
sentinel.ignore_team_kills = false;
|
||||
|
||||
minHeightOverride = undefined;
|
||||
minz_struct = struct::get( "vehicle_oob_minz", "targetname");
|
||||
if( isdefined( minz_struct ) )
|
||||
minHeightOverride = minz_struct.origin[2];
|
||||
|
||||
sentinel thread qrdrone::QRDrone_watch_distance( ( 0 ), minHeightOverride );
|
||||
sentinel.distance_shutdown_override = &SentinelDistanceFailure;
|
||||
|
||||
player vehicle::set_vehicle_drivable_time( ( 60000 ), sentinel.killstreak_end_time );
|
||||
visionset_mgr::activate( "visionset", "sentinel_visionset", player, 1, 90000, 1 );
|
||||
|
||||
if ( isdefined( sentinel.PlayerDrivenVersion ) )
|
||||
sentinel SetVehicleType( sentinel.PlayerDrivenVersion );
|
||||
}
|
||||
|
||||
function EndSentinelRemoteControl( sentinel, exitRequestedByOwner )
|
||||
{
|
||||
sentinel.treat_owner_damage_as_friendly_fire = true;
|
||||
sentinel.ignore_team_kills = true;
|
||||
|
||||
if ( isdefined( sentinel.owner ) )
|
||||
{
|
||||
sentinel.owner vehicle::stop_monitor_missiles_locked_on_to_me();
|
||||
if( sentinel.controlled === true )
|
||||
visionset_mgr::deactivate( "visionset", "sentinel_visionset", sentinel.owner );
|
||||
}
|
||||
|
||||
if( exitRequestedByOwner )
|
||||
{
|
||||
if ( isdefined( sentinel.owner ) )
|
||||
{
|
||||
sentinel.owner qrdrone::destroyHud();
|
||||
sentinel.owner unlink();
|
||||
sentinel clientfield::set( "vehicletransition", 0 );
|
||||
}
|
||||
sentinel thread audio::sndUpdateVehicleContext(false);
|
||||
}
|
||||
|
||||
if ( isdefined( sentinel.original_vehicle_type ) )
|
||||
sentinel SetVehicleType( sentinel.original_vehicle_type );
|
||||
|
||||
}
|
||||
|
||||
function OnTimeout()
|
||||
{
|
||||
sentinel = self;
|
||||
|
||||
sentinel killstreaks::play_pilot_dialog_on_owner( "timeout", "sentinel" );
|
||||
|
||||
params = level.killstreakBundle["sentinel"];
|
||||
|
||||
if( isdefined( sentinel.owner ) )
|
||||
{
|
||||
RadiusDamage( sentinel.origin,
|
||||
params.ksExplosionOuterRadius,
|
||||
params.ksExplosionInnerDamage,
|
||||
params.ksExplosionOuterDamage,
|
||||
sentinel.owner,
|
||||
"MOD_EXPLOSIVE",
|
||||
GetWeapon( "sentinel" ) );
|
||||
if( isdefined( params.ksExplosionRumble ) )
|
||||
sentinel.owner PlayRumbleOnEntity( params.ksExplosionRumble );
|
||||
}
|
||||
|
||||
sentinel notify( "sentinel_shutdown" );
|
||||
}
|
||||
|
||||
function HealthMonitor()
|
||||
{
|
||||
self endon( "death" );
|
||||
|
||||
params = level.killstreakBundle["sentinel"];
|
||||
|
||||
if( isdefined( params.fxLowHealth ) )
|
||||
{
|
||||
while( 1 )
|
||||
{
|
||||
if( self.lowhealth > self.health )
|
||||
{
|
||||
PlayFXOnTag( params.fxLowHealth, self, "tag_origin" );
|
||||
break;
|
||||
}
|
||||
{wait(.05);};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SentinelDistanceFailure()
|
||||
{
|
||||
sentinel = self;
|
||||
|
||||
sentinel notify( "sentinel_shutdown" );
|
||||
}
|
||||
|
||||
function WatchDeath()
|
||||
{
|
||||
sentinel = self;
|
||||
sentinel waittill( "death", attacker, damageFromUnderneath, weapon, point, dir, modType );
|
||||
sentinel notify( "sentinel_shutdown" );
|
||||
|
||||
attacker = self [[ level.figure_out_attacker ]]( attacker );
|
||||
if ( isdefined( attacker ) && ( !isdefined( self.owner ) || self.owner util::IsEnemyPlayer( attacker ) ) )
|
||||
{
|
||||
if ( isPlayer( attacker ) )
|
||||
{
|
||||
challenges::destroyedAircraft( attacker, weapon, sentinel.controlled === true );
|
||||
attacker challenges::addFlySwatterStat( weapon, self );
|
||||
attacker AddWeaponStat( weapon, "destroy_aitank_or_setinel", 1 );
|
||||
scoreevents::processScoreEvent( "destroyed_sentinel", attacker, sentinel.owner, weapon );
|
||||
if ( modType == "MOD_RIFLE_BULLET" || modType == "MOD_PISTOL_BULLET" )
|
||||
{
|
||||
attacker addPlayerStat( "shoot_down_sentinel", 1 );
|
||||
}
|
||||
LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_SENTINEL", attacker.entnum );
|
||||
}
|
||||
|
||||
if ( isdefined( sentinel ) && isdefined( sentinel.owner ) )
|
||||
{
|
||||
sentinel killstreaks::play_destroyed_dialog_on_owner( "sentinel", sentinel.killstreak_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function WatchTeamChange()
|
||||
{
|
||||
self notify( "Sentinel_WatchTeamChange_Singleton" );
|
||||
self endon ( "Sentinel_WatchTeamChange_Singleton" );
|
||||
sentinel = self;
|
||||
|
||||
sentinel endon( "sentinel_shutdown" );
|
||||
sentinel.owner util::waittill_any( "joined_team", "disconnect", "joined_spectators" );
|
||||
sentinel notify( "sentinel_shutdown" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function WatchWater()
|
||||
{
|
||||
sentinel = self;
|
||||
sentinel endon( "sentinel_shutdown" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
wait ( 0.1 );
|
||||
trace = physicstrace( self.origin + ( 0, 0, 10 ), self.origin + ( 0, 0, 6 ), ( -2, -2, -2 ), ( 2, 2, 2 ), self, ( (1 << 2) ));
|
||||
if( trace["fraction"] < 1.0 )
|
||||
break;
|
||||
}
|
||||
|
||||
sentinel notify( "sentinel_shutdown" );
|
||||
}
|
||||
|
||||
function WatchShutdown()
|
||||
{
|
||||
sentinel = self;
|
||||
|
||||
sentinel waittill( "sentinel_shutdown" );
|
||||
|
||||
if( ( isdefined( sentinel.control_initiated ) && sentinel.control_initiated ) || ( isdefined( sentinel.controlled ) && sentinel.controlled ) )
|
||||
{
|
||||
sentinel remote_weapons::EndRemoteControlWeaponUse( false );
|
||||
while( ( isdefined( sentinel.control_initiated ) && sentinel.control_initiated ) || ( isdefined( sentinel.controlled ) && sentinel.controlled ) )
|
||||
{wait(.05);};
|
||||
}
|
||||
|
||||
if( isdefined( sentinel.owner ) )
|
||||
{
|
||||
sentinel.owner qrdrone::destroyHud();
|
||||
}
|
||||
|
||||
killstreakrules::killstreakStop( "sentinel", sentinel.originalTeam, sentinel.killstreak_id );
|
||||
|
||||
if( isalive( sentinel ) )
|
||||
sentinel Kill();
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,52 @@
|
||||
#using scripts\codescripts\struct;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\visionset_mgr_shared;
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
|
||||
#using_animtree( "mp_autoturret" );
|
||||
|
||||
#namespace autoturret;
|
||||
|
||||
function autoexec __init__sytem__() { system::register("autoturret",&__init__,undefined,undefined); }
|
||||
|
||||
function __init__()
|
||||
{
|
||||
clientfield::register( "vehicle", "auto_turret_open", 1, 1, "int", &turret_open, !true, !true );
|
||||
clientfield::register( "scriptmover", "auto_turret_init", 1, 1, "int", &turret_init_anim, !true, !true );
|
||||
clientfield::register( "scriptmover", "auto_turret_close", 1, 1, "int", &turret_close_anim, !true, !true );
|
||||
|
||||
visionset_mgr::register_visionset_info( "turret_visionset", 1, 16, undefined, "mp_vehicles_turret" );
|
||||
}
|
||||
|
||||
function turret_init_anim( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( !newVal )
|
||||
return;
|
||||
|
||||
self UseAnimTree( #animtree );
|
||||
self SetAnimRestart( %o_turret_sentry_close, 1.0, 0.0, 1.0 );
|
||||
self SetAnimTime( %o_turret_sentry_close, 1.0 );
|
||||
}
|
||||
|
||||
function turret_open( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( !newVal )
|
||||
return;
|
||||
|
||||
self UseAnimTree( #animtree );
|
||||
self SetAnimRestart( %o_turret_sentry_deploy, 1.0, 0.0, 1.0 );
|
||||
}
|
||||
|
||||
function turret_close_anim( localClientNum, oldVal, newVal, bNewEnt, bInitialSnap, fieldName, bWasTimeJump )
|
||||
{
|
||||
if ( !newVal )
|
||||
return;
|
||||
|
||||
self UseAnimTree( #animtree );
|
||||
self SetAnimRestart( %o_turret_sentry_close, 1.0, 0.0, 1.0 );
|
||||
}
|
||||
@@ -0,0 +1,621 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\mp\_util;
|
||||
#using scripts\mp\gametypes\_globallogic_audio;
|
||||
#using scripts\mp\gametypes\_hostmigration;
|
||||
#using scripts\mp\gametypes\_spawning;
|
||||
#using scripts\mp\killstreaks\_airsupport;
|
||||
#using scripts\mp\killstreaks\_emp;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\killstreaks\_killstreak_bundles;
|
||||
#using scripts\mp\killstreaks\_placeables;
|
||||
#using scripts\mp\killstreaks\_remote_weapons;
|
||||
#using scripts\mp\killstreaks\_killstreak_hacking;
|
||||
#using scripts\mp\teams\_teams;
|
||||
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\challenges_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\hostmigration_shared;
|
||||
#using scripts\shared\scoreevents_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\popups_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\weapons\_weaponobjects;
|
||||
#using scripts\shared\turret_shared;
|
||||
#using scripts\shared\vehicle_shared;
|
||||
#using scripts\shared\vehicle_death_shared;
|
||||
#using scripts\shared\visionset_mgr_shared;
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#precache( "string", "KILLSTREAK_EARNED_AUTO_TURRET" );
|
||||
#precache( "string", "KILLSTREAK_AUTO_TURRET_INBOUND" );
|
||||
#precache( "string", "KILLSTREAK_AUTO_TURRET_NOT_AVAILABLE" );
|
||||
#precache( "string", "KILLSTREAK_AUTO_TURRET_HACKED" );
|
||||
#precache( "string", "KILLSTREAK_DESTROYED_AUTO_TURRET" );
|
||||
#precache( "triggerstring", "KILLSTREAK_AUTO_TURRET_PLACE_TURRET_HINT" );
|
||||
#precache( "triggerstring", "KILLSTREAK_AUTO_TURRET_INVALID_TURRET_LOCATION" );
|
||||
#precache( "triggerstring", "KILLSTREAK_SENTRY_TURRET_PICKUP" );
|
||||
#precache( "triggerstring", "MP_REMOTE_USE_TURRET" );
|
||||
#precache( "string", "mpl_killstreak_auto_turret" );
|
||||
|
||||
#using_animtree( "mp_autoturret" );
|
||||
|
||||
|
||||
|
||||
|
||||
// tu1: make sure this matches the same value in placeables.gsc
|
||||
|
||||
#namespace turret;
|
||||
|
||||
function init()
|
||||
{
|
||||
killstreaks::register( "autoturret", "autoturret", "killstreak_auto_turret", "auto_turret_used", &ActivateTurret );
|
||||
killstreaks::register_alt_weapon( "autoturret", "auto_gun_turret" );
|
||||
killstreaks::register_remote_override_weapon( "autoturret", "killstreak_remote_turret" );
|
||||
killstreaks::register_strings( "autoturret", &"KILLSTREAK_EARNED_AUTO_TURRET", &"KILLSTREAK_AUTO_TURRET_NOT_AVAILABLE", &"KILLSTREAK_AUTO_TURRET_INBOUND", undefined, &"KILLSTREAK_AUTO_TURRET_HACKED", false );
|
||||
killstreaks::register_dialog( "autoturret", "mpl_killstreak_auto_turret", "turretDialogBundle", undefined, "friendlyTurret", "enemyTurret", "enemyTurretMultiple", "friendlyTurretHacked", "enemyTurretHacked", "requestTurret", "threatTurret" );
|
||||
|
||||
// TODO: Move to killstreak data
|
||||
level.killstreaks["autoturret"].threatOnKill = true;
|
||||
|
||||
clientfield::register( "vehicle", "auto_turret_open", 1, 1, "int" );
|
||||
clientfield::register( "scriptmover", "auto_turret_init", 1, 1, "int" ); // re-export model in close position to save this clientfield
|
||||
clientfield::register( "scriptmover", "auto_turret_close", 1, 1, "int" );
|
||||
|
||||
level.autoturretOpenAnim = %o_turret_sentry_deploy;
|
||||
level.autoturretCloseAnim = %o_turret_sentry_close;
|
||||
|
||||
remote_weapons::RegisterRemoteWeapon( "autoturret", &"MP_REMOTE_USE_TURRET", &StartTurretRemoteControl, &EndTurretRemoteControl, true );
|
||||
vehicle::add_main_callback( "sentry_turret", &InitTurret );
|
||||
|
||||
visionset_mgr::register_info( "visionset", "turret_visionset", 1, 81, 16, true, &visionset_mgr::ramp_in_out_thread_per_player, false );
|
||||
}
|
||||
|
||||
function InitTurret()
|
||||
{
|
||||
turretVehicle = self;
|
||||
//turretVehicle.delete_on_death = undefined; // don't delete on death as we may need to support futz on death
|
||||
turretVehicle.dontfreeme = true; // don't allow the shared shutdown sequence until we are ready
|
||||
turretVehicle.damage_on_death = false; // never cause damage when auto turret dies
|
||||
turretVehicle.delete_on_death = undefined; // disallow the vehicle death's delete
|
||||
turretVehicle.watch_remote_weapon_death = true;
|
||||
turretVehicle.watch_remote_weapon_death_duration = 1.2;
|
||||
|
||||
turretVehicle.maxhealth = ( 2000 );
|
||||
turretVehicle.damageTaken = 0;
|
||||
|
||||
tableHealth = killstreak_bundles::get_max_health( "autoturret" );
|
||||
|
||||
if ( isdefined( tableHealth ) )
|
||||
{
|
||||
turretVehicle.maxhealth = tableHealth;
|
||||
|
||||
}
|
||||
|
||||
turretVehicle.health = turretVehicle.maxhealth;
|
||||
|
||||
turretVehicle turret::set_max_target_distance( ( 2500 ), 0 );
|
||||
// setting min dist squared prevents an exploit of drawing fire and not getting hurt when there is no collision on the turret
|
||||
turretVehicle turret::set_min_target_distance_squared( DistanceSquared( turretVehicle GetTagOrigin( "tag_flash" ), turretVehicle GetTagOrigin( "tag_barrel" ) ), 0 );
|
||||
turretVehicle turret::set_on_target_angle( ( 15 ), 0 );
|
||||
turretVehicle clientfield::set( "enemyvehicle", 1 );
|
||||
turretVehicle.soundmod = "drone_land";
|
||||
//turretVehicle NotSolid();
|
||||
|
||||
turretVehicle.overrideVehicleDamage = &OnTurretDamage;
|
||||
turretVehicle.overrideVehicleDeath = &OnTurretDeath;
|
||||
}
|
||||
|
||||
function ActivateTurret()
|
||||
{
|
||||
player = self;
|
||||
assert( IsPlayer( player ) );
|
||||
|
||||
killstreakId = self killstreakrules::killstreakStart( "autoturret", player.team, false, false );
|
||||
if( killstreakId == (-1) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bundle = level.killstreakBundle["autoturret"];
|
||||
|
||||
turret = player placeables::SpawnPlaceable( "autoturret", killstreakId,
|
||||
&OnPlaceTurret, &OnCancelPlacement, &OnPickupTurret, &OnShutdown, undefined, undefined,
|
||||
"veh_t7_turret_sentry_gun_world_mp", "veh_t7_turret_sentry_gun_world_yellow", "veh_t7_turret_sentry_gun_world_red", true,
|
||||
&"KILLSTREAK_SENTRY_TURRET_PICKUP", ( 90 * 1000 ), undefined, 0, bundle.ksPlaceableHint, bundle.ksPlaceableInvalidLocationHint );
|
||||
|
||||
turret thread WatchTurretShutdown( killstreakId, player.team );
|
||||
turret thread util::ghost_wait_show_to_player( player );
|
||||
turret.otherModel thread util::ghost_wait_show_to_others( player );
|
||||
turret clientfield::set( "auto_turret_init", 1 );
|
||||
turret.otherModel clientfield::set( "auto_turret_init", 1 );
|
||||
|
||||
event = turret util::waittill_any_return( "placed", "cancelled", "death" );
|
||||
if( event != "placed" )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
turret playsound ("mpl_turret_startup");
|
||||
return true;
|
||||
}
|
||||
|
||||
function OnPlaceTurret( turret )
|
||||
{
|
||||
player = self;
|
||||
assert( IsPlayer( player ) );
|
||||
|
||||
if( isdefined( turret.vehicle ) )
|
||||
{
|
||||
turret.vehicle.origin = turret.origin;
|
||||
turret.vehicle.angles = turret.angles;
|
||||
|
||||
turret.vehicle thread util::ghost_wait_show( 0.05 );
|
||||
|
||||
turret.vehicle playsound ("mpl_turret_startup");
|
||||
}
|
||||
else
|
||||
{
|
||||
turret.vehicle = SpawnVehicle( "sentry_turret", turret.origin, turret.angles, "dynamic_spawn_ai" );
|
||||
turret.vehicle.owner = player;
|
||||
turret.vehicle SetOwner( player );
|
||||
turret.vehicle.ownerEntNum = player.entNum;
|
||||
turret.vehicle.parentStruct = turret;
|
||||
turret.vehicle.controlled = false;
|
||||
turret.vehicle.treat_owner_damage_as_friendly_fire = true;
|
||||
turret.vehicle.ignore_team_kills = true;
|
||||
turret.vehicle.deal_no_crush_damage = true;
|
||||
|
||||
turret.vehicle.team = player.team;
|
||||
turret.vehicle SetTeam( player.team );
|
||||
turret.vehicle turret::set_team( player.team, 0 );
|
||||
turret.vehicle turret::set_torso_targetting( 0 );
|
||||
turret.vehicle turret::set_target_leading( 0 );
|
||||
turret.vehicle.use_non_teambased_enemy_selection = true;
|
||||
turret.vehicle.waittill_turret_on_target_delay = 0.25;
|
||||
//turret.vehicle turret::set_see_from_tag_flash( true, 0 );
|
||||
//turret.vehicle turret::
|
||||
turret.vehicle.ignore_vehicle_underneath_splash_scalar = true;
|
||||
|
||||
turret.vehicle killstreaks::configure_team( "autoturret", turret.killstreakId, player, "small_vehicle" );
|
||||
turret.vehicle killstreak_hacking::enable_hacking( "autoturret", &HackedCallbackPre, &HackedCallbackPost );
|
||||
|
||||
turret.vehicle thread turret_watch_owner_events();
|
||||
turret.vehicle thread turret_laser_watch();
|
||||
turret.vehicle thread setup_death_watch_for_new_targets();
|
||||
|
||||
turret.vehicle CreateTurretInfluencer( "turret" );
|
||||
turret.vehicle CreateTurretInfluencer( "turret_close" );
|
||||
|
||||
turret.vehicle thread util::ghost_wait_show( 0.05 );
|
||||
|
||||
if ( IsSentient( turret.vehicle ) == false )
|
||||
turret.vehicle MakeSentient(); // so other sentients will consider this as a potential enemy
|
||||
|
||||
player killstreaks::play_killstreak_start_dialog( "autoturret", player.pers["team"], turret.killstreakId );
|
||||
level thread popups::DisplayKillstreakTeamMessageToAll( "autoturret", player );
|
||||
player AddWeaponStat( GetWeapon( "autoturret" ), "used", 1 );
|
||||
|
||||
turret.vehicle.killstreak_end_time = GetTime() + ( 90 * 1000 ) + 5000;
|
||||
}
|
||||
|
||||
turret.vehicle turret::enable( 0, false );
|
||||
Target_Set( turret.vehicle, ( 0, 0, 36 ) );
|
||||
turret.vehicle Unlink();
|
||||
|
||||
turret.vehicle vehicle::disconnect_paths( 0, false );
|
||||
|
||||
turret.vehicle thread TurretScanning();
|
||||
|
||||
turret play_deploy_anim();
|
||||
|
||||
player remote_weapons::UseRemoteWeapon( turret.vehicle, "autoturret", false );
|
||||
}
|
||||
|
||||
function HackedCallbackPre( hacker )
|
||||
{
|
||||
turretVehicle = self;
|
||||
turretVehicle clientfield::set( "enemyvehicle", 2 );
|
||||
turretVehicle.owner clientfield::set_to_player( "static_postfx", 0 );
|
||||
if( turretVehicle.controlled === true )
|
||||
visionset_mgr::deactivate( "visionset", "turret_visionset", turretVehicle.owner );
|
||||
turretVehicle.owner remote_weapons::RemoveAndAssignNewRemoteControlTrigger( turretVehicle.useTrigger );
|
||||
turretVehicle remote_weapons::EndRemoteControlWeaponUse( true );
|
||||
turretVehicle.owner unlink();
|
||||
turretVehicle clientfield::set( "vehicletransition", 0 );
|
||||
}
|
||||
|
||||
function HackedCallbackPost( hacker )
|
||||
{
|
||||
turretVehicle = self;
|
||||
hacker remote_weapons::UseRemoteWeapon( turretVehicle, "autoturret", false );
|
||||
turretVehicle notify( "WatchRemoteControlDeactivate_remoteWeapons" );
|
||||
turretVehicle.killstreak_end_time = hacker killstreak_hacking::set_vehicle_drivable_time_starting_now( turretVehicle );
|
||||
}
|
||||
|
||||
function play_deploy_anim_after_wait( wait_time )
|
||||
{
|
||||
turret = self;
|
||||
turret endon( "death" );
|
||||
|
||||
wait wait_time;
|
||||
|
||||
turret play_deploy_anim();
|
||||
}
|
||||
|
||||
function play_deploy_anim()
|
||||
{
|
||||
turret = self;
|
||||
|
||||
turret clientfield::set( "auto_turret_close", 0 );
|
||||
turret.otherModel clientfield::set( "auto_turret_close", 0 );
|
||||
|
||||
if ( isdefined( turret.vehicle ))
|
||||
{
|
||||
turret.vehicle clientfield::set( "auto_turret_open", 1 );
|
||||
}
|
||||
}
|
||||
|
||||
function OnCancelPlacement( turret )
|
||||
{
|
||||
turret notify( "sentry_turret_shutdown" );
|
||||
}
|
||||
|
||||
function OnPickupTurret( turret )
|
||||
{
|
||||
player = self;
|
||||
turret.vehicle Ghost();
|
||||
turret.vehicle turret::disable( 0 );
|
||||
turret.vehicle LinkTo( turret );
|
||||
Target_Remove( turret.vehicle );
|
||||
|
||||
turret clientfield::set( "auto_turret_close", 1 );
|
||||
turret.otherModel clientfield::set( "auto_turret_close", 1 );
|
||||
|
||||
if ( isdefined( turret.vehicle ) )
|
||||
{
|
||||
turret.vehicle notify( "end_turret_scanning" );
|
||||
turret.vehicle SetTurretTargetRelativeAngles( ( 0, 0, 0 ) );
|
||||
|
||||
turret.vehicle clientfield::set( "auto_turret_open", 0 );
|
||||
|
||||
if( isdefined( turret.vehicle.useTrigger ) )
|
||||
{
|
||||
turret.vehicle.useTrigger Delete();
|
||||
turret.vehicle playsound ("mpl_turret_down");
|
||||
}
|
||||
|
||||
turret.vehicle vehicle::connect_paths();
|
||||
}
|
||||
}
|
||||
|
||||
function OnTurretDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
|
||||
{
|
||||
empDamage = int( iDamage + ( self.healthdefault * ( 1 ) ) + 0.5 );
|
||||
|
||||
iDamage = self killstreaks::OnDamagePerWeapon( "autoturret", eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, self.maxhealth, undefined, self.maxhealth*0.4, undefined, empDamage, undefined, true, 1.0 );
|
||||
self.damageTaken += iDamage;
|
||||
|
||||
if ( self.controlled )
|
||||
{
|
||||
self.owner vehicle::update_damage_as_occupant( self.damageTaken, self.maxHealth );
|
||||
}
|
||||
|
||||
// turret death
|
||||
if ( self.damageTaken > self.maxHealth && !isdefined( self.will_die ) )
|
||||
{
|
||||
self.will_die = true;
|
||||
self thread OnDeathAfterFrameEnd( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime );
|
||||
}
|
||||
|
||||
return iDamage;
|
||||
}
|
||||
|
||||
function OnTurretDeath( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime )
|
||||
{
|
||||
// currently, OnTurretDeath is not getting called, so we call OnDeath directly from OnTurretDamage
|
||||
self OnDeath( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime );
|
||||
}
|
||||
|
||||
function OnDeathAfterFrameEnd( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime )
|
||||
{
|
||||
waittillframeend;
|
||||
|
||||
if ( isdefined( self ) )
|
||||
{
|
||||
self OnDeath( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime );
|
||||
}
|
||||
}
|
||||
|
||||
function OnDeath( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime )
|
||||
{
|
||||
turretVehicle = self;
|
||||
|
||||
// only die once
|
||||
if ( turretVehicle.dead === true )
|
||||
return;
|
||||
|
||||
turretVehicle.dead = true;
|
||||
|
||||
turretVehicle DisableDriverFiring( true );
|
||||
turretvehicle turret::disable( 0 );
|
||||
|
||||
turretvehicle vehicle::connect_paths();
|
||||
|
||||
eAttacker = self [[ level.figure_out_attacker ]]( eAttacker );
|
||||
|
||||
if( isdefined( turretVehicle.parentStruct ) )
|
||||
{
|
||||
turretVehicle.parentStruct placeables::ForceShutdown();
|
||||
|
||||
if ( turretVehicle.parentStruct.killstreakTimedOut === true && isdefined( turretVehicle.owner ) )
|
||||
{
|
||||
turretVehicle.owner globallogic_audio::play_taacom_dialog( "timeout", turretVehicle.parentStruct.killstreakType );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( isdefined( eAttacker ) && isdefined( turretVehicle.owner ) && ( eAttacker != turretVehicle.owner ) )
|
||||
turretVehicle.parentStruct killstreaks::play_destroyed_dialog_on_owner( turretVehicle.parentStruct.killstreakType, turretVehicle.parentStruct.killstreakId );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isdefined( eAttacker ) && IsPlayer( eAttacker ) && ( !isdefined( self.owner ) || self.owner util::IsEnemyPlayer( eAttacker ) ) )
|
||||
{
|
||||
scoreevents::processScoreEvent( "destroyed_sentry_gun", eAttacker, self, weapon );
|
||||
eAttacker challenges::destroyScoreStreak( weapon, turretVehicle.controlled, true, false );
|
||||
eAttacker challenges::destroyNonAirScoreStreak_PostStatsLock( weapon );
|
||||
eAttacker AddPlayerStat( "destroy_turret", 1 );
|
||||
eAttacker AddWeaponStat( weapon, "destroy_turret", 1 );
|
||||
LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_AUTO_TURRET", eAttacker.entnum );
|
||||
}
|
||||
|
||||
turretVehicle vehicle_death::death_fx();
|
||||
turretVehicle playsound ("mpl_m_turret_exp");
|
||||
|
||||
// anticipating futz
|
||||
|
||||
wait 0.1;
|
||||
|
||||
turretVehicle Ghost();
|
||||
turretVehicle NotSolid();
|
||||
|
||||
turretVehicle util::waittill_any_timeout( 2.0, "remote_weapon_end" );
|
||||
|
||||
if ( isdefined( turretVehicle ) )
|
||||
{
|
||||
// wait until control is released, vehicle gets deleted, or owner disconnects
|
||||
while ( isdefined( turretVehicle ) && ( turretVehicle.controlled || !isdefined( turretVehicle.owner ) ) )
|
||||
{wait(.05);};
|
||||
|
||||
turretVehicle.dontfreeme = undefined; // allows vehicle shared shutdown to finish
|
||||
|
||||
// we decided to be responsible for deleting the vehicle, so we delete here
|
||||
wait 0.5;
|
||||
if ( isdefined ( turretVehicle ) )
|
||||
turretVehicle delete();
|
||||
}
|
||||
}
|
||||
|
||||
function OnShutdown( turret )
|
||||
{
|
||||
turret notify( "sentry_turret_shutdown" );
|
||||
}
|
||||
|
||||
function StartTurretRemoteControl( turretVehicle )
|
||||
{
|
||||
player = self;
|
||||
assert( IsPlayer( player ) );
|
||||
|
||||
turretVehicle turret::disable( 0 );
|
||||
turretVehicle UseVehicle( player, 0 );
|
||||
turretVehicle clientfield::set( "vehicletransition", 1 );
|
||||
turretVehicle.controlled = true;
|
||||
turretVehicle.treat_owner_damage_as_friendly_fire = false;
|
||||
turretVehicle.ignore_team_kills = false;
|
||||
|
||||
player vehicle::set_vehicle_drivable_time( ( 90 * 1000 ) + 5000, turretVehicle.killstreak_end_time );
|
||||
player vehicle::update_damage_as_occupant( (isdefined(turretVehicle.damageTaken)?turretVehicle.damageTaken:0), (isdefined(turretVehicle.maxHealth)?turretVehicle.maxHealth:100) );
|
||||
|
||||
visionset_mgr::activate( "visionset", "turret_visionset", self, 1, 90000, 1 );
|
||||
}
|
||||
|
||||
function EndTurretRemoteControl( turretVehicle, exitRequestedByOwner )
|
||||
{
|
||||
if( exitRequestedByOwner )
|
||||
{
|
||||
turretVehicle thread EnableTurretAfterWait( 0.1 ); // currently, this must be called after the player leaves the vehicle
|
||||
}
|
||||
turretVehicle clientfield::set( "vehicletransition", 0 );
|
||||
|
||||
if ( isdefined( turretVehicle.owner ) && ( turretVehicle.controlled === true ) )
|
||||
visionset_mgr::deactivate( "visionset", "turret_visionset", turretVehicle.owner );
|
||||
|
||||
turretVehicle.controlled = false;
|
||||
turretVehicle.treat_owner_damage_as_friendly_fire = true;
|
||||
turretVehicle.ignore_team_kills = true;
|
||||
}
|
||||
|
||||
function EnableTurretAfterWait( wait_time ) // self == turretVehicle
|
||||
{
|
||||
self endon ( "death" );
|
||||
if ( isdefined( self.owner ) )
|
||||
{
|
||||
self.owner endon( "joined_team" );
|
||||
self.owner endon( "disconnect" );
|
||||
self.owner endon( "joined_spectators" );
|
||||
}
|
||||
|
||||
wait wait_time;
|
||||
self turret::enable( 0, false );
|
||||
}
|
||||
|
||||
function CreateTurretInfluencer( name )
|
||||
{
|
||||
turret = self;
|
||||
|
||||
preset = GetInfluencerPreset( name );
|
||||
|
||||
if ( !IsDefined( preset ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// place the influencer out infront of the turret
|
||||
projected_point = turret.origin + VectorScale( AnglesToForward( turret.angles ), preset["radius"] * 0.7 );
|
||||
return spawning::create_enemy_influencer( name, turret.origin, turret.team );
|
||||
}
|
||||
|
||||
function turret_watch_owner_events()
|
||||
{
|
||||
self notify( "turret_watch_owner_events_singleton" );
|
||||
self endon ( "tturet_watch_owner_events_singleton" );
|
||||
self endon( "death" );
|
||||
|
||||
self.owner util::waittill_any( "joined_team", "disconnect", "joined_spectators" );
|
||||
|
||||
self MakeVehicleUsable();
|
||||
self.controlled = false;
|
||||
|
||||
if ( isdefined( self.owner ) )
|
||||
{
|
||||
self.owner unlink();
|
||||
self clientfield::set( "vehicletransition", 0 );
|
||||
}
|
||||
|
||||
self MakeVehicleUnusable();
|
||||
|
||||
if ( isdefined( self.owner ) )
|
||||
{
|
||||
self.owner killstreaks::clear_using_remote();
|
||||
}
|
||||
|
||||
self.abandoned = true;
|
||||
|
||||
OnShutdown( self );
|
||||
}
|
||||
|
||||
function turret_laser_watch()
|
||||
{
|
||||
turretVehicle = self;
|
||||
turretVehicle endon( "death" );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
laser_should_be_on = ( !turretVehicle.controlled && turretVehicle turret::does_have_target( 0 ) );
|
||||
|
||||
if ( laser_should_be_on )
|
||||
{
|
||||
if ( IsLaserOn( turretVehicle ) == false )
|
||||
{
|
||||
turretVehicle turret::enable_laser( true, 0 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( IsLaserOn( turretVehicle ) )
|
||||
{
|
||||
turretVehicle turret::enable_laser( false, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
wait 0.25;
|
||||
}
|
||||
}
|
||||
|
||||
function setup_death_watch_for_new_targets()
|
||||
{
|
||||
turretVehicle = self;
|
||||
|
||||
turretVehicle endon( "death" );
|
||||
old_target = undefined;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
turretVehicle waittill( "has_new_target", new_target );
|
||||
|
||||
if ( isdefined( old_target ) )
|
||||
old_target notify( "abort_death_watch" );
|
||||
|
||||
new_target thread target_death_watch( turretVehicle );
|
||||
old_target = new_target;
|
||||
}
|
||||
}
|
||||
|
||||
function target_death_watch( turretVehicle )
|
||||
{
|
||||
target = self;
|
||||
target endon( "abort_death_watch" );
|
||||
|
||||
turretVehicle endon( "death" );
|
||||
|
||||
target util::waittill_any( "death", "disconnect", "joined_team", "joined_spectators" );
|
||||
|
||||
turretVehicle turret::stop( 0, true );
|
||||
}
|
||||
|
||||
function TurretScanning()
|
||||
{
|
||||
turretVehicle = self;
|
||||
|
||||
turretVehicle endon( "death" );
|
||||
turretVehicle endon( "end_turret_scanning" );
|
||||
|
||||
turret_data = turretVehicle _get_turret_data( 0 );
|
||||
|
||||
turretVehicle.do_not_clear_targets_during_think = true; // don't let shared turret code clear targets; TurretScanning will clear targets
|
||||
// note: turret:clear_target() indirectly affects targetType which affects how SetTurretTargetRelativeAngles behaves.
|
||||
|
||||
wait 0.8;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
if ( turretVehicle.controlled )
|
||||
{
|
||||
wait 0.5;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( turretVehicle turret::does_have_target( 0 ) )
|
||||
{
|
||||
wait 0.25;
|
||||
continue;
|
||||
}
|
||||
|
||||
/# turret_data = turretVehicle _get_turret_data( 0 ); #/ // for live update
|
||||
|
||||
turretVehicle turret::clear_target( 0 );
|
||||
|
||||
if ( turretVehicle.scanPos === "left" )
|
||||
{
|
||||
turretVehicle SetTurretTargetRelativeAngles( ( 0, ( turret_data.leftArc - 10 ), 0 ), 0 );
|
||||
turretVehicle.scanPos = "right";
|
||||
}
|
||||
else
|
||||
{
|
||||
turretVehicle SetTurretTargetRelativeAngles( ( 0, -( turret_data.rightArc - 10 ), 0 ), 0 );
|
||||
turretVehicle.scanPos = "left";
|
||||
}
|
||||
|
||||
wait 2.5;
|
||||
}
|
||||
}
|
||||
|
||||
function WatchTurretShutdown( killstreakId, team )
|
||||
{
|
||||
turret = self;
|
||||
|
||||
turret waittill( "sentry_turret_shutdown" );
|
||||
|
||||
killstreakrules::killstreakStop( "autoturret", team, killstreakId );
|
||||
|
||||
if( isdefined( turret.vehicle ) )
|
||||
{
|
||||
turret.vehicle spawning::remove_influencers();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,430 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\challenges_shared;
|
||||
#using scripts\shared\clientfield_shared;
|
||||
#using scripts\shared\damagefeedback_shared;
|
||||
#using scripts\shared\killstreaks_shared;
|
||||
#using scripts\shared\math_shared;
|
||||
#using scripts\shared\scoreevents_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\tweakables_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
#using scripts\shared\weapons\_heatseekingmissile;
|
||||
#using scripts\shared\weapons\_weaponobjects;
|
||||
|
||||
#using scripts\mp\gametypes\_globallogic_audio;
|
||||
#using scripts\mp\killstreaks\_airsupport;
|
||||
#using scripts\mp\killstreaks\_killstreak_bundles;
|
||||
#using scripts\mp\killstreaks\_killstreak_detect;
|
||||
#using scripts\mp\killstreaks\_killstreak_hacking;
|
||||
#using scripts\mp\killstreaks\_killstreakrules;
|
||||
#using scripts\mp\killstreaks\_killstreaks;
|
||||
#using scripts\mp\teams\_teams;
|
||||
#using scripts\mp\_util;
|
||||
|
||||
|
||||
|
||||
Line truncated
|
||||
|
||||
|
||||
#precache( "eventstring", "mpl_killstreak_radar" );
|
||||
#precache( "string", "KILLSTREAK_EARNED_RADAR" );
|
||||
#precache( "string", "KILLSTREAK_RADAR_INBOUND" );
|
||||
#precache( "string", "KILLSTREAK_RADAR_NOT_AVAILABLE" );
|
||||
#precache( "string", "KILLSTREAK_DESTROYED_UAV" );
|
||||
#precache( "string", "KILLSTREAK_RADAR_HACKED" );
|
||||
|
||||
#precache( "fx", "killstreaks/fx_uav_damage_trail" );
|
||||
#precache( "fx", "killstreaks/fx_uav_lights" );
|
||||
#precache( "fx", "killstreaks/fx_uav_bunner" );
|
||||
|
||||
|
||||
|
||||
#namespace uav;
|
||||
|
||||
function init()
|
||||
{
|
||||
if ( level.teamBased )
|
||||
{
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
level.activeUAVs[ team ] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
level.activeUAVs = [];
|
||||
}
|
||||
|
||||
level.activePlayerUAVs = [];
|
||||
level.spawnedUAVs = [];
|
||||
|
||||
if ( tweakables::getTweakableValue( "killstreak", "allowradar" ) )
|
||||
{
|
||||
killstreaks::register( "uav", "uav", "killstreak_uav", "uav_used", &ActivateUAV );
|
||||
killstreaks::register_strings( "uav", &"KILLSTREAK_EARNED_RADAR", &"KILLSTREAK_RADAR_NOT_AVAILABLE", &"KILLSTREAK_RADAR_INBOUND", undefined, &"KILLSTREAK_RADAR_HACKED" );
|
||||
killstreaks::register_dialog( "uav", "mpl_killstreak_radar", "uavDialogBundle", "uavPilotDialogBundle", "friendlyUav", "enemyUav", "enemyUavMultiple", "friendlyUavHacked", "enemyUavHacked", "requestUav", "threatUav" );
|
||||
}
|
||||
|
||||
level thread UAVTracker();
|
||||
|
||||
callback::on_connect( &OnPlayerConnect );
|
||||
callback::on_spawned( &OnPlayerSpawned );
|
||||
callback::on_joined_team( &OnPlayerJoinedTeam );
|
||||
|
||||
setMatchFlag( "radar_allies", 0 );
|
||||
setMatchFlag( "radar_axis", 0 );
|
||||
}
|
||||
|
||||
function HackedPreFunction( hacker )
|
||||
{
|
||||
uav = self;
|
||||
uav ResetActiveUAV();
|
||||
}
|
||||
|
||||
function ConfigureTeamPost( owner, isHacked )
|
||||
{
|
||||
uav = self;
|
||||
uav thread teams::WaitUntilTeamChangeSingleTon( owner, "UAV_watch_team_change", &OnTeamChange, owner.entNum, "delete", "death", "leaving" );
|
||||
if ( isHacked == false )
|
||||
{
|
||||
uav teams::HideToSameTeam();
|
||||
}
|
||||
else
|
||||
{
|
||||
uav SetVisibleToAll();
|
||||
}
|
||||
owner AddActiveUAV();
|
||||
}
|
||||
|
||||
function ActivateUAV()
|
||||
{
|
||||
assert( isdefined( level.players ) );
|
||||
|
||||
if ( self killstreakrules::isKillstreakAllowed( "uav", self.team ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
killstreak_id = self killstreakrules::killstreakStart( "uav", self.team );
|
||||
if ( killstreak_id == -1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rotator = level.airsupport_rotator;
|
||||
attach_angle = -90;
|
||||
|
||||
uav = spawn( "script_model", rotator getTagOrigin( "tag_origin" ) );
|
||||
if ( !isdefined( level.spawnedUAVs ) ) level.spawnedUAVs = []; else if ( !IsArray( level.spawnedUAVs ) ) level.spawnedUAVs = array( level.spawnedUAVs ); level.spawnedUAVs[level.spawnedUAVs.size]=uav;;
|
||||
|
||||
uav setModel( "veh_t7_drone_uav_enemy_vista" );
|
||||
|
||||
uav.targetname = "uav";
|
||||
|
||||
uav killstreaks::configure_team( "uav", killstreak_id, self, undefined, undefined, &ConfigureTeamPost );
|
||||
uav killstreak_hacking::enable_hacking( "uav", &HackedPreFunction, undefined );
|
||||
|
||||
uav clientfield::set( "enemyvehicle", 1 );
|
||||
killstreak_detect::killstreakTargetSet( uav );
|
||||
|
||||
uav SetDrawInfrared( true );
|
||||
|
||||
uav.killstreak_id = killstreak_id;
|
||||
uav.leaving = false;
|
||||
uav.health = 99999;
|
||||
|
||||
uav.maxhealth = ( 700 );
|
||||
uav.lowhealth = ( ( 700 ) * 0.5 );
|
||||
|
||||
uav SetCanDamage( true );
|
||||
uav thread killstreaks::MonitorDamage( "uav", uav.maxhealth, &DestroyUAV, uav.lowhealth, &OnLowHealth, 0, undefined, true );
|
||||
|
||||
uav thread heatseekingmissile::MissileTarget_ProximityDetonateIncomingMissile( "crashing", undefined, true );
|
||||
uav.rocketDamage = uav.maxhealth + 1;
|
||||
|
||||
minFlyHeight = int( airsupport::getMinimumFlyHeight() );
|
||||
zOffset = minFlyHeight + (isdefined(level.uav_z_offset)?level.uav_z_offset:( 2500 ));
|
||||
|
||||
angle = randomInt( 360 );
|
||||
radiusOffset = (isdefined(level.uav_rotation_radius)?level.uav_rotation_radius:( 4000 )) + randomInt( (isdefined(level.uav_rotation_random_offset)?level.uav_rotation_random_offset:( 1000 )) );
|
||||
xOffset = cos( angle ) * radiusOffset;
|
||||
yOffset = sin( angle ) * radiusOffset;
|
||||
angleVector = vectorNormalize( ( xOffset, yOffset, zOffset ) );
|
||||
angleVector = angleVector * zOffset;
|
||||
uav linkTo( rotator, "tag_origin", angleVector, ( 0, angle + attach_angle, 0 ) );
|
||||
|
||||
self AddWeaponStat( GetWeapon( "uav" ), "used", 1 );
|
||||
|
||||
uav thread killstreaks::WaitForTimeout( "uav", ( 25000 ), &OnTimeout, "delete", "death", "crashing" );
|
||||
uav thread killstreaks::WaitForTimecheck( ( ( 25000 ) / 2 ), &OnTimecheck, "delete", "death", "crashing" );
|
||||
|
||||
uav thread StartUAVFx();
|
||||
|
||||
self killstreaks::play_killstreak_start_dialog( "uav", self.team, killstreak_id );
|
||||
|
||||
uav killstreaks::play_pilot_dialog_on_owner( "arrive", "uav", killstreak_id );
|
||||
uav thread killstreaks::player_killstreak_threat_tracking( "uav" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function OnLowHealth( attacker, weapon )
|
||||
{
|
||||
self.is_damaged = true;
|
||||
params = level.killstreakBundle["uav"];
|
||||
if( isdefined( params.fxLowHealth ) )
|
||||
PlayFXOnTag( params.fxLowHealth, self, "tag_origin" );
|
||||
}
|
||||
|
||||
function OnTeamChange( entNum, event )
|
||||
{
|
||||
DestroyUAV( undefined, undefined );
|
||||
}
|
||||
|
||||
function DestroyUAV( attacker, weapon )
|
||||
{
|
||||
attacker = self [[ level.figure_out_attacker ]]( attacker );
|
||||
if( isdefined( attacker ) && ( !isdefined( self.owner ) || self.owner util::IsEnemyPlayer( attacker ) ) )
|
||||
{
|
||||
challenges::destroyedAircraft( attacker, weapon, false );
|
||||
scoreevents::processScoreEvent( "destroyed_uav", attacker, self.owner, weapon );
|
||||
LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_UAV", attacker.entnum );
|
||||
attacker challenges::addFlySwatterStat( weapon, self );
|
||||
}
|
||||
|
||||
if( !self.leaving )
|
||||
{
|
||||
self RemoveActiveUAV();
|
||||
|
||||
self killstreaks::play_destroyed_dialog_on_owner( "uav", self.killstreak_id );
|
||||
}
|
||||
|
||||
self notify( "crashing" );
|
||||
|
||||
self playsound ( "evt_helicopter_midair_exp" );
|
||||
|
||||
params = level.killstreakBundle["uav"];
|
||||
if( isdefined( params.ksExplosionFX ) )
|
||||
PlayFXOnTag( params.ksExplosionFX, self, "tag_origin" );
|
||||
|
||||
self StopLoopSound();
|
||||
self setModel( "tag_origin" );
|
||||
Target_Remove( self );
|
||||
self unlink();
|
||||
|
||||
wait( 0.5 );
|
||||
|
||||
ArrayRemoveValue( level.spawnedUAVs, self );
|
||||
self notify( "delete" );
|
||||
self delete();
|
||||
}
|
||||
|
||||
function OnPlayerConnect()
|
||||
{
|
||||
self.entNum = self getEntityNumber();
|
||||
|
||||
if ( !level.teambased )
|
||||
{
|
||||
level.activeUAVs[ self.entNum ] = 0;
|
||||
}
|
||||
|
||||
level.activePlayerUAVs[ self.entNum ] = 0; // needed for UAV-related kill scores
|
||||
}
|
||||
|
||||
function OnPlayerSpawned()
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
if( level.teambased == false || level.multiteam == true )
|
||||
{
|
||||
level notify( "uav_update" );
|
||||
}
|
||||
}
|
||||
|
||||
function OnPlayerJoinedTeam()
|
||||
{
|
||||
HideAllUAVsToSameTeam();
|
||||
}
|
||||
|
||||
function OnTimeout()
|
||||
{
|
||||
PlayAfterburnerFx();
|
||||
|
||||
if( ( isdefined( self.is_damaged ) && self.is_damaged ) )
|
||||
{
|
||||
PlayFxOnTag( "killstreaks/fx_uav_damage_trail", self, "tag_body" );
|
||||
}
|
||||
|
||||
self killstreaks::play_pilot_dialog_on_owner( "timeout", "uav" );
|
||||
|
||||
self.leaving = true;
|
||||
self RemoveActiveUAV();
|
||||
|
||||
airsupport::Leave( ( 10 ) );
|
||||
wait( ( 10 ) );
|
||||
|
||||
Target_Remove( self );
|
||||
ArrayRemoveValue( level.spawnedUAVs, self );
|
||||
self delete();
|
||||
}
|
||||
|
||||
function OnTimecheck()
|
||||
{
|
||||
self killstreaks::play_pilot_dialog_on_owner( "timecheck", "uav", self.killstreak_id );
|
||||
}
|
||||
|
||||
function StartUAVFx()
|
||||
{
|
||||
self endon( "death" );
|
||||
wait ( 0.1 );
|
||||
|
||||
if( isdefined( self ) )
|
||||
{
|
||||
PlayFXOnTag( "killstreaks/fx_uav_lights", self, "tag_origin" );
|
||||
PlayFXOnTag( "killstreaks/fx_uav_bunner", self, "tag_origin" );
|
||||
self PlayLoopSound ("veh_uav_engine_loop", 1);
|
||||
}
|
||||
}
|
||||
|
||||
function PlayAfterburnerFx()
|
||||
{
|
||||
self endon( "death" );
|
||||
wait ( 0.1 );
|
||||
|
||||
if( isdefined( self ) )
|
||||
{
|
||||
PlayFXOnTag( "killstreaks/fx_uav_bunner", self, "tag_origin" );
|
||||
self StopLoopSound();
|
||||
team = util::getOtherTeam( self.team );
|
||||
self playsoundtoteam ( "veh_kls_uav_afterburner" , team );
|
||||
}
|
||||
}
|
||||
|
||||
function HasUAV( team_or_entnum )
|
||||
{
|
||||
return level.activeUAVs[ team_or_entnum ] > 0;
|
||||
}
|
||||
|
||||
function AddActiveUAV()
|
||||
{
|
||||
if ( level.teamBased )
|
||||
{
|
||||
assert( isdefined( self.team ) );
|
||||
level.activeUAVs[self.team]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( isdefined( self.entNum ) );
|
||||
if ( !isdefined( self.entNum ) )
|
||||
{
|
||||
self.entNum = self GetEntityNumber();
|
||||
}
|
||||
|
||||
level.activeUAVs[ self.entNum ]++;
|
||||
}
|
||||
|
||||
level.activePlayerUAVs[ self.entNum ]++;
|
||||
|
||||
level notify ( "uav_update" );
|
||||
}
|
||||
|
||||
function RemoveActiveUAV()
|
||||
{
|
||||
uav = self;
|
||||
uav ResetActiveUAV();
|
||||
uav killstreakrules::killstreakStop( "uav", self.originalteam, self.killstreak_id );
|
||||
}
|
||||
|
||||
function ResetActiveUAV()
|
||||
{
|
||||
if ( level.teamBased )
|
||||
{
|
||||
level.activeUAVs[self.team]--;
|
||||
assert( level.activeUAVs[self.team] >= 0 );
|
||||
|
||||
if( level.activeUAVs[self.team] < 0 )
|
||||
{
|
||||
level.activeUAVs[self.team] = 0;
|
||||
}
|
||||
}
|
||||
else if( isdefined( self.owner ) )
|
||||
{
|
||||
assert( isdefined( self.owner.entNum ) );
|
||||
if( !isdefined( self.owner.entNum ) )
|
||||
{
|
||||
self.owner.entNum = self.owner getEntityNumber();
|
||||
}
|
||||
|
||||
level.activeUAVs[self.owner.entNum]--;
|
||||
|
||||
assert( level.activeUAVs[self.owner.entNum] >= 0 );
|
||||
if( level.activeUAVs[self.owner.entNum] < 0 )
|
||||
{
|
||||
level.activeUAVs[self.owner.entNum] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isdefined( self.owner ) )
|
||||
{
|
||||
level.activePlayerUAVs[self.owner.entNum]--;
|
||||
assert( level.activePlayerUAVs[self.owner.entNum] >= 0 );
|
||||
}
|
||||
level notify ( "uav_update" );
|
||||
}
|
||||
|
||||
function UAVTracker()
|
||||
{
|
||||
level endon ( "game_ended" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
level waittill ( "uav_update" );
|
||||
|
||||
// intentionally keeping both teambased and non-teambased logic for now
|
||||
// TODO: one "might" be able to change it to teambased only; when trying to do so, watch for knock-on effects
|
||||
|
||||
if( level.teamBased )
|
||||
{
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
activeUAVs = level.activeUAVs[ team ];
|
||||
activeUAVsAndSatellites = activeUAVs + ( ( isdefined( level.activeSatellites ) ) ? level.activeSatellites[ team ] : 0 );
|
||||
|
||||
SetTeamSpyplane( team, int( min( activeUAVs, 2 ) ) );
|
||||
util::set_team_radar( team, ( activeUAVsAndSatellites > 0 ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < level.players.size; i++ )
|
||||
{
|
||||
player = level.players[ i ];
|
||||
|
||||
assert( isdefined( player.entNum ) );
|
||||
if( !isdefined( player.entNum ) )
|
||||
{
|
||||
player.entNum = player getEntityNumber();
|
||||
}
|
||||
|
||||
activeUAVs = level.activeUAVs[ player.entNum ];
|
||||
activeUAVsAndSatellites = activeUAVs + ( ( isdefined( level.activeSatellites ) ) ? level.activeSatellites[ player.entnum ] : 0 );
|
||||
|
||||
player SetClientUIVisibilityFlag( "radar_client", ( activeUAVsAndSatellites > 0 ) );
|
||||
player.hasSpyplane = int( min( activeUAVs, 2 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function HideAllUAVsToSameTeam()
|
||||
{
|
||||
foreach( uav in level.spawnedUAVs )
|
||||
{
|
||||
if ( isdefined( uav ) )
|
||||
{
|
||||
|
||||
uav teams::HideToSameTeam();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user