boiii-scripts/mp/killstreaks/_placeables.gsc
2023-04-13 17:30:38 +02:00

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();
}
}
}
}