This commit is contained in:
Future committed 2023-04-13 17:30:38 +02:00
commit 013c6f3b4d
921 files changed
+337975

No files matched your search

+197
View File
@@ -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
+230
View File
@@ -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
+954
View File
@@ -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;
}
+26
View File
@@ -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 );
}
+684
View File
@@ -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();
}
}
}
+59
View File
@@ -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);
}
}
}
+827
View File
@@ -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
+342
View File
@@ -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();
}
+162
View File
@@ -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
}
+470
View File
@@ -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" );
}
}
+82
View File
@@ -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);
}
}
+539
View File
@@ -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();
}
}
}
+661
View File
@@ -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
+70
View File
@@ -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
+471
View File
@@ -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;
}
+297
View File
@@ -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" );
}
}
+48
View File
@@ -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();
#/
}
+236
View File
@@ -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;
}
}
}
#/
+552
View File
@@ -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;
}
+488
View File
@@ -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
+348
View File
@@ -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)
+493
View File
@@ -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", &microwave_open, !true, !true );
clientfield::register( "scriptmover", "turret_microwave_init", 1, 1, "int", &microwave_init_anim, !true, !true );
clientfield::register( "scriptmover", "turret_microwave_close", 1, 1, "int", &microwave_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() ); #/
}
+710
View File
@@ -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;
}
+534
View File
@@ -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();
}
}
}
}
+31
View File
@@ -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" );
}
}
+428
View File
@@ -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 );
}
+515
View File
@@ -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
+121
View File
@@ -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
+303
View File
@@ -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
}
+681
View File
@@ -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;
}
+529
View File
@@ -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" );
}
+1
View File
@@ -0,0 +1 @@
+140
View File
@@ -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
+372
View File
@@ -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;
}
+588
View File
@@ -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
+52
View File
@@ -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 );
}
+621
View File
@@ -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();
}
}
+430
View File
@@ -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();
}
}
}