984 lines
26 KiB
Plaintext
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();
|
|
}
|
|
}
|
|
#/ |