535 lines
19 KiB
Plaintext
535 lines
19 KiB
Plaintext
#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;
|
|
|
|
|
|
|
|
|
|
#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();
|
|
}
|
|
}
|
|
}
|
|
}
|