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

984 lines
26 KiB
Plaintext

#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include common_scripts\utility;
#include maps\mp\killstreaks\_orbital_util;
NODE_OFFSET = ( 0, 0, 70 );
FLY_NODE_OFFSET = ( 0, 0, 40 );
DROPPOINT_DISTANCE_SQ = 22500; // 150 * 150
init()
{
level._orbital_care_pod = [];
level.orbitalDropMarkers = [];
level._effect[ "ocp_death" ] = LoadFX( "vfx/explosion/exo_droppod_explosion");
level._effect[ "ocp_midair" ] = LoadFX( "vfx/explosion/exo_droppod_split" );
level._effect[ "ocp_ground_marker" ] = LoadFX( "vfx/unique/vfx_marker_killstreak_guide_carepackage" );
level._effect[ "ocp_ground_marker_bad" ]= LoadFX( "vfx/unique/vfx_marker_killstreak_guide_carepackage_fizzle" );
level._effect[ "ocp_exhaust" ] = LoadFX( "vfx/vehicle/vehicle_ocp_exhaust" );
level._effect[ "ocp_thruster_small" ] = LoadFX( "vfx/vehicle/vehicle_ocp_thrusters_small" );
level._effect[ "vfx_ocp_steam" ] = LoadFX( "vfx/steam/vfx_ocp_steam" );
level._effect[ "vfx_ocp_steam2" ] = LoadFX( "vfx/steam/vfx_ocp_steam2" );
level._effect[ "ocp_glow" ] = LoadFX( "vfx/unique/orbital_carepackage_glow" );
level.killStreakFuncs["orbital_carepackage"] = ::tryUseDefaultOrbitalCarePackage;
level.killstreakWieldWeapons["orbital_carepackage_pod_mp"] = "orbital_carepackage";
level.killstreakFuncs["orbital_carepackage_juggernaut_exosuit"] = ::tryUseOrbitalJuggernautExosuit;
PrecacheMpAnim("orbital_care_package_open");
PrecacheMpAnim("orbital_care_package_fan_spin");
/#
level thread debugDestroyCarepackages();
#/
}
tryUseDefaultOrbitalCarePackage( lifeId, modules )
{
return tryUseOrbitalCarePackage( lifeId, "orbital_carepackage", modules );
}
tryUseOrbitalJuggernautExosuit( lifeId, modules )
{
return tryUseOrbitalCarePackage( lifeId, "orbital_carepackage_juggernaut_exosuit", modules );
}
tryUseOrbitalCarePackage( lifeId, streakName, modules )
{
if ( array_contains( modules, "orbital_carepackage_drone" ) && currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxVehicleCount + 1 >= maxVehiclesAllowed() )
{
//"Too many vehicles already in the area."
self IPrintLnBold( &"MP_TOO_MANY_VEHICLES" );
return false;
}
result = self playerLaunchCarepackage( streakName, modules );
if ( !isDefined( result ) || !result )
return false;
if( streakName == "orbital_carepackage" )
self maps\mp\gametypes\_missions::processChallenge( "ch_streak_orbitalcare", 1 );
return true;
}
playerLaunchCarepackage( streakName, modules )
{
outsideNode = self playerGetOutsideNode( "carepackage" );
outsidePosition = undefined;
if ( IsDefined( outsideNode ) )
{
outsidePosition = outsideNode.origin;
}
else
{
if ( isdefined ( level.isHorde ) && level.isHorde )
{
outsideNode = [[level.hordeGetOutsidePosition]]();
outsidePosition = outsideNode.origin;
}
else
{
self thread playerPlayInvalidPositionEffect( getfx( "ocp_ground_marker_bad" ) );
self SetClientOmnvar( "ui_invalid_orbital_care_package", 1 );
return false;
}
}
drone = undefined;
if ( array_contains( modules, "orbital_carepackage_drone" ) )
{
drone = SpawnHelicopter( self, outsidePosition + ( 0, 0, 200 ), ( 0, 0, 0 ), "orbital_carepackage_drone_mp", "orbital_carepackage_pod_01_vehicle" );
if ( !IsDefined( drone ) )
return false;
drone Hide();
}
result = FirePod( "orbital_carepackage_pod_mp", self, outsideNode, streakName, modules, drone, undefined, undefined, true );
return IsDefined( result );
}
FirePod( weaponType, player, node, streakName, modules, drone, startPos, excludedCrateTypes, giveBackCarepackage )
{
if ( !IsDefined( startPos ) )
startPos = player playerGetOrbitalStartPos( node, "carepackage" );
targetPos = node.origin;
if ( !IsDefined( excludedCrateTypes ) )
excludedCrateTypes = [];
/# debugPlacementLine( startPos, targetPos, ( 0, 1, 0 ) ); #/
podrocket = MagicBullet( weaponType, startPos, targetPos, player );
if ( !IsDefined( podrocket ) )
return;
podrocket thread SetMissileSpecialClipmaskDelayed( 3.0 ); //Only need to check item clip near the ground
podrocket thread trajectory_kill( player );
DropPod = player createPlayerDropPod(podrocket);
DropPod.streakName = streakName;
DropPod.modules = modules;
DropPod.dropPoint = node.origin;
DropPod.drone = drone;
DropPod.giveBackCarepackage = giveBackCarepackage;
podrocket.team = player.team;
podrocket.owner = player;
podrocket.type = "remote";
return monitorDrop( player, podrocket, DropPod, streakName, excludedCrateTypes, weaponType );
}
trajectory_kill( player )
{
self endon("death");
lastOrigin = self.origin;
while( IsDefined( self ) )
{
if ( !level.teamBased )
capsule_damage( 10000, self.origin, lastOrigin, 30, undefined, player );
else
capsule_damage( 10000, self.origin, lastOrigin, 30, level.otherTeam[ player.team ], player );
lastOrigin = self.origin;
wait 0.05;
}
}
capsule_damage( damage, origin1, origin2, radius, killTeam, attacker )
{
assert( radius > 0 );
delta = origin2 - origin1;
deltaNml = VectorNormalize( delta );
dist = Length( delta );
radiusSq = radius * radius;
foreach ( enemy in level.characters )
{
if ( !IsAlive( enemy ) )
continue;
if ( enemy != attacker && IsDefined( killTeam ) && IsDefined( enemy.team ) && enemy.team != killTeam )
continue;
deltaEnemy = enemy.origin - origin1;
dot = VectorDot( deltaEnemy, deltaNml );
if ( dot > (radius * -1) && dot < dist + radius )
{
closestPoint = origin1 + ( deltaNml * dot );
distEnemySq = DistanceSquared( closestPoint, enemy.origin );
if ( distEnemySq <= radiusSq )
enemy DoDamage( damage, closestPoint, attacker, self, "MOD_EXPLOSIVE", "orbital_carepackage_pod_mp" );
}
}
}
SetMissileSpecialClipmaskDelayed( delayTime )
{
self endon("death");
wait delayTime;
self SetMissileSpecialClipmask( true ); // Causes the rocket to collide with item clip, which is necessary as it will become a physics object on impact
}
createPlayerDropPod(podrocket)
{
PodNum = 0;
if(!IsDefined(level._orbital_care_pod))
{
level._orbital_care_pod = [];
}
else //if (IsDefined(self._orbital_care_pod))
{
level._orbital_care_pod = cleanArray(level._orbital_care_pod);
PodNum = level._orbital_care_pod.size;
}
level._orbital_care_pod[PodNum] = SpawnStruct();
level._orbital_care_pod[PodNum].HasLeftCam = false;
level._orbital_care_pod[PodNum].podrocket = podrocket;
level._orbital_care_pod[PodNum].podrocket.maxhealth = 100;
level._orbital_care_pod[PodNum].podrocket.health = 100;
level._orbital_care_pod[PodNum].podrocket.damageTaken = 0;
level._orbital_care_pod[PodNum].podrocket.isPodRocket = true;
level._orbital_care_pod[PodNum].owner = self;
level._orbital_care_pod[PodNum].alive = true;
return level._orbital_care_pod[PodNum];
}
Rocket_CleanupOnDeath()
{
entityNumber = self getEntityNumber();
level.rockets[ entityNumber ] = self;
self waittill( "death" );
level.rockets[ entityNumber ] = undefined;
if(IsDefined(self.killCamEnt))
{
self.killCamEnt Unlink();
self.killCamEnt.origin += (0,0,300);
}
}
getDropTypeFromStreakName( streakName )
{
switch ( streakName )
{
case "orbital_carepackage_juggernaut_exosuit":
return "orbital_carepackage_juggernaut_exosuit";
case "airdrop_reinforcement_common":
return "airdrop_reinforcement_common";
case "airdrop_reinforcement_uncommon":
return "airdrop_reinforcement_uncommon";
case "airdrop_reinforcement_rare":
return "airdrop_reinforcement_rare";
case "airdrop_reinforcement_practice":
return "airdrop_reinforcement_practice";
case "horde_support_drop":
return "horde_support_drop";
default:
return "airdrop_assault";
}
}
allowDroneDelivery( player )
{
if ( !IsDefined( player ) )
return false;
if( level.teamBased && level.teamEMPed[player.team] )
return false;
if( !level.teamBased && IsDefined(level.empPlayer) && level.empPlayer != player )
return false;
return true;
}
monitorDrop( player, podrocket, DropPod, streakName, excludedCrateTypes, weaponType )
{
droptype = getDropTypeFromStreakName( streakName );
if ( droptype == "airdrop_assault" && array_contains( DropPod.modules, "orbital_carepackage_odds" ) )
droptype = "airdrop_assault_odds";
if ( IsDefined( level.getCrateForDropType ) )
crateType = [[ level.getCrateForDropType ]]( dropType );
else
crateType = maps\mp\killstreaks\_airdrop::getCrateTypeForDropType( droptype );
thread monitorDropInternal( player, podrocket, DropPod, droptype, crateType, weaponType );
return crateType;
}
monitorDropInternal( player, podrocket, DropPod, droptype, crateType, weaponType )
{
level endon ( "game_ended" );
podrocket thread Rocket_CleanupOnDeath();
hasTrap = array_contains( DropPod.modules, "orbital_carepackage_trap" );
dropCrate = player maps\mp\killstreaks\_airdrop::createAirDropCrate( player, droptype, crateType, podrocket.origin, undefined, hasTrap, false );
dropCrate.moduleTrap = array_contains( DropPod.modules, "orbital_carepackage_trap" );
dropCrate.moduleHide = array_contains( DropPod.modules, "orbital_carepackage_hide" );
dropCrate.moduleRoll = array_contains( DropPod.modules, "orbital_carepackage_roll" );
dropCrate.modulePickup = array_contains( DropPod.modules, "orbital_carepackage_fast_pickup" );
dropCrate.angles = (0,0,0);
podrocket.killCamEnt = dropCrate.killCamEnt;
if ( weaponType == "orbital_carepackage_pod_plane_mp" )
podrocket.killCamEnt.killCamStartTime = GetTime();
droneDelivery = array_contains(DropPod.modules, "orbital_carepackage_drone");
marker = Spawn( "script_model", DropPod.dropPoint + ( 0, 0, 5 ) );
marker.angles = ( -90, 0, 0 );
marker SetModel( "tag_origin" );
marker Hide();
marker ShowToPlayer( player );
PlayFXOnTag( getfx( "ocp_ground_marker" ), marker, "tag_origin" );
marker thread carePackageSetupMinimap( DropPod.modules, player );
maps\mp\killstreaks\_orbital_util::addDropMarker( marker );
if ( droneDelivery )
player thread playerMonitorForDroneDelivery( podrocket, DropPod, marker, dropCrate );
dropCrate LinkTo( podrocket, "tag_origin", ( 0, 0, 0 ), ( -90, 0, 0 ) );
podrocket waittill( "death", attacker_ent, means_of_death, weapon_name );
if ( IsDefined( podrocket ) && !droneDelivery && podrocket.origin[2] > DropPod.dropPoint[2] && DistanceSquared( podrocket.origin, DropPod.dropPoint ) > DROPPOINT_DISTANCE_SQ )
{
if ( DropPod.giveBackCarepackage )
{
if ( isdefined ( level.isHorde ) && level.isHorde )
{
outsidePosition = [[level.hordeGetOutsidePosition]]();
FirePod( "orbital_carepackage_pod_mp", self, outsidePosition, "horde_support_drop", DropPod.modules, false, undefined, undefined, true );
}
else
{
if ( IsDefined( player ) )
player playerGiveBackCarepackage( DropPod );
}
}
level thread cleanupCarepackage( DropPod, dropCrate, marker );
return;
}
if ( droneDelivery && allowDroneDelivery(player) && IsDefined( DropPod.drone ) )
{
DropPod.drone Show();
}
else
{
Earthquake( 0.4, 1, DropPod.dropPoint, 800 );
PlayRumbleOnPosition( "artillery_rumble", DropPod.dropPoint );
}
KillFXOnTag( getfx( "ocp_ground_marker" ), marker, "tag_origin" );
DropPod.alive = false;
if ( droneDelivery && allowDroneDelivery(player) && IsDefined( DropPod.drone ) )
{
DropPod.drone waittill( "delivered" );
dropCrate SetContents( dropCrate.oldContents );
dropCrate.oldContents = undefined;
}
marker thread carepackageCleanup( dropCrate );
dropCrate CloneBrushmodelToScriptmodel( level.airDropCrateCollision );
// Below adds physics to crate
dropCrate.droppingToGround = true;
dropCrate Unlink();
dropCrate PhysicsLaunchServer( (0,0,0) );
dropCrate thread crateDetectStopPhysics();
dropCrate thread orbitalPhysicsWaiter( droptype, crateType, player );
level thread RemovePod(dropCrate, DropPod);
}
crateImpactCleanup( player ) // self = dropCrate
{
if ( !IsDefined( player ) )
return;
nearestNodes = GetNodesInRadiusSorted( self.origin, 300, 0, 300 );
foreach ( character in level.characters )
{
if ( !IsAlive( character ) )
continue;
if ( IsAlliedSentient( character, player ) )
{
// Any allies that are touching the clip should be teleported out of its way
if ( character IsTouching( self ) )
{
foreach ( node in nearestNodes )
{
if ( DistanceSquared( node.origin, self.origin ) > 100 * 100 )
{
character SetOrigin( node.origin, true );
nearestNodes = array_remove( nearestNodes, node );
break;
}
}
}
}
}
}
crateDetectStopPhysics()
{
self endon( "physics_finished" );
self endon( "death" );
SECONDS_TO_STOP_PHYSICS = 4;
NUM_FRAMES_TO_STOP_PHYSICS = SECONDS_TO_STOP_PHYSICS / 0.05;
DIST_NOT_MOVING_SQ = 5 * 5;
numFrames = 0;
lastOrigin = self.origin;
while ( true )
{
waitframe();
distSq = DistanceSquared( lastOrigin, self.origin );
if ( distSq < DIST_NOT_MOVING_SQ )
numFrames++;
else
numFrames = 0;
lastOrigin = self.origin;
if ( numFrames >= NUM_FRAMES_TO_STOP_PHYSICS )
{
self PhysicsStop();
return;
}
}
}
playerGiveBackCarepackage( DropPod ) // self == player
{
streakVal = self maps\mp\killstreaks\_killstreaks::getStreakCost( "orbital_carepackage" );
slotIndex = self maps\mp\killstreaks\_killstreaks::getNextKillstreakSlotIndex( "orbital_carepackage", false );
self thread maps\mp\gametypes\_hud_message::killstreakSplashNotify( "orbital_carepackage", streakVal, undefined, DropPod.modules, slotIndex );
self thread maps\mp\killstreaks\_killstreaks::giveKillstreak( "orbital_carepackage", false, false, self, DropPod.modules );
}
cleanupCarepackage( DropPod, dropCrate, marker )
{
if ( IsDefined( dropCrate ) )
{
self thread RemovePod(dropCrate, DropPod);
dropCrate Delete();
}
if ( IsDefined( DropPod.drone ) )
DropPod.drone maps\mp\killstreaks\_drone_carepackage::carepackageDrone_remove();
if ( IsDefined( marker ) )
{
if ( IsDefined( marker.objIdFriendly ) )
_objective_delete( marker.objIdFriendly );
if ( IsDefined( marker.objIdEnemy ) )
_objective_delete( marker.objIdEnemy );
KillFXOnTag( getfx( "ocp_ground_marker" ), marker, "tag_origin" );
waitframe();
marker Delete();
}
}
orbitalPhysicsWaiter( droptype, crateType, player )
{
self endon("death");
self maps\mp\killstreaks\_airdrop::physicsWaiter( droptype, crateType );
self PlaySound("orbital_pkg_panel");
if(IsDefined(self.enemymodel))
{
self.enemymodel thread orbitalAnimate();
self.enemyModel Solid();
}
if(IsDefined(self.friendlymodel))
{
self.friendlymodel thread orbitalAnimate();
self.friendlymodel Solid();
}
self thread crateImpactCleanup( player );
}
orbitalAnimate( alreadyOpen )
{
self endon("death");
if ( !IsDefined( alreadyOpen ) || !alreadyOpen )
wait .75;
if ( IsDefined( alreadyOpen ) && alreadyOpen )
self ScriptModelPlayAnim("orbital_care_package_open_loop");
else
self ScriptModelPlayAnim("orbital_care_package_open");
PlayFXOnTag( getfx("ocp_glow"), self, "TAG_ORIGIN");
if ( !IsDefined( alreadyOpen ) || !alreadyOpen )
{
waitframe();
PlayFXOnTag( getfx("vfx_ocp_steam2"), self, "TAG_FX_PANEL_F");
PlayFXOnTag( getfx("vfx_ocp_steam2"), self, "TAG_FX_PANEL_K");
waitframe();
PlayFXOnTag( getfx("vfx_ocp_steam"), self, "TAG_FX_PANEL_FR");
PlayFXOnTag( getfx("vfx_ocp_steam"), self, "TAG_FX_PANEL_KL");
waitframe();
PlayFXOnTag( getfx("vfx_ocp_steam"), self, "TAG_FX_PANEL_FL");
PlayFXOnTag( getfx("vfx_ocp_steam"), self, "TAG_FX_PANEL_KR");
}
}
delayCleanupDropPod( dropPod )
{
wait 5;
dropPod Delete();
}
RemovePod(Crate, DropPod)
{
/////// In theory removes all left over meshes and and removes structs from the array on the player...
Crate waittill("death");
wait(15);
for(i = 0; i < level._orbital_care_pod.size; i++)
{
if(IsDefined(level._orbital_care_pod[i]) && level._orbital_care_pod[i] == DropPod)
{
if(level._orbital_care_pod[i].alive == false)
{
level._orbital_care_pod[i] = undefined;
}
}
}
if(IsDefined(DropPod))
{
DropPod = undefined;
}
}
// Setup of drop pod in the air
carePackageSetupMinimap( modules, carrier ) // self == fake care package
{
self endon( "death" );
if ( array_contains( modules, "orbital_carepackage_hide" ) )
return;
//setup owner team
curObjID = maps\mp\gametypes\_gameobjects::getNextObjID();
Objective_Add( curObjID, "invisible", ( 0, 0, 0 ) );
Objective_Position( curObjID, self.origin );
Objective_State( curObjID, "active" );
shaderName = "compass_objpoint_ammo_friendly";
Objective_Icon( curObjID, shaderName );
if ( !level.teamBased )
Objective_PlayerTeam( curObjId, carrier GetEntityNumber() );
else
Objective_Team( curObjID, carrier.team );
self.objIdFriendly = curObjID;
// setup enemy team
if( ! ( IsDefined ( level.isHorde ) && level.isHorde ) )
{
curObjID = maps\mp\gametypes\_gameobjects::getNextObjID();
Objective_Add( curObjID, "invisible", ( 0, 0, 0 ) );
Objective_Position( curObjID, self.origin );
Objective_State( curObjID, "active" );
Objective_Icon( curObjID, "compass_objpoint_ammo_enemy" );
if ( !level.teamBased )
Objective_PlayerEnemyTeam( curObjId, carrier GetEntityNumber() );
else
Objective_Team( curObjID, level.otherTeam[ carrier.team ] );
self.objIdEnemy = curObjID;
}
if ( array_contains( modules, "orbital_carepackage_drone" ) )
{
self waittill( "linkedToDrone" );
Objective_OnEntity( self.objIdFriendly, self );
if ( IsDefined( self.objIdEnemy ) )
{
Objective_OnEntity( self.objIdEnemy, self );
self Show(); // show to all now
}
}
}
carepackageCleanup( dropCrate ) // self == fake care package
{
dropCrate waittill_any( "physics_finished", "death" );
if ( IsDefined( self.objIdFriendly ) )
_objective_delete( self.objIdFriendly );
if ( IsDefined( self.objIdEnemy ) )
_objective_delete( self.objIdEnemy );
KillFXOnTag( getfx("ocp_glow"), self, "TAG_ORIGIN");
if( IsDefined ( level.isHorde ) && level.isHorde )
dropCrate notify ( "drop_pod_cleared" );
waitframe();
self Delete();
}
setupDamageCallback( crate )
{
crate.health = 500;
crate.maxhealth = crate.health;
crate.readyToDie = false;
setupDamageCallbackInternal( crate.friendlyModel );
setupDamageCallbackInternal( crate.enemyModel );
}
setupDamageCallbackInternal( crate )
{
crate thread maps\mp\gametypes\_damage::setEntityDamageCallback( 9999, undefined, undefined, ::crateHandleDamageCallback, true );
}
disableDamageCallback( crate )
{
disableDamageCallbackInternal( crate.friendlyModel );
disableDamageCallbackInternal( crate.enemyModel );
}
disableDamageCallbackInternal( crate )
{
crate.damageCallback = undefined;
crate SetCanDamage( false );
crate SetDamageCallbackOn( false );
}
crateHandleDamageCallback( attacker, weapon, type, damage )
{
parentCrate = self;
if ( IsDefined( self.parentCrate ) )
parentCrate = self.parentCrate;
finalDamage = self maps\mp\gametypes\_damage::modifyDamage( attacker, weapon, type, damage );
parentCrate.health -= finalDamage;
if ( parentCrate.health <= 0 )
{
// don't actually let code destroy it
disableDamageCallback( parentCrate );
parentCrate notify( "disabled" );
}
return 0;
}
playerMonitorForDroneDelivery( podRocket, dropPod, marker, dropCrate )
{
self endon( "disconenct" );;
self endon( "joined_team" );
self endon( "joined_spectators" );
SCR_CONST_REACHED_NODE_RADIUS_SQ = 24 * 24;
DIST_TO_GROUND_SQ = 500 * 500;
targetPos = dropPod.dropPoint;
curPos = podRocket.origin;
distToGroundSq = DistanceSquared( curPos, targetPos );
setupDamageCallback( dropCrate );
drone = dropPod.drone;
drone thread carepackageDroneWatchCrateDeath( dropCrate );
dropCrate.oldContents = dropCrate SetContents( 0 );
dropCrate.friendlyModel Solid();
dropCrate.enemyModel Solid();
while ( true )
{
if ( !IsDefined( podRocket ) )
break;
curPos = podRocket.origin;
distToGroundSq = DistanceSquared( curPos, targetPos );
if ( distToGroundSq <= DIST_TO_GROUND_SQ )
break;
waitframe();
}
if ( distToGroundSq > DIST_TO_GROUND_SQ )
{
if ( dropPod.giveBackCarepackage && allowDroneDelivery( self ) )
self playerGiveBackCarepackage( dropPod );
level thread cleanupCarepackage( dropPod, dropCrate, marker );
return;
}
if ( !IsDefined( self ) )
{
level thread cleanupCarepackage( dropPod, dropCrate, marker );
return;
}
// if EMP'd abort on drone delivery
if ( !allowDroneDelivery( self ) )
{
level thread cleanupCarepackage( dropCrate, undefined, undefined );
return;
}
drone thread carepackageDroneWatchDeath();
drone endon( "death" );
drone Vehicle_Teleport( dropCrate.origin, dropCrate.angles, false, false );
dropCrate LinkTo( drone, "tag_origin", ( 0, 0, 0 ), ( 0, 0, 0 ) );
dropCrate.friendlyModel ScriptModelPlayAnim( "orbital_care_package_fan_spin", "nothing" );
dropCrate.enemyModel ScriptModelPlayAnim( "orbital_care_package_fan_spin", "nothing" );
maps\mp\killstreaks\_drone_carepackage::setupCarepackageDrone( drone, true );
drone.crate = dropCrate;
if ( IsDefined( podRocket ) )
{
curPos = podRocket.origin;
podRocket notify( "death" );
podRocket Delete();
}
playSoundAtPos( curPos, "orbital_pkg_pod_midair_exp" );
PlayFX( getfx( "ocp_midair" ), curPos, GetDvarVector("scr_ocp_forward", ( 0, 0, -1 ) ) );
drone thread drone_thrusterFX();
goalPos = DropPod.dropPoint + NODE_OFFSET;
drone SetVehGoalPos( goalPos, true );
drone Vehicle_SetSpeedImmediate( GetDvarFloat( "scr_ocp_dropspeed", 30 ), GetDvarFloat( "scr_ocp_dropa", 20 ), GetDvarFloat( "scr_ocp_dropd", 1 ) );
drone SetHoverParams( 30, 5, 5 );
drone SetMaxPitchRoll( 15, 15 );
while ( DistanceSquared( drone.origin, goalPos ) > SCR_CONST_REACHED_NODE_RADIUS_SQ && dropCrate.health > 0 )
waitframe();
if ( dropCrate.health > 0 )
wait 1;
if ( dropCrate.health > 0 )
{
marker LinkTo( drone, "tag_origin" );
marker notify( "linkedToDrone" );
drone thread maps\mp\killstreaks\_drone_carepackage::carepackageDrone_deleteOnActivate();
drone carepackageDroneFindOwner();
}
disableDamageCallback( dropCrate );
dropCrate PlaySoundOnMovingEnt( "orbital_pkg_drone_jets_off" );
if ( IsDefined( drone ) )
drone drone_stopThrusterEffects();
dropCrate.friendlyModel ScriptModelClearAnim( "orbital_care_package_fan_spin", "nothing" );
dropCrate.enemyModel ScriptModelClearAnim( "orbital_care_package_fan_spin", "nothing" );
waitframe();
if ( IsDefined( drone ) )
drone maps\mp\killstreaks\_drone_carepackage::carepackageDrone_Delete();
}
carepackageDroneWatchDeath() // self == drone
{
self endon( "delivered" );
self waittill( "death" );
self notify( "delivered" );
}
carepackageDroneWatchCrateDeath( crate ) // self == drone
{
self endon( "delivered" );
crate waittill( "disabled" );
self notify( "delivered" );
}
/#
carepackageDroneDebugPathing() // self == drone
{
owner = self.owner;
owner endon( "disconnect" );
self endon( "death" );
self endon( "delivered" );
toOwner = true;
goalClient = self.owner;
SetDvarIfUninitialized( "scr_ocp_debugDeliveryNext", "0" );
DIST_BEFORE_DELIVERY_SQ = ( 150 * 150 );
restartPathing = true;
nextGoalTime = GetTime();
while ( GetDvar( "scr_ocp_debugDelivery", "0" ) != "0" )
{
while ( true )
{
alive = isReallyAlive( goalClient );
if ( !alive )
{
restartPathing = true;
waitframe();
}
if ( nextGoalTime < GetTime() || restartPathing )
{
restartPathing = false;
self SetDroneGoalPos( goalClient, FLY_NODE_OFFSET + ( 0, -100, 0 ) );
nextGoalTime = GetTime() + 1000;
}
distSq = DistanceSquared( self.origin, goalClient.origin + FLY_NODE_OFFSET );
if ( distSq < DIST_BEFORE_DELIVERY_SQ )
{
break;
}
waitframe();
}
while ( GetDvar( "scr_ocp_debugDeliveryNext" ) == "0" )
waitframe();
SetDvar( "scr_ocp_debugDeliveryNext", "0" );
toOwner = !toOwner;
if ( !toOwner && IsDefined( level.players[1] ) )
{
goalClient = level.players[1];
}
else
{
goalClient = owner;
toOwner = true;
}
}
}
#/
carepackageDroneFindOwner() // self == drone
{
owner = self.owner;
owner endon( "disconnect" );
self endon( "death" );
self endon( "delivered" );
/#
if ( GetDvar( "scr_ocp_debugDelivery", "0" ) != "0" )
{
self carepackageDroneDebugPathing();
}
#/
DIST_BEFORE_DELIVERY_SQ = ( 150 * 150 );
restartPathing = true;
nextGoalTime = GetTime();
while ( true )
{
ownerAlive = isReallyAlive( owner );
if ( !ownerAlive )
{
restartPathing = true;
waitframe();
}
if ( nextGoalTime < GetTime() || restartPathing )
{
restartPathing = false;
self SetDroneGoalPos( owner, FLY_NODE_OFFSET + ( 0, -100, 0 ) );
nextGoalTime = GetTime() + 1000;
}
distSq = DistanceSquared( self.origin, owner.origin + FLY_NODE_OFFSET );
if ( distSq < DIST_BEFORE_DELIVERY_SQ )
{
wait GetDvarFloat( "scr_ocp_waitDeliver", 1 );
self notify( "delivered" );
return;
}
waitframe();
}
}
drone_thrusterFX()
{
self endon( "death" );
PlayFXOnTag( getfx( "ocp_thruster_small" ), self, "j_thruster_fl" );
PlayFXOnTag( getfx( "ocp_thruster_small" ), self, "j_thruster_fr" );
PlayFXOnTag( getfx( "ocp_thruster_small" ), self, "j_thruster_kl" );
PlayFXOnTag( getfx( "ocp_thruster_small" ), self, "j_thruster_kr" );
waitframe();
waitframe();
if ( IsDefined( self ) )
PlayFXOnTag( getfx( "ocp_exhaust" ), self, "tag_fx" );
while ( true )
{
level waittill( "connected", player );
self thread drone_thrusterPlayerConnected( player );
}
}
drone_thrusterPlayerConnected( player )
{
player endon( "disconnect" );
player waittill( "spawned_player" );
if ( IsDefined( player ) && IsDefined( self ) )
self drone_thrusterPlayer( player );
}
drone_thrusterPlayer( player ) // self == drone
{
player endon( "disconnect" );
self endon( "death" );
PlayFXOnTagForClients( getfx( "ocp_thruster_small" ), self, "j_thruster_fl", player );
PlayFXOnTagForClients( getfx( "ocp_thruster_small" ), self, "j_thruster_fr", player );
PlayFXOnTagForClients( getfx( "ocp_thruster_small" ), self, "j_thruster_kl", player );
PlayFXOnTagForClients( getfx( "ocp_thruster_small" ), self, "j_thruster_kr", player );
waitframe();
waitframe();
if ( IsDefined( self ) )
PlayFXOnTagForClients( getfx( "ocp_exhaust" ), self, "tag_fx", player );
}
drone_stopThrusterEffects() // self == drone
{
KillFXOnTag( getfx( "ocp_thruster_small" ), self, "j_thruster_fl" );
KillFXOnTag( getfx( "ocp_thruster_small" ), self, "j_thruster_fr" );
KillFXOnTag( getfx( "ocp_thruster_small" ), self, "j_thruster_kl" );
KillFXOnTag( getfx( "ocp_thruster_small" ), self, "j_thruster_kr" );
waitframe();
waitframe();
if ( IsDefined( self ) )
KillFXOnTag( getfx( "ocp_exhaust" ), self, "tag_fx" );
}
/#
debugDestroyCarepackages()
{
while ( true )
{
if ( GetDvar( "scr_ocp_destroyall", "0" ) != "0" )
{
SetDvar( "scr_ocp_destroyall", "0" );
foreach ( crate in level.carePackages )
crate maps\mp\killstreaks\_airdrop::deleteCrate();
}
waitframe();
}
}
#/