aboutsummaryrefslogtreecommitdiff
path: root/Northstar.CustomServers/scripts/vscripts/_utility.gnut
diff options
context:
space:
mode:
Diffstat (limited to 'Northstar.CustomServers/scripts/vscripts/_utility.gnut')
-rw-r--r--Northstar.CustomServers/scripts/vscripts/_utility.gnut4394
1 files changed, 0 insertions, 4394 deletions
diff --git a/Northstar.CustomServers/scripts/vscripts/_utility.gnut b/Northstar.CustomServers/scripts/vscripts/_utility.gnut
deleted file mode 100644
index 50851dae..00000000
--- a/Northstar.CustomServers/scripts/vscripts/_utility.gnut
+++ /dev/null
@@ -1,4394 +0,0 @@
-
-globalize_all_functions
-
-//=========================================================
-// _utility
-//
-//=========================================================
-
-int functionref( bool = false ) ornull te = null
-int EntTracker = 0
-
-global const C_PLAYFX_SINGLE = 0
-global const C_PLAYFX_MULTIPLE = 1
-global const C_PLAYFX_LOOP = 2
-
-global const MUTEALLFADEIN = 2
-
-global struct ZipLine
-{
- entity start
- entity mid
- entity end
-}
-
-global int HUMAN_RAGDOLL_IMPACT_TABLE_IDX = -1
-
-global struct ArrayDotResultStruct
-{
- entity ent
- float dot
-}
-
-global struct ShieldDamageModifier
-{
- float permanentDamageFrac = TITAN_SHIELD_PERMAMENT_DAMAGE_FRAC
- bool normalizeShieldDamage = false
- float damageScale = 1.0
-}
-
-
-struct
-{
- bool isSkyboxView = false
-} file
-
-void function Utility_Init()
-{
- te = TotalEnts
- EntTracker = 0
-
- #document( "SetDeathFuncName", "Sets the name of a function that runs when the NPC dies." )
- #document( "CenterPrint", "Print to the screen" )
- #document( "GetAllSoldiers", "Get all living soldiers." )
- #document( "ClearDeathFuncName", "Clears the script death function." )
-
- HUMAN_RAGDOLL_IMPACT_TABLE_IDX = PrecacheImpactEffectTable( "ragdoll_human" )
-
- RegisterSignal( "PetTitanUpdated" )
- RegisterSignal( "WaitDeadTimeOut" )
- RegisterSignal( "InventoryChanged" )
-
- AddClientCommandCallback( "OnDevnetBugScreenshot", ClientCommand_OnDevnetBugScreenshot )
- #if DEV
- FlagInit( "AimAssistSwitchTest_Enabled" )
- AddClientCommandCallback( "DoomTitan", ClientCommand_DoomTitan )
- #endif
-}
-
-void function GiveAllTitans()
-{
-
- array<entity> players = GetPlayerArray()
- foreach ( player in players )
- {
- #if MP
- GiveTitanToPlayer( player )
- #endif
-
- if ( player.IsTitan() )
- {
- entity soul = player.GetTitanSoul()
- if ( soul )
- {
- SoulTitanCore_SetNextAvailableTime( soul, 1 )
- }
- }
- }
-
- array<entity> titans = GetNPCArrayByClass( "npc_titan" )
- foreach ( titan in titans )
- {
- entity soul = titan.GetTitanSoul()
- if ( soul )
- SoulTitanCore_SetNextAvailableTime( soul, 1 )
- }
-}
-
-#if DEV
-
-void function KillAllBadguys()
-{
- array<entity> npcs = GetNPCArrayOfEnemies( GetPlayerArray()[0].GetTeam() )
- foreach ( n in npcs )
- {
- if ( n.GetClassName() == "npc_bullseye" )
- continue
-
- if ( !IsAlive( n ) )
- continue
- n.Die()
- }
-}
-
-bool function ClientCommand_DoomTitan( entity player, array<string> args )
-{
- entity titan
- if ( player.IsTitan() )
- titan = player
- else
- titan = player.GetPetTitan()
-
- if ( !IsAlive( titan ) )
- return true
-
- if ( GetDoomedState( titan ) )
- return true
-
- entity soul = titan.GetTitanSoul()
- soul.SetShieldHealth( 0 )
-
- titan.TakeDamage( titan.GetHealth(), null, null, { damageSourceId=damagedef_suicide, scriptType = DF_SKIP_DAMAGE_PROT } )
-
- return true
-}
-#endif
-
-void function PrintPlaylists()
-{
- printt( "=== PLAYLIST NAMES: ===" )
-
- int count = GetPlaylistCount()
- for ( int i = 0; i < count; i++ )
- {
- printt( "--", GetPlaylistName( i ) )
- }
-}
-
-entity function CreateEntity( string name )
-{
-// if ( name == "npc_titan" )
-// {
-// DumpStack(3)
-// }
-// if ( name == "info_particle_system" )
-// {
-// printl( " " )
-// DumpStack(3)
-// }
- return Entities_CreateByClassname( name )
-}
-
-// used from the console to quick-test fields
-void function setnpcfields( string key, var val )
-{
- array<entity> npcs = GetNPCArrayByClass( "npc_soldier" )
- foreach ( npc in npcs )
- {
- npc.kv[ key ] = val
- }
-}
-
-void function WaitUntilNumDead( array<entity> guys, int numDead )
-{
- Assert( numDead <= guys.len(), "asked for " + numDead + " guys to die, but only passed in an array of " + guys.len() + " guys." )
- float timeout = -1
- __WaitUntilDeadInternal( guys, numDead, timeout, __WaitUntilDeadTracker )
-}
-
-void function WaitUntilNumDeadWithTimeout( array<entity> guys, int numDead, float timeout )
-{
- Assert( numDead <= guys.len(), "asked for " + numDead + " guys to die, but only passed in an array of " + guys.len() + " guys." )
- Assert( timeout > 0 )
- __WaitUntilDeadInternal( guys, numDead, timeout, __WaitUntilDeadTracker )
-}
-
-void function WaitUntilAllDead( array<entity> guys )
-{
- int count = guys.len()
- float timeout = -1
- __WaitUntilDeadInternal( guys, count, timeout, __WaitUntilDeadTracker )
-}
-
-void function WaitUntilAllDeadWithTimeout( array<entity> guys, float timeout )
-{
- int count = guys.len()
- Assert( timeout > 0 )
- __WaitUntilDeadInternal( guys, count, timeout, __WaitUntilDeadTracker )
-}
-
-void function WaitUntilNumDeadOrLeeched( array<entity> guys, int numDead )
-{
- Assert( numDead <= guys.len(), "asked for " + numDead + " guys to die, but only passed in an array of " + guys.len() + " guys." )
- float timeout = -1
- __WaitUntilDeadInternal( guys, numDead, timeout, __WaitUntilDeadOrLeechedTracker )
-}
-
-void function WaitUntilNumDeadOrLeechedWithTimeout( array<entity> guys, int numDead, float timeout )
-{
- Assert( numDead <= guys.len(), "asked for " + numDead + " guys to die, but only passed in an array of " + guys.len() + " guys." )
- Assert( timeout > 0 )
- __WaitUntilDeadInternal( guys, numDead, timeout, __WaitUntilDeadOrLeechedTracker )
-}
-
-void function WaitUntilAllDeadOrLeeched( array<entity> guys )
-{
- int count = guys.len()
- float timeout = -1
- __WaitUntilDeadInternal( guys, count, timeout, __WaitUntilDeadOrLeechedTracker )
-}
-
-void function WaitUntilAllDeadOrLeechedWithTimeout( array<entity> guys, float timeout )
-{
- int count = guys.len()
- Assert( timeout > 0 )
- __WaitUntilDeadInternal( guys, count, timeout, __WaitUntilDeadOrLeechedTracker )
-}
-
-void function __WaitUntilDeadInternal( array<entity> guys, int numDead, float timeout, void functionref( entity, table<string, int> ) deathTrackerFunc )
-{
- table<string, int> master = { count = numDead }
-
- if ( timeout > 0.0 )
- thread __WaitUntilDeadTrackerDelayedSignal( master, "WaitDeadTimeOut", timeout )
-
- //when the thread ends, let child threads know
- OnThreadEnd(
- function() : ( master )
- {
- Signal( master, "OnDestroy" )
- }
- )
-
- foreach ( guy in guys )
- thread deathTrackerFunc( guy, master )
-
- while ( master.count > 0 )
- {
- table result = WaitSignal( master, "OnDeath", "WaitDeadTimeOut" )
- if ( result.signal == "WaitDeadTimeOut" ) //can't do endsignal, because it will kill the calling function too
- return
- }
-}
-
-void function __WaitUntilDeadTrackerDelayedSignal( table<string, int> master, string signal, float delay )
-{
- EndSignal( master, signal )
-
- wait delay
- if ( IsValid( master ) )
- Signal( master, signal )
-}
-
-void function __WaitUntilDeadTracker( entity guy, table<string, int> master )
-{
- EndSignal( master, "OnDestroy" )
- if ( IsAlive( guy ) )
- WaitSignal( guy, "OnDeath", "OnDestroy" )
-
- master.count--
- Signal( master, "OnDeath" )
-}
-
-void function __WaitUntilDeadOrLeechedTracker( entity guy, table<string, int> master )
-{
- EndSignal( master, "OnDestroy" )
- if ( IsAlive( guy ) )
- WaitSignal( guy, "OnDeath", "OnDestroy", "OnLeeched" )
-
- master.count--
- Signal( master, "OnDeath" )
-}
-
-void function SetRebreatherMaskVisible( entity ent, bool visible )
-{
- asset modelname = ent.GetModelName()
-
- int maskIdx = ent.FindBodyGroup( "mask" )
- if ( maskIdx == -1 )
- return
-
- int visibleIdx = 1
- if ( !visible )
- visibleIdx = 0
-
- ent.SetBodygroup( maskIdx, visibleIdx )
-}
-
-int function EntHasSpawnflag( entity ent, int spawnflagHexVal )
-{
- return ( expect int( ent.kv.spawnflags ) & spawnflagHexVal )
-}
-
-entity function CreateInfoTarget( vector origin = <0,0,0>, vector angles = <0,0,0> )
-{
- entity info_target = CreateEntity( "info_target" )
- info_target.SetOrigin( origin )
- info_target.SetAngles( angles )
- DispatchSpawn( info_target )
- return info_target
-}
-
-entity function CreateExpensiveScriptMover( vector origin = <0.0, 0.0, 0.0>, vector angles = <0.0, 0.0, 0.0>, int solidType = 0 )
-{
- entity script_mover = CreateEntity( "script_mover" )
- script_mover.kv.solid = solidType
- script_mover.SetValueForModelKey( $"models/dev/empty_model.mdl" )
- script_mover.kv.SpawnAsPhysicsMover = 0
- script_mover.SetOrigin( origin )
- script_mover.SetAngles( angles )
-
- DispatchSpawn( script_mover )
- return script_mover
-}
-
-entity function CreateScriptMover( vector origin = <0.0, 0.0, 0.0>, vector angles = <0.0, 0.0, 0.0>, int solidType = 0 )
-{
- entity script_mover = CreateEntity( "script_mover_lightweight" )
- script_mover.kv.solid = solidType
- script_mover.SetValueForModelKey( $"models/dev/empty_model.mdl" )
- script_mover.kv.SpawnAsPhysicsMover = 0
- script_mover.SetOrigin( origin )
- script_mover.SetAngles( angles )
- DispatchSpawn( script_mover )
- return script_mover
-}
-
-entity function CreateScriptMoverModel( asset model, vector origin = <0.0, 0.0, 0.0>, vector angles = <0.0, 0.0, 0.0>, int solidType = 0, float fadeDist = -1 )
-{
- entity script_mover = CreateEntity( "script_mover_lightweight" )
- script_mover.kv.solid = solidType
- script_mover.kv.fadedist = fadeDist
- script_mover.SetValueForModelKey( model )
- script_mover.kv.SpawnAsPhysicsMover = 0
- script_mover.SetOrigin( origin )
- script_mover.SetAngles( angles )
- DispatchSpawn( script_mover )
- return script_mover
-}
-
-entity function CreateExpensiveScriptMoverModel( asset model, vector origin = <0.0, 0.0, 0.0>, vector angles = <0.0, 0.0, 0.0>, int solidType = 0, float fadeDist = -1 )
-{
- entity script_mover = CreateEntity( "script_mover" )
- script_mover.kv.solid = solidType
- script_mover.kv.fadedist = fadeDist
- script_mover.SetValueForModelKey( model )
- script_mover.kv.SpawnAsPhysicsMover = 0
- script_mover.SetOrigin( origin )
- script_mover.SetAngles( angles )
- DispatchSpawn( script_mover )
- return script_mover
-}
-
-entity function CreateOwnedScriptMover( entity owner )
-{
- entity script_mover = CreateEntity( "script_mover" )
- script_mover.kv.solid = 0
- script_mover.SetValueForModelKey( $"models/dev/empty_model.mdl" )
- script_mover.kv.SpawnAsPhysicsMover = 0
- script_mover.SetOrigin( owner.GetOrigin() )
- script_mover.SetAngles( owner.GetAngles() )
- DispatchSpawn( script_mover )
- script_mover.Hide()
-
- script_mover.SetOwner( owner )
- return script_mover
-}
-
-// useful for finding out what ents are in a level. Should only be used for debugging.
-int function TotalEnts( bool hidden = false )
-{
- array<entity> entities
-
- EntTracker++
-
- entity ent = Entities_FindInSphere( null, < 0, 0, 0 >, 90000 )
- string name
- for ( ;; )
- {
- if ( ent == null )
- break
-
- entities.append( ent )
-
- name = ent.GetTargetName()
-
- string strPrefix = "Old ent"
- if ( ent.e.totalEntsStoredID == 0 )
- {
- string strPrefix = "* New ent"
- ent.e.totalEntsStoredID = EntTracker
- }
-
- string strPostfix = ""
- if ( name != "" )
- strPostfix = " \"" + name + "\""
-
- if ( !hidden )
- printl( strPrefix + " (" + ent.e.totalEntsStoredID + "): " + ent + strPostfix )
-
- ent = Entities_FindInSphere( ent, < 0, 0, 0 >, 90000 )
- }
-
- if ( !hidden )
- printl( "Total entities " + entities.len() )
-
- return entities.len()
-}
-
-bool function IsThreadTop()
-{
- return getstackinfos( 3 ) == null
-}
-
-string function ThisFunc()
-{
- return expect string( expect table( getstackinfos( 2 ) )[ "func" ] )
-}
-
-entity function ge( int index ) // shorthand version for typing from console
-{
- return GetEntByIndex( index )
-}
-
-entity function GetEnt( string name )
-{
- entity ent = Entities_FindByName( null, name )
- if ( ent == null )
- {
- ent = Entities_FindByClassname( null, name )
- Assert( Entities_FindByClassname( ent, name ) == null, "Tried to GetEnt but there were multiple entities with that name" )
- }
- else
- {
- Assert( Entities_FindByName( ent, name ) == null, "Tried to GetEnt but there were multiple entities with name " + name )
- }
-
- return ent
-}
-
-array<entity> function ArrayWithinCenter( array<entity> ents, vector start, int range )
-{
- array<entity> Array
- foreach ( ent in ents )
- {
- if ( Distance( start, ent.GetWorldSpaceCenter() ) > range )
- continue
-
- Array.append( ent )
- }
-
- return Array
-}
-
-vector function GetCenter( array<entity> ents )
-{
- vector total
-
- foreach ( ent in ents )
- {
- total += ent.GetOrigin()
- }
-
- total.x /= float( ents.len() )
- total.y /= float( ents.len() )
- total.z /= float( ents.len() )
-
- return total
-}
-
-void function TableRemoveInvalid( table<entity, entity> Table )
-{
- array<entity> deleteKey = []
-
- foreach ( entity key, entity value in Table )
- {
- if ( !IsValid_ThisFrame( key ) )
- deleteKey.append( key )
-
- if ( !IsValid_ThisFrame( value ) )
- deleteKey.append( key )
- }
-
- foreach ( key in deleteKey )
- {
- // in this search, two things could end up on the same key
- if ( key in Table )
- delete Table[ key ]
- }
-}
-
-void function TableRemoveInvalidByValue( table<entity, entity> Table )
-{
- array<entity> deleteKey = []
-
- foreach ( key, entity value in Table )
- {
- if ( !IsValid_ThisFrame( value ) )
- deleteKey.append( key )
- }
-
- foreach ( key in deleteKey )
- {
- delete Table[ key ]
- }
-}
-
-void function TableRemoveDeadByKey( table<entity, entity> Table )
-{
- array<entity> deleteKey = []
-
- foreach ( key, value in Table )
- {
- if ( !IsAlive( key ) )
- deleteKey.append( key )
- }
-
- foreach ( key in deleteKey )
- {
- delete Table[ key ]
- }
-}
-
-
-void function ArrayDump( array<var> Array )
-{
- for ( int i = 0; i < Array.len(); i++ )
- {
- printl( "index " + i + " is: " + Array[i] )
- }
-}
-
-
-int function DotCompareLargest( ArrayDotResultStruct a, ArrayDotResultStruct b )
-{
- if ( a.dot < b.dot )
- return 1
- else if ( a.dot > b.dot )
- return -1
-
- return 0
-}
-
-int function DotCompareSmallest( ArrayDotResultStruct a, ArrayDotResultStruct b )
-{
- if ( a.dot > b.dot )
- return 1
- else if ( a.dot < b.dot )
- return -1
-
- return 0
-}
-
-array<ArrayDotResultStruct> function ArrayDotResults( array<entity> Array, entity ent )
-{
- array<ArrayDotResultStruct> allResults
-
- foreach ( arrayEnt in Array )
- {
- ArrayDotResultStruct results
-
- results.dot = VectorDot_EntToEnt( ent, arrayEnt )
- results.ent = arrayEnt
- allResults.append( results )
- }
-
- return allResults
-}
-
-
-// Return an array of entities ordered from closest to furthest from the facing of the entity
-array<entity> function ArrayClosestToView( array<entity> Array, entity ent )
-{
- Assert( type( Array ) == "array" )
- array<ArrayDotResultStruct> allResults = ArrayDotResults( Array, ent )
-
- allResults.sort( DotCompareLargest )
-
- array<entity> returnEntities = []
-
- foreach ( index, result in allResults )
- {
- //printl( "Results are " + result.dot )
- returnEntities.insert( index, result.ent )
- }
-
- // the actual distances aren't returned
- return returnEntities
-}
-
-
-entity function SpawnRefEnt( entity ent )
-{
- printl( "Ent model " + ent.GetValueForModelKey() )
- int attach = ent.LookupAttachment( "ref" )
- vector origin = ent.GetAttachmentOrigin( attach )
- vector angles = ent.GetAttachmentAngles( attach )
-
- entity ref = CreateEntity( "prop_dynamic" )
- //ref.kv.SpawnAsPhysicsMover = 0
- ref.SetValueForModelKey( $"models/dev/empty_model.mdl" )
- DispatchSpawn( ref )
-
- ref.SetOrigin( origin )
- ref.SetAngles( angles )
- ref.Hide()
- return ref
-}
-
-entity function CreateScriptRef( vector ornull origin = null, vector ornull angles = null )
-{
- entity ent = CreateEntity( "script_ref" )
-
- if ( origin )
- ent.SetOrigin( expect vector( origin ) )
-
- if ( angles )
- ent.SetAngles( expect vector( angles ) )
-
- DispatchSpawn( ent )
- return ent
-}
-
-entity function CreateScriptRefMinimap( vector origin, vector angles )
-{
- entity ent = CreateEntity( "script_ref_minimap" )
-
- ent.SetOrigin( origin )
- ent.SetAngles( angles )
-
- DispatchSpawn( ent )
-
- return ent
-}
-
-bool function exists( table tbl, string val )
-{
- if ( !(val in tbl) )
- return false
-
- return tbl[ val ] != null
-}
-
-var function TableRandomIndex( table Table )
-{
- array Array = []
-
- foreach ( index, _ in Table )
- {
- Array.append( index )
- }
-
- return Array.getrandom()
-}
-
-// should improve this
-float function YawDifference( float yaw1, float yaw2 )
-{
- Assert( yaw1 >= 0 )
- Assert( yaw1 <= 360 )
- Assert( yaw2 >= 0 )
- Assert( yaw2 <= 360 )
-
- float diff = fabs( yaw1 - yaw2 )
-
- if ( diff > 180 )
- return 360 - diff
- else
- return diff
-
- unreachable
-}
-
-
-
-/*function TrackIsTouching( ent )
-{
- return // now uses IsTouching
-
- //ent.s.touching <- {}
- //ent.ConnectOutput( "OnStartTouch", TrackIsTouching_OnStartTouch )
- //ent.ConnectOutput( "OnEndTouch", TrackIsTouching_OnEndTouch )
-}
-
-void function TrackIsTouching_OnStartTouch( entity self, entity activator, entity caller, var value )
-{
- if ( activator )
- {
- self.s.touching[ activator ] <- true
- }
-}
-
-void function TrackIsTouching_OnEndTouch( entity self, entity activator, entity caller, var value )
-{
- if ( activator )
- {
- if ( activator in self.s.touching )
- {
- delete self.s.touching[ activator ]
- }
- }
-}*/
-
-void function NPC_NoTarget( entity self )
-{
- self.SetNoTarget( true )
- self.SetNoTargetSmartAmmo( true )
-}
-
-vector function GetSimpleTraceEnd( vector start, vector end, float frac )
-{
- vector vec = end - start
- vec *= frac
- return start + vec
-}
-
-bool function LoadedMain()
-{
- if ( "LoadedMain" in level )
- return true
-
- level.LoadedMain <- true
-
- return false
-}
-
-void function Warning( string msg )
-{
- printl( "*** WARNING ***" )
- printl( msg )
- DumpStack()
- printl( "*** WARNING ***" )
-}
-
-void function TimeOut( float time )
-{
- table Table = {}
- EndSignal( Table, "OnDeath" )
- delaythread( time ) Signal( Table, "OnDeath" )
-}
-
-string function GetActiveWeaponClass( entity player )
-{
- entity weapon = player.GetActiveWeapon()
- Assert( weapon != null )
-
- string weaponclass = weapon.GetWeaponClassName()
- return weaponclass
-}
-
-bool function HasWeapon( entity ent, string weaponClassName, array<string> mods = [] )
-{
- Assert( ent.IsPlayer() || ent.IsNPC() )
-
- array<entity> weaponArray = ent.GetMainWeapons()
- foreach ( weapon in weaponArray )
- {
- if ( weapon.GetWeaponClassName() == weaponClassName )
- {
- if ( WeaponHasSameMods( weapon, mods ) )
- return true
- }
- }
-
- return false
-}
-
-bool function HasOrdnance( entity ent, string weaponClassName, array<string> mods = [] )
-{
- return HasOffhandForSlot( ent, OFFHAND_ORDNANCE, weaponClassName, mods )
-}
-
-bool function HasCoreAbility( entity ent, string weaponClassName, array<string> mods = [] )
-{
- return HasOffhandForSlot( ent, OFFHAND_EQUIPMENT, weaponClassName, mods )
-}
-
-bool function HasSpecial( entity ent, string weaponClassName, array<string> mods = [] )
-{
- return HasOffhandForSlot( ent, OFFHAND_SPECIAL, weaponClassName, mods )
-}
-
-bool function HasAntiRodeo( entity ent, string weaponClassName, array<string> mods = [] )
-{
- return HasOffhandForSlot( ent, OFFHAND_ANTIRODEO, weaponClassName, mods )
-}
-
-bool function HasMelee( entity ent, string weaponClassName, array<string> mods = [] )
-{
- return HasOffhandForSlot( ent, OFFHAND_MELEE, weaponClassName, mods )
-}
-
-bool function HasOffhandForSlot( entity ent, int slot, string weaponClassName, array<string> mods = [] )
-{
- Assert( ent.IsPlayer() || ent.IsNPC() )
-
- entity weapon = ent.GetOffhandWeapon( slot )
- if ( !IsValid( weapon ) )
- return false
-
- if ( weapon.GetWeaponClassName() != weaponClassName )
- return false
-
- return WeaponHasSameMods( weapon, mods )
-}
-
-bool function WeaponHasSameMods( entity weapon, array<string> mods = [] )
-{
- array hasMods = clone mods
- foreach ( mod in weapon.GetMods() )
- {
- hasMods.removebyvalue( mod )
- }
-
- // has all the same mods.
- return hasMods.len() == 0
-}
-
-bool function HasOffhandWeapon( entity ent, string weaponClassName )
-{
- Assert( ent.IsPlayer() || ent.IsNPC() )
-
- array<entity> weaponArray = ent.GetOffhandWeapons()
- foreach ( weapon in weaponArray )
- {
- if ( weapon.GetWeaponClassName() == weaponClassName )
- return true
- }
-
- return false
-}
-
-float function GetFraction( float value, float min, float max )
-{
- return ( value - min ) / ( max - min )
-}
-
-float function GetFractionClamped( float value, float min, float max )
-{
- float frac = GetFraction( value, min, max )
- return clamp( frac, 0.0, 1.0 )
-}
-
-float function GetValueFromFraction( float value, float value_min, float value_max, float return_min, float return_max )
-{
- float frac = GetFractionClamped( value, value_min, value_max )
- float retVal = return_min + ( ( return_max - return_min ) * frac )
- return clamp( retVal, return_min, return_max )
-}
-
-bool function VectorCompare( vector vec1, vector vec2 )
-{
- if ( vec1.x != vec2.x )
- return false
-
- if ( vec1.y != vec2.y )
- return false
-
- return vec1.z == vec2.z
-}
-
-// returns vectordot from viewEnt to targetEnt
-float function VectorDot_EntToEnt( entity viewEnt, entity targetEnt )
-{
- vector maxs = targetEnt.GetBoundingMaxs()
- vector mins = targetEnt.GetBoundingMins()
- maxs += mins
- maxs.x *= 0.5
- maxs.y *= 0.5
- maxs.z *= 0.5
- vector targetOrg = targetEnt.GetOrigin() + maxs
-
- maxs = viewEnt.GetBoundingMaxs()
- mins = viewEnt.GetBoundingMins()
- maxs += mins
- maxs.x *= 0.5
- maxs.y *= 0.5
- maxs.z *= 0.5
- vector viewOrg = viewEnt.GetOrigin() + maxs
-
- //DebugDrawLine( targetOrg, viewOrg, 255, 255, 255, true, 0.5 )
- vector vecToEnt = ( targetOrg - viewOrg )
- vecToEnt = Normalize( vecToEnt )
-
- float dotVal = DotProduct( vecToEnt, viewEnt.GetForwardVector() )
- return dotVal
-}
-
-void function PrecacheEffect( asset effectName )
-{
- entity warningParticle = CreateEntity( "info_particle_system" )
- warningParticle.SetValueForEffectNameKey( effectName )
- warningParticle.kv.start_active = 0
- DispatchSpawn( warningParticle )
- warningParticle.Destroy()
-}
-
-void function PrecacheEntity( string entName, asset model = $"" )
-{
- entity tempEnt = CreateEntity( entName )
-
- if ( model != $"" )
- tempEnt.SetValueForModelKey( model )
-
- tempEnt.kv.spawnflags = SF_NPC_ALLOW_SPAWN_SOLID
-
- DispatchSpawn( tempEnt )
- tempEnt.Destroy()
-}
-
-void function PrecacheProjectileEntity( string entName, string weaponClassName, asset model = $"" )
-{
- entity tempEnt = Entities_CreateProjectileByClassname( entName, weaponClassName )
-
- if ( model != $"" )
- tempEnt.SetValueForModelKey( model )
-
- tempEnt.kv.spawnflags = SF_NPC_ALLOW_SPAWN_SOLID
-
- DispatchSpawn( tempEnt )
- tempEnt.Destroy()
-}
-
-void function PrecacheSprite( asset spriteName )
-{
- entity sprite = CreateEntity( "env_sprite_oriented" )
- sprite.SetValueForModelKey( spriteName )
- sprite.kv.spawnflags = 1
- DispatchSpawn( sprite )
- sprite.Destroy()
-}
-
-entity function CreatePointMessage( string msg, vector origin, int displayRadius = 512 )
-{
- entity point_message = CreateEntity( "point_message" )
- point_message.SetOrigin( origin )
- point_message.kv.message = msg
- point_message.kv.radius = displayRadius
-
- DispatchSpawn( point_message )
-
- return point_message
-}
-
-entity function CreateGameText( string msg, float xPos, float yPos, int channel, string color = "255 255 255", float fadein = 2, float fadeout = 0.5, float holdtime = 2 )
-{
- entity game_text = CreateEntity( "game_text" )
-
- game_text.SetScriptName( "gt" + UniqueString() )
- game_text.kv.message = msg
- game_text.kv["x"] = xPos
- game_text.kv["y"] = yPos
- game_text.kv.channel = channel
- game_text.kv.color = color
- game_text.kv.color2 = "240 110 0" // doesn't appear to do anything atm, not supporting in params
- game_text.kv.fadein = fadein
- game_text.kv.fadeout = fadeout
- game_text.kv.holdtime = holdtime
- game_text.kv.fxtime = "0.25"
-
- DispatchSpawn( game_text )
-
- return game_text
-}
-
-// pass the origin where the player's feet would be
-// tests a player sized box for any collision and returns true only if it's clear
-bool function PlayerCanTeleportHere( entity player, vector testOrg, entity ignoreEnt = null ) //TODO: This is a copy of SP's PlayerPosInSolid(). Not changing it to avoid patching SP. Merge into one function next game
-{
- int solidMask = TRACE_MASK_PLAYERSOLID
- vector mins
- vector maxs
- int collisionGroup = TRACE_COLLISION_GROUP_PLAYER
- array<entity> ignoreEnts = [ player ]
-
- if ( IsValid( ignoreEnt ) )
- ignoreEnts.append( ignoreEnt )
- TraceResults result
-
- mins = player.GetPlayerMins()
- maxs = player.GetPlayerMaxs()
- result = TraceHull( testOrg, testOrg + < 0, 0, 1 >, mins, maxs, ignoreEnts, solidMask, collisionGroup )
-
- if ( result.startSolid )
- return false
-
- return true
-}
-
-
-enum eAttach
-{
- No
- ViewAndTeleport
- View
- Teleport
- ThirdPersonView
-}
-
-
-void function LoadDiamond()
-{
- printl( " " )
- printl( " " )
- printl( " " )
-
- // Draw a diamond of a random size and phase (of the moon) so it is easy to separate sections of logs.
- int random_spread = RandomIntRange( 4, 7 )
- float random_fullness = RandomFloat( 2.0 )
- bool functionref( int, int ) compare_func
- string msg
-
- if ( RandomFloat( 1.0 ) > 0.5 )
- {
- compare_func = bool function( int a, int b )
- {
- return a <= b
- }
- }
- else
- {
- compare_func = bool function( int a, int b )
- {
- return a >= b
- }
- }
-
- for ( int i = 0; i <= random_spread - 2; i++ )
- {
- msg = ""
-
- for ( int p = 0; p <= random_spread - i; p++ )
- {
- msg = msg + " "
- }
-
- for ( int p = 0; p <= i * 2; p++ )
- {
- if ( p == i * 2 || p == 0 )
- {
- msg = msg + "*"
- }
- else
- {
- int an_int = int( i * random_fullness )
-
- if ( compare_func( p, an_int ) )
- msg = msg + "*"
- else
- msg = msg + " "
- }
- }
-
- printl( msg )
- }
-
- for ( int i = random_spread - 1; i >= 0; i-- )
- {
- msg = ""
-
- for ( int p = 0; p <= random_spread - i; p++ )
- {
- msg = msg + " "
- }
-
-
- for ( int p = 0; p <= i * 2; p++ )
- {
- if ( p == i * 2 || p == 0 )
- {
- msg = msg + "*"
- }
- else
- {
- if ( compare_func( p, int( i * random_fullness ) ) )
- {
- msg = msg + "*"
- }
- else
- {
- msg = msg + " "
- }
- }
- }
-
- printl( msg )
- }
-
- printl( " " )
- printl( " " )
- printl( " " )
-}
-
-// this will clear all dropped weapons in the map
-void function ClearDroppedWeapons( float delayTime = 0.0 )
-{
- if ( delayTime > 0 )
- wait delayTime
-
- bool onlyNotOwnedWeapons = true // don't get the ones in guys' hands
- array<entity> weapons = GetWeaponArray( onlyNotOwnedWeapons )
-
- foreach ( weapon in weapons )
- {
- // don't clean up weapon pickups that were placed in leveled
- int spawnflags = expect string( weapon.kv.spawnflags ).tointeger()
- if ( spawnflags & SF_WEAPON_START_CONSTRAINED )
- continue
-
- weapon.Destroy()
- }
-}
-
-void function ClearActiveProjectilesForTeam( int team, vector searchOrigin = <0,0,0>, float searchDist = -1 )
-{
- array<entity> projectiles = GetProjectileArrayEx( "any", team, TEAM_ANY, searchOrigin, searchDist )
-
- printt( "cleaning up", projectiles.len(), "weapon projectiles for team", team )
-
- foreach ( proj in projectiles )
- {
- if( !IsValid( proj ) )
- continue
-
- proj.Destroy()
- }
-}
-
-void function RestockPlayerAmmo_Silent( entity player = null )
-{
- RestockPlayerAmmo( player, true )
-}
-
-void function RestockPlayerAmmo( entity player = null, bool isSilent = false )
-{
- array<entity> players
- if ( IsAlive( player ) )
- players.append( player )
- else
- players = GetPlayerArray_Alive()
-
- foreach( player in players )
- {
- player.RefillAllAmmo()
-
- if ( !isSilent )
- EmitSoundOnEntityOnlyToPlayer( player, player, "Coop_AmmoBox_AmmoRefill" )
- }
-}
-
-entity function CreateLightSprite( vector origin, vector angles, string lightcolor = "255 0 0", float scale = 0.5 )
-{
- // attach a light so we can see it
- entity env_sprite = CreateEntity( "env_sprite" )
- env_sprite.SetScriptName( UniqueString( "molotov_sprite" ) )
- env_sprite.kv.rendermode = 5
- env_sprite.kv.origin = origin
- env_sprite.kv.angles = angles
- env_sprite.kv.rendercolor = lightcolor
- env_sprite.kv.renderamt = 255
- env_sprite.kv.framerate = "10.0"
- env_sprite.SetValueForModelKey( $"sprites/glow_05.vmt" )
- env_sprite.kv.scale = string( scale )
- env_sprite.kv.spawnflags = 1
- env_sprite.kv.GlowProxySize = 16.0
- env_sprite.kv.HDRColorScale = 1.0
- DispatchSpawn( env_sprite )
- EntFireByHandle( env_sprite, "ShowSprite", "", 0, null, null )
-
- return env_sprite
-}
-
-// defaultWinner: if it's a tie, return this value
-int function GetCurrentWinner( int defaultWinner = TEAM_MILITIA )
-{
- int imcScore
- int militiaScore
-
- if ( IsRoundBased() )
- {
- imcScore = GameRules_GetTeamScore2( TEAM_IMC )
- militiaScore = GameRules_GetTeamScore2( TEAM_MILITIA )
-
- if ( IsRoundBasedUsingTeamScore() && ( imcScore == militiaScore ) )
- {
- imcScore = GameRules_GetTeamScore( TEAM_IMC )
- militiaScore = GameRules_GetTeamScore( TEAM_MILITIA )
- }
- }
- else
- {
- imcScore = GameRules_GetTeamScore( TEAM_IMC )
- militiaScore = GameRules_GetTeamScore( TEAM_MILITIA )
- }
-
- int currentWinner = defaultWinner
-
- if ( militiaScore > imcScore )
- currentWinner = TEAM_MILITIA
- else if ( imcScore > militiaScore )
- currentWinner = TEAM_IMC
-
- return currentWinner
-}
-
-void function SetNpcFollowsPlayerOverride( entity player, void functionref( entity, entity ) override )
-{
- player.p.followPlayerOverride = override
-}
-
-void function ClearNpcFollowsPlayerOverride( entity player )
-{
- player.p.followPlayerOverride = null
-}
-
-void function AddCallback_GameStateEnter( int gameState, void functionref() callbackFunc )
-{
- Assert( gameState < svGlobal.gameStateEnterCallbacks.len() )
-
- Assert( !svGlobal.gameStateEnterCallbacks[ gameState ].contains( callbackFunc ), "Already added " + string( callbackFunc ) + " with AddCallback_GameStateEnter" )
-
- svGlobal.gameStateEnterCallbacks[ gameState ].append( callbackFunc )
-}
-
-void function GM_SetObserverFunc( void functionref( entity ) callbackFunc )
-{
- svGlobal.observerFunc = callbackFunc
-}
-
-void function GM_AddPlayingThinkFunc( void functionref() callbackFunc )
-{
- Assert( !svGlobal.playingThinkFuncTable.contains( callbackFunc ), "Already added " + string( callbackFunc ) + " with GM_AddPlayingThinkFunc" )
-
- svGlobal.playingThinkFuncTable.append( callbackFunc )
-}
-
-void function GM_AddThirtySecondsLeftFunc( void functionref() callbackFunc )
-{
- Assert( !svGlobal.thirtySecondsLeftFuncTable.contains( callbackFunc ), "Already added " + string( callbackFunc ) + " with GM_AddThirtySecondsLeftFunc" )
-
- svGlobal.thirtySecondsLeftFuncTable.append( callbackFunc )
-}
-
-void function GM_SetMatchProgressAnnounceFunc( void functionref( int ) callbackFunc )
-{
- svGlobal.matchProgressAnnounceFunc = callbackFunc
-}
-
-// Get an absolute offset poistion to an entity even if it's been rotated in world space
-vector function GetEntPosPlusOffset( entity ent, float offsetX, float offsetY, float offsetZ )
-{
- vector entAngles = ent.GetAngles()
- vector entOrg = ent.GetOrigin()
-
- vector right = AnglesToRight( entAngles )
- right = Normalize( right )
- vector pos = entOrg + ( right * offsetY )
-
- vector forward = AnglesToForward( entAngles )
- forward = Normalize( forward )
- pos = pos + ( forward * offsetX )
-
- vector up = AnglesToUp( entAngles )
- up = Normalize( up )
- pos = pos + ( up * offsetZ )
-
- return pos
-}
-
-void function EmitSoundToTeamPlayers( string alias, int team )
-{
- array<entity> players = GetPlayerArrayOfTeam( team )
-
- foreach ( player in players )
- EmitSoundOnEntityOnlyToPlayer( player, player, alias )
-}
-
-void function EmitDifferentSoundsAtPositionForPlayerAndWorld( string soundForPlayer, string soundForWorld, vector position, entity player, int teamNum )
-{
- if ( IsValid( player ) && player.IsPlayer() )
- {
- EmitSoundAtPositionExceptToPlayer( teamNum, position, player, soundForWorld )
- EmitSoundAtPositionOnlyToPlayer( teamNum, position, player, soundForPlayer)
- }
- else
- {
- EmitSoundAtPosition( teamNum, position, soundForWorld )
- }
-}
-
-void function EmitDifferentSoundsOnEntityForPlayerAndWorld( string soundForPlayer, string soundForWorld, entity soundEnt, entity player )
-{
- if ( IsValid( player ) && player.IsPlayer() )
- {
- EmitSoundOnEntityExceptToPlayerNotPredicted( soundEnt, player, soundForWorld )
- EmitSoundOnEntityOnlyToPlayer(soundEnt, player, soundForPlayer)
- }
- else
- {
- EmitSoundOnEntity( soundEnt, soundForWorld )
- }
-}
-
-// Drop an entity to the ground by tracing straight down from its z-axis
-void function DropToGround( entity ent )
-{
- vector targetOrigin = OriginToGround( ent.GetOrigin() + <0,0,1> )
- ent.SetOrigin( targetOrigin )
-}
-
-void function DropTitanToGround( entity titan, array<entity> ignoreEnts )
-{
- vector endOrigin = titan.GetOrigin() - < 0, 0, 20000 >
- vector mins = GetBoundsMin( HULL_TITAN )
- vector maxs = GetBoundsMax( HULL_TITAN )
- TraceResults traceResult = TraceHull( titan.GetOrigin(), endOrigin, mins, maxs, ignoreEnts, TRACE_MASK_TITANSOLID, TRACE_COLLISION_GROUP_NONE )
-
- titan.SetOrigin( traceResult.endPos )
-}
-
-vector function OriginToGround( vector origin )
-{
- vector endOrigin = origin - < 0, 0, 20000 >
- TraceResults traceResult = TraceLine( origin, endOrigin, [], TRACE_MASK_NPCWORLDSTATIC, TRACE_COLLISION_GROUP_NONE )
-
- return traceResult.endPos
-}
-
-float function GetVerticalClearance( vector origin )
-{
- vector endOrigin = origin + < 0, 0, 20000 >
- TraceResults traceResult = TraceLine( origin, endOrigin, [], TRACE_MASK_NPCWORLDSTATIC, TRACE_COLLISION_GROUP_NONE )
- vector endPos = traceResult.endPos
- float zDelta = ( endPos.z - origin.z )
-
- return zDelta
-}
-
-// ---------------------------------------------------------------------
-// Determine if an entity is a valid player spawnpoint
-// ---------------------------------------------------------------------
-bool function PlayerSpawnpointIsValid( entity ent )
-{
- if ( ent.GetClassName() != "prop_dynamic" )
- return false
- if ( ent.GetValueForModelKey() != $"models/humans/pete/mri_male.mdl" )
- return false
-
- return true
-}
-
-// ---------------------------------------------------------------------
-// Make an NPC or the player invincible (true/false)
-// (_npc.nut intercepts incoming damage and negates it if the ent is tagged as invincible)
-// ---------------------------------------------------------------------
-void function MakeInvincible( entity ent )
-{
- Assert( IsValid( ent ), "Tried to make invalid " + ent + " invincible" )
- Assert( ent.IsNPC() || ent.IsPlayer(), "MakeInvincible() can only be called on NPCs and the player" )
- Assert( IsAlive( ent ), "Tried to make dead ent " + ent + " invincible" )
-
- ent.SetInvulnerable()
-}
-
-void function ClearInvincible( entity ent )
-{
- Assert( IsValid( ent ), "Tried to clear invalid " + ent + " invincible" )
-
- ent.ClearInvulnerable()
-}
-
-bool function IsInvincible( entity ent )
-{
- return ent.IsInvulnerable()
-}
-
-//-------------------------------------
-// Teleport an entity (teleporter) to an entity's org and angles (ent)
-//--------------------------------------
-void function TeleportToEnt( entity teleporter, entity ent )
-{
- Assert( teleporter != null, "Unable to teleport null entity" )
- Assert( ent != null, "Unable to teleport to a null entity" )
- teleporter.SetOrigin( ent.GetOrigin() )
- teleporter.SetAngles( ent.GetAngles() )
-}
-
-//-----------------------------------------------------------
-// CreateShake() - create and fire an env_shake at a specified origin
-// - returns the shake in case you want to parent it
-//------------------------------------------------------------
-
-entity function CreateShake_internal( vector org, float amplitude, float frequency, float duration, float radius, int spawnFlags )
-{
- entity env_shake = CreateEntity( "env_shake" )
- env_shake.kv.amplitude = amplitude
- env_shake.kv.radius = radius
- env_shake.kv.duration = duration
- env_shake.kv.frequency = frequency
- env_shake.kv.spawnflags = spawnFlags
-
- DispatchSpawn( env_shake )
-
- env_shake.SetOrigin( org )
-
- EntFireByHandle( env_shake, "StartShake", "", 0, null, null )
- EntFireByHandle( env_shake, "Kill", "", ( duration + 1 ), null, null )
-
- return env_shake
-}
-
-entity function CreateShake( vector org, float amplitude = 16, float frequency = 150, float duration = 1.5, float radius = 2048 )
-{
- return CreateShake_internal( org, amplitude, frequency, duration, radius, 0 );
-}
-
-entity function CreateShakeRumbleOnly( vector org, float amplitude = 16, float frequency = 150, float duration = 1.5, float radius = 2048 )
-{
- return CreateShake_internal( org, amplitude, frequency, duration, radius, SF_SHAKE_RUMBLE_ONLY );
-}
-
-entity function CreateShakeNoRumble( vector org, float amplitude = 16, float frequency = 150, float duration = 1.5, float radius = 2048 )
-{
- return CreateShake_internal( org, amplitude, frequency, duration, radius, SF_SHAKE_NO_RUMBLE );
-}
-
-entity function CreateAirShake( vector org, float amplitude = 16, float frequency = 150, float duration = 1.5, float radius = 2048 )
-{
- return CreateShake_internal( org, amplitude, frequency, duration, radius, SF_SHAKE_INAIR );
-}
-
-entity function CreateAirShakeRumbleOnly( vector org, float amplitude = 16, float frequency = 150, float duration = 1.5, float radius = 2048 )
-{
- return CreateShake_internal( org, amplitude, frequency, duration, radius, (SF_SHAKE_INAIR | SF_SHAKE_RUMBLE_ONLY) );
-}
-
-entity function CreateAirShakeNoRumble( vector org, float amplitude = 16, float frequency = 150, float duration = 1.5, float radius = 2048 )
-{
- return CreateShake_internal( org, amplitude, frequency, duration, radius, (SF_SHAKE_INAIR | SF_SHAKE_NO_RUMBLE) );
-}
-
-//-------------------------------------
-// CreatePhysExplosion - physExplosion...small, medium or large
-//--------------------------------------
-entity function CreatePhysExplosion( vector org, float radius, int magnitude = 1, int flags = 1, bool dealsDamage = true )
-{
- entity env_physexplosion = CreateEntity( "env_physexplosion" )
- env_physexplosion.kv.spawnflags = flags // default 1 = No Damage - Only Force
- env_physexplosion.kv.magnitude = magnitude
- env_physexplosion.kv.radius = string( radius )
- env_physexplosion.SetOrigin( org )
- env_physexplosion.kv.scriptDamageType = damageTypes.explosive
- DispatchSpawn( env_physexplosion )
-
- EntFireByHandle( env_physexplosion, "Explode", "", 0, null, null )
- EntFireByHandle( env_physexplosion, "Kill", "", 2, null, null )
-}
-
-//-----------------------------------------------------------
-// CreatePropDynamic( model ) - create a generic prop_dynamic with default properties
-//------------------------------------------------------------
-entity function CreatePropDynamic( asset model, vector ornull origin = null, vector ornull angles = null, var solidType = 0, float fadeDist = -1 )
-{
- entity prop_dynamic = CreateEntity( "prop_dynamic" )
- prop_dynamic.SetValueForModelKey( model )
- prop_dynamic.kv.fadedist = fadeDist
- prop_dynamic.kv.renderamt = 255
- prop_dynamic.kv.rendercolor = "255 255 255"
- prop_dynamic.kv.solid = solidType // 0 = no collision, 2 = bounding box, 6 = use vPhysics, 8 = hitboxes only
- if ( origin )
- {
- // hack: Setting origin twice. SetOrigin needs to happen before DispatchSpawn, otherwise the prop may not touch triggers
- prop_dynamic.SetOrigin( expect vector( origin ) )
- if ( angles )
- prop_dynamic.SetAngles( expect vector( angles ) )
- }
- DispatchSpawn( prop_dynamic )
- if ( origin )
- {
- // hack: Setting origin twice. SetOrigin needs to happen after DispatchSpawn, otherwise origin is snapped to nearest whole unit
- prop_dynamic.SetOrigin( expect vector( origin ) )
- if ( angles )
- prop_dynamic.SetAngles( expect vector( angles ) )
- }
-
- return prop_dynamic
-}
-
-
-//-----------------------------------------------------------
-// CreatePropDynamicLightweight( model ) - create a generic prop_dynamic_lightweight with default properties
-//------------------------------------------------------------
-entity function CreatePropDynamicLightweight( asset model, vector ornull origin = null, vector ornull angles = null, var solidType = 0, float fadeDist = -1 )
-{
- entity prop_dynamic = CreateEntity( "prop_dynamic_lightweight" )
- prop_dynamic.SetValueForModelKey( model )
- prop_dynamic.kv.fadedist = fadeDist
- prop_dynamic.kv.renderamt = 255
- prop_dynamic.kv.rendercolor = "255 255 255"
- prop_dynamic.kv.solid = solidType // 0 = no collision, 2 = bounding box, 6 = use vPhysics, 8 = hitboxes only
- if ( origin )
- {
- // hack: Setting origin twice. SetOrigin needs to happen before DispatchSpawn, otherwise the prop may not touch triggers
- prop_dynamic.SetOrigin( expect vector( origin ) )
- if ( angles )
- prop_dynamic.SetAngles( expect vector( angles ) )
- }
- DispatchSpawn( prop_dynamic )
- if ( origin )
- {
- // hack: Setting origin twice. SetOrigin needs to happen after DispatchSpawn, otherwise origin is snapped to nearest whole unit
- prop_dynamic.SetOrigin( expect vector( origin ) )
- if ( angles )
- prop_dynamic.SetAngles( expect vector( angles ) )
- }
-
- return prop_dynamic
-}
-
-
-//-----------------------------------------------------------
-// CreatePropScript( model ) - create a generic prop_script with default properties
-//------------------------------------------------------------
-entity function CreatePropScript( asset model, vector ornull origin = null, vector ornull angles = null, int solidType = 0, float fadeDist = -1 )
-{
- entity prop_script = CreateEntity( "prop_script" )
- prop_script.SetValueForModelKey( model )
- prop_script.kv.fadedist = fadeDist
- prop_script.kv.renderamt = 255
- prop_script.kv.rendercolor = "255 255 255"
- prop_script.kv.solid = solidType // 0 = no collision, 2 = bounding box, 6 = use vPhysics, 8 = hitboxes only
- if ( origin )
- {
- // hack: Setting origin twice. SetOrigin needs to happen before DispatchSpawn, otherwise the prop may not touch triggers
- prop_script.SetOrigin( expect vector( origin ) )
- if ( angles )
- prop_script.SetAngles( expect vector( angles ) )
- }
- DispatchSpawn( prop_script )
- if ( origin )
- {
- // hack: Setting origin twice. SetOrigin needs to happen after DispatchSpawn, otherwise origin is snapped to nearest whole unit
- prop_script.SetOrigin( expect vector( origin ) )
- if ( angles )
- prop_script.SetAngles( expect vector( angles ) )
- }
-
- return prop_script
-}
-
-
-
-//-----------------------------------------------------------
-// CreatePropPhysics( model ) - create a generic prop_physics with default properties
-//------------------------------------------------------------
-entity function CreatePropPhysics( asset model, vector origin, vector angles )
-{
- entity prop_physics = CreateEntity( "prop_physics" )
- prop_physics.SetValueForModelKey( model )
- prop_physics.kv.spawnflags = 0
- prop_physics.kv.fadedist = -1
- prop_physics.kv.physdamagescale = 0.1
- prop_physics.kv.inertiaScale = 1.0
- prop_physics.kv.renderamt = 255
- prop_physics.kv.rendercolor = "255 255 255"
- SetTeam( prop_physics, TEAM_BOTH ) // need to have a team other then 0 or it won't take impact damage
-
- prop_physics.SetOrigin( origin )
- prop_physics.SetAngles( angles )
- DispatchSpawn( prop_physics )
-
- return prop_physics
-}
-
-//-----------------------------------------------------------
-// SpawnBullseye() - creates a npc_bullseye and attaches it to an entity
-//------------------------------------------------------------
-entity function SpawnBullseye( int team, entity ent = null )
-{
- entity bullseye = CreateEntity( "npc_bullseye" )
- bullseye.SetScriptName( UniqueString( "bullseye" ) )
- bullseye.kv.rendercolor = "255 255 255"
- bullseye.kv.renderamt = 0
- bullseye.kv.health = 9999
- bullseye.kv.max_health = -1
- bullseye.kv.spawnflags = 516
- bullseye.kv.FieldOfView = 0.5
- bullseye.kv.FieldOfViewAlert = 0.2
- bullseye.kv.AccuracyMultiplier = 1.0
- bullseye.kv.physdamagescale = 1.0
- bullseye.kv.WeaponProficiency = eWeaponProficiency.VERYGOOD
- bullseye.kv.minangle = "360"
- DispatchSpawn( bullseye )
-
- SetTeam( bullseye, team )
-
- if ( ent )
- {
- vector bounds = ent.GetBoundingMaxs()
- bullseye.SetOrigin( ent.GetOrigin() + < 0, 0, bounds.z * 0.5 > )
- bullseye.SetParent( ent )
- }
-
- return bullseye
-}
-
-void function CenterPrint( ... )
-{
- string msg = ""
- for ( int i = 0; i < vargc; i++ )
- msg = ( msg + " " + string( vargv[ i ] ) )
-
- int words = expect int( vargc )
- if ( words < 1 )
- words = 1
-
- float delay = GraphCapped( float( words ), 2.0, 8.0, 2.1, 3.5 )
-
- entity ent = CreateGameText( msg, -1, 0.5, 10, "255 255 255", 0.25, 0.25, delay )
- EntFireByHandle( ent, "Display", "", 0, null, null )
-
- thread DestroyCenterPrint( ent, delay )
-}
-
-void function DestroyCenterPrint( entity ent, float delay )
-{
- wait( delay )
- ent.Destroy()
-}
-
-bool function IsValidPlayer( entity player )
-{
- if ( !IsValid( player ) )
- return false
-
- if ( !player.IsPlayer() )
- return false
-
- if ( IsDisconnected( player ) )
- return false
-
- return true
-}
-
-bool function IsDisconnected( entity player )
-{
- return player.p.isDisconnected
-}
-
-/****************************************************************************************************\
-/*
-|* PLAY FX
-\*
-\****************************************************************************************************/
-
-entity function PlayFX( asset effectName, vector org, vector ornull optionalAng = null, vector ornull overrideAngle = null )
-{
- return __CreateFxInternal( effectName, null, "", org, optionalAng, C_PLAYFX_SINGLE, null, -1, null, overrideAngle )
-}
-
-entity function PlayFXWithControlPoint( asset effectName, vector org, entity cpoint1, int visibilityFlagOverride = -1, entity visibilityFlagEntOverride = null, vector ornull overrideAngle = null, int _type = C_PLAYFX_SINGLE )
-{
- return __CreateFxInternal( effectName, null, "", org, null, _type, cpoint1, visibilityFlagOverride, visibilityFlagEntOverride, overrideAngle)
-}
-
-entity function PlayFXOnEntityWithControlPoint( asset effectName, entity ent, entity cpoint1, int visibilityFlagOverride = -1, entity visibilityFlagEntOverride = null, vector ornull overrideAngle = null, int _type = C_PLAYFX_SINGLE )
-{
- return __CreateFxInternal( effectName, ent, "", null, null, _type, cpoint1, visibilityFlagOverride, visibilityFlagEntOverride, overrideAngle)
-}
-
-entity function PlayFXOnEntity( asset effectName, entity ent, string optionalTag = "", vector ornull optionalTranslation = null, vector ornull optionalRotation = null, int visibilityFlagOverride = -1, entity visibilityFlagEntOverride = null, vector ornull overrideAngle = null )
-{
- return __CreateFxInternal( effectName, ent, optionalTag, optionalTranslation, optionalRotation, C_PLAYFX_SINGLE, null, visibilityFlagOverride, visibilityFlagEntOverride, overrideAngle )
-}
-
-entity function PlayFXForPlayer( asset effectName, entity player, vector ornull org, vector ornull optionalAng = null )
-{
- return __CreateFxInternal( effectName, null, "", org, optionalAng, C_PLAYFX_SINGLE, null, ENTITY_VISIBLE_TO_OWNER, player )
-}
-
-entity function PlayFXOnEntityForEveryoneExceptPlayer( asset effectName, entity ent, entity player, string optionalTag = "", vector ornull optionalTranslation = null, vector ornull optionalRotation = null )
-{
- return __CreateFxInternal( effectName, ent, optionalTag, optionalTranslation, optionalRotation, C_PLAYFX_SINGLE, null, (ENTITY_VISIBLE_TO_FRIENDLY | ENTITY_VISIBLE_TO_ENEMY), player )
-}
-
-entity function PlayFXForEveryoneExceptPlayer( asset effectName, entity player, vector ornull org, vector ornull optionalAng = null )
-{
- return __CreateFxInternal( effectName, null, "", org, optionalAng, C_PLAYFX_SINGLE, null, (ENTITY_VISIBLE_TO_FRIENDLY | ENTITY_VISIBLE_TO_ENEMY), player )
-}
-
-void function PlayFXOnTitanPlayerForTime( asset effectName, entity titan, string attachment, float duration )
-{
- titan.EndSignal( "OnDeath" )
- titan.EndSignal( "DisembarkingTitan" )
- titan.EndSignal( "TitanEjectionStarted" )
-
- entity fx = PlayFXOnEntityForEveryoneExceptPlayer( effectName, titan, titan, attachment )
-
- OnThreadEnd(
- function() : ( fx )
- {
- if ( IsValid(fx) )
- {
- fx.Destroy()
- }
- }
- )
-
- wait duration
-}
-
-entity function ClientStylePlayFXOnEntity( asset effectName, entity ent, string tag, float duration = 2.0 )
-{
- string name = ent.GetScriptName()
- ent.SetScriptName( UniqueString() ) // hack because you can only specify control points by name
- // hack this is also not quite right because we can't specify the attachment type on the server... should be trivial to add in code:
- // change DEFINE_FIELD( m_parentAttachmentType, FIELD_INTEGER ), to DEFINE_KEYFIELD( m_parentAttachmentType, FIELD_INTEGER, "attachmentType" ),
- entity result = __CreateFxInternal( effectName, ent, tag, null, null, C_PLAYFX_SINGLE, ent, (ENTITY_VISIBLE_TO_FRIENDLY | ENTITY_VISIBLE_TO_ENEMY), ent )
- EntFireByHandle( result, "Kill", "", duration, null, null )
- ent.SetScriptName( name )
-
- return result
-}
-
-entity function PlayLoopFX( asset effectName, vector ornull org, vector ornull optionalAng = null )
-{
- return __CreateFxInternal( effectName, null, "", org, optionalAng, C_PLAYFX_LOOP )
-}
-
-entity function PlayLoopFXOnEntity( asset effectName, entity ent, string optionalTag = "", vector ornull optionalTranslation = null, vector ornull optionalRotation = null, int visibilityFlagOverride = -1, entity visibilityFlagEntOverride = null )
-{
- return __CreateFxInternal( effectName, ent, optionalTag, optionalTranslation, optionalRotation, C_PLAYFX_LOOP, null, visibilityFlagOverride, visibilityFlagEntOverride )
-}
-
-entity function __CreateFxInternal( asset effectName, entity ent, string optionalTag = "", vector ornull optionalTranslation = <0,0,0>, vector ornull optionalRotation = <0,0,0>,
- int _type = C_PLAYFX_SINGLE, entity cpointEnt1 = null, int visibilityFlagOverride = -1, entity visibilityFlagEntOverride = null, vector ornull overrideAngle = null )
-{
- entity fx = CreateEntity( "info_particle_system" )
- fx.SetValueForEffectNameKey( effectName )
- if( visibilityFlagOverride != -1 )
- fx.kv.VisibilityFlags = visibilityFlagOverride
- else
- fx.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE
- fx.kv.start_active = 1
- fx.e.fxType = _type
-
- if ( _type == C_PLAYFX_SINGLE )
- fx.DoNotCreateFXOnRestore();
-
- vector coreOrg
- vector coreAng
-
- //are we attaching to an ent?
- if ( ent )
- {
- //are we attaching to a tag on an ent
- if ( optionalTag != "" )
- {
- int attachID = ent.LookupAttachment( optionalTag )
- coreOrg = ent.GetAttachmentOrigin( attachID )
- coreAng = ent.GetAttachmentAngles( attachID )
- }
- else
- {
- coreOrg = ent.GetOrigin()
- coreAng = ent.GetAngles()
- }
-
- fx.Code_SetTeam( ent.GetTeam() );
- }
- else //if not we're just playing in space
- {
- optionalTag = ""
- coreOrg = < 0, 0, 0 >
- coreAng = < 0, 0, 0 >
- }
-
- if ( optionalTranslation )
- {
- expect vector( optionalTranslation )
- if ( ent )
- coreOrg = PositionOffsetFromEnt( ent, optionalTranslation.x, optionalTranslation.y, optionalTranslation.z )
- else
- coreOrg = coreOrg + optionalTranslation
- }
-
- coreOrg = ClampToWorldspace( coreOrg )
- fx.SetOrigin( coreOrg )
-
- if ( overrideAngle )
- {
- expect vector( overrideAngle )
- fx.SetAngles( overrideAngle )
- }
- else if ( optionalRotation )
- {
- expect vector( optionalRotation )
- fx.SetAngles( coreAng + optionalRotation )
- }
- else
- {
- fx.SetAngles( coreAng )
- }
-
- if ( ent )
- {
- if ( !ent.IsMarkedForDeletion() ) // TODO: This is a hack for shipping. The real solution is to spawn the FX before deleting the parent entity.
- {
- fx.SetParent( ent, optionalTag, true )
- }
- }
-
- if ( visibilityFlagEntOverride != null )
- fx.SetOwner( visibilityFlagEntOverride )
-
- if ( cpointEnt1 )
- fx.kv.cpoint1 = cpointEnt1.GetTargetName()
-
- DispatchSpawn( fx )
- thread __DeleteFxInternal( fx )
-
- //SetTargetName( fx, "FX_" + effectName )
- return fx
-}
-
-void function __DeleteFxInternal( entity fx )
-{
- //if it loops or is multiple then don't delete internally
- if ( fx.e.fxType == C_PLAYFX_MULTIPLE )
- return
-
- if ( fx.e.fxType == C_PLAYFX_LOOP )
- return
-
- wait 30 //no way to know when an effect is over
- if ( !IsValid( fx ) )
- return
-
- fx.ClearParent()
- fx.Destroy()
-}
-
-void function StartFX( entity fx )
-{
- Assert( fx.e.fxType == C_PLAYFX_LOOP, "Tried to use StartFX() on effect that is not LOOPING" )
- EntFireByHandle( fx, "Start", "", 0, null, null )
-}
-
-void function StopFX( entity fx )
-{
- Assert( fx.e.fxType == C_PLAYFX_LOOP, "Tried to use StopFX() on effect that is not LOOPING" )
- EntFireByHandle( fx, "Stop", "", 0, null, null )
-}
-
-void function ReplayFX( entity fx )
-{
- Assert( fx.e.fxType == C_PLAYFX_MULTIPLE, "Tried to use ReplayFX() on effect that is not MULTIPLE" )
- //thread it because there is a WaitFrame() inside the function
- thread __ReplayFXInternal( fx )
-}
-
-void function __ReplayFXInternal( entity fx )
-{
- //for non-looping fx, we must stop first before we can fire again
- EntFireByHandle( fx, "Stop", "", 0, null, null )
- //we can't start in the same frame, WaitFrame() skips 1 false
- //it should be noted that "WaitFrame()" doesn't work with a timescale above 1
- WaitFrame()
- //may have died since the last frame
- if ( IsValid( fx ) )
- EntFireByHandle( fx, "Start", "", 0, null, null )
-}
-
-void function Entity_StopFXArray( entity ent )
-{
- foreach( fx in ent.e.fxArray )
- {
- if ( IsValid( fx ) )
- {
- StopFX( fx )
- fx.Destroy()
- }
- }
-}
-
-/****************************************************************************************************\
-|* end play fx
-\****************************************************************************************************/
-
-
-table function GetDamageTableFromInfo( var damageInfo )
-{
- table Table = {}
- Table.damageSourceId <- DamageInfo_GetDamageSourceIdentifier( damageInfo )
- Table.origin <- DamageInfo_GetDamagePosition( damageInfo )
- Table.force <- DamageInfo_GetDamageForce( damageInfo )
- Table.scriptType <- DamageInfo_GetCustomDamageType( damageInfo )
-
- return Table
-}
-
-bool function EntityInSolid( entity ent, entity ignoreEnt = null, int buffer = 0 ) //TODO: This function returns true for a player standing inside a friendly grunt. It also returns true if you are right up against a ceiling.Needs fixing for next game
-{
- Assert( IsValid( ent ) )
- int solidMask
- vector mins
- vector maxs
- int collisionGroup
- array<entity> ignoreEnts = []
-
- ignoreEnts.append( ent )
-
- if ( IsValid( ignoreEnt ) )
- {
- ignoreEnts.append( ignoreEnt )
- }
-
- if ( ent.IsTitan() )
- solidMask = TRACE_MASK_TITANSOLID
- else if ( ent.IsPlayer() )
- solidMask = TRACE_MASK_PLAYERSOLID
- else
- solidMask = TRACE_MASK_NPCSOLID
-
- if ( ent.IsPlayer() )
- {
- mins = ent.GetPlayerMins()
- maxs = ent.GetPlayerMaxs()
- collisionGroup = TRACE_COLLISION_GROUP_PLAYER
- }
- else
- {
- Assert( ent.IsNPC() )
- mins = ent.GetBoundingMins()
- maxs = ent.GetBoundingMaxs()
- collisionGroup = TRACE_COLLISION_GROUP_NONE
- }
-
- if ( buffer > 0 )
- {
- mins.x -= float( buffer )
- mins.y -= float( buffer )
- maxs.x += float( buffer )
- maxs.y += float( buffer )
- }
-
- // if we got into solid, teleport back to safe place
- vector currentOrigin = ent.GetOrigin()
- TraceResults result = TraceHull( currentOrigin, currentOrigin + < 0, 0, 1 >, mins, maxs, ignoreEnts, solidMask, collisionGroup )
- //PrintTable( result )
- //DrawArrow( result.endPos, Vector(0,0,0), 5, 150 )
- if ( result.startSolid )
- return true
-
- return result.fraction < 1.0 // TODO: Probably not needed according to Jiesang. Fix after ship.
-}
-
-bool function EntityInSpecifiedEnt( entity ent, entity specifiedEnt, int buffer = 0 )
-{
- Assert( IsValid( ent ) )
- Assert( IsValid( specifiedEnt ) )
-
- int solidMask
- vector mins
- vector maxs
- int collisionGroup
-
- if ( ent.IsTitan() )
- solidMask = TRACE_MASK_TITANSOLID
- else if ( ent.IsPlayer() )
- solidMask = TRACE_MASK_PLAYERSOLID
- else
- solidMask = TRACE_MASK_NPCSOLID
-
- if ( ent.IsPlayer() )
- {
- mins = ent.GetPlayerMins()
- maxs = ent.GetPlayerMaxs()
- collisionGroup = TRACE_COLLISION_GROUP_PLAYER
- }
- else
- {
- Assert( ent.IsNPC() )
- mins = ent.GetBoundingMins()
- maxs = ent.GetBoundingMaxs()
- collisionGroup = TRACE_COLLISION_GROUP_NONE
- }
-
- if ( buffer > 0 )
- {
- mins.x -= float( buffer )
- mins.y -= float( buffer )
- maxs.x += float( buffer )
- maxs.y += float( buffer )
- }
-
- // if we got into solid, teleport back to safe place
- vector currentOrigin = ent.GetOrigin()
- TraceResults result = TraceHull( currentOrigin, currentOrigin + < 0, 0, 1 >, mins, maxs, null, solidMask, collisionGroup )
- //PrintTable( result )
- //DrawArrow( result.endPos, Vector(0,0,0), 5, 150 )
- if ( result.startSolid == false )
- return false
-
- return result.hitEnt == specifiedEnt
-}
-
-void function KillFromInfo( entity ent, var damageInfo )
-{
- entity attacker = DamageInfo_GetAttacker( damageInfo )
- entity weapon = DamageInfo_GetWeapon( damageInfo )
- //float amount = DamageInfo_GetDamage( damageInfo )
-
- // JFS: if the player became invalid, the attacker becomes the projectile which is bad
- if ( attacker.IsProjectile() )
- attacker = svGlobal.worldspawn
-
- if ( !weapon )
- weapon = attacker
-
- table Table = GetDamageTableFromInfo( damageInfo )
- Table.forceKill <- true
-
- ent.TakeDamage( 9999, attacker, weapon, Table )
-}
-
-
-entity function GetPlayerTitanInMap( entity player )
-{
- // temporarily flipped
- entity petTitan = player.GetPetTitan()
- if ( IsValid( petTitan ) && IsAlive( petTitan ) )
- return petTitan
-
- // first try to return the player's actual titan
- if ( player.IsTitan() )
- return player
-
- return null
-}
-
-
-entity function GetPlayerTitanFromSouls( entity player )
-{
- // returns the first owned titan found
- array<entity> souls = GetTitanSoulArray()
- foreach ( soul in souls )
- {
- if ( !IsValid( soul ) )
- continue
-
- if ( soul.GetBossPlayer() != player )
- continue
-
- if ( !IsAlive( soul.GetTitan() ) )
- continue
-
- return soul.GetTitan()
- }
-
- return null
-}
-
-void function DisableTitanShield( entity titan )
-{
- entity soul = titan.GetTitanSoul()
-
- soul.SetShieldHealth( 0 )
- soul.SetShieldHealthMax( 0 )
-}
-
-void function DisableShield( entity ent )
-{
- entity soul = ent.GetTitanSoul()
-
- if ( soul )
- {
- DisableTitanShield( ent )
- return
- }
-
- ent.SetShieldHealth( 0 )
- ent.SetShieldHealthMax( 0 )
-}
-
-void function SetVelocityTowardsEntity( entity entToMove, entity targetEnt, float speed )
-{
- Assert( speed > 0 )
- Assert( IsValid( entToMove ) )
- Assert( IsValid( targetEnt ) )
-
- vector direction = ( targetEnt.GetWorldSpaceCenter() - entToMove.GetOrigin() )
- direction = Normalize( direction ) * speed
- entToMove.SetVelocity( direction )
-}
-
-void function SetVelocityTowardsEntityTag( entity entToMove, entity targetEnt, string targetTag, float speed )
-{
- Assert( speed > 0 )
- Assert( IsValid( entToMove ) )
- Assert( IsValid( targetEnt ) )
-
- int attachID = targetEnt.LookupAttachment( targetTag )
- vector attachOrigin = targetEnt.GetAttachmentOrigin( attachID )
-
- vector direction = ( attachOrigin - entToMove.GetOrigin() )
- direction = Normalize( direction ) * speed
- entToMove.SetVelocity( direction )
-}
-
-void function EntityDemigod_TryAdjustDamageInfo( entity ent, var damageInfo )
-{
- float dmg = DamageInfo_GetDamage( damageInfo )
- if ( dmg <= 0 )
- return
-
- if ( ent.IsTitan() && !GetDoomedState( ent ) ) //Allow demigod titans to go into doomed
- return
-
- int bottomLimit = 5
- if ( ent.GetHealth() <= bottomLimit )
- ent.SetHealth( bottomLimit + 1 ) //Set it up so that you at least take 1 damage, for hit indicators etc to trigger
-
- int health = ent.GetHealth()
-
- if ( health - dmg <= bottomLimit )
- {
- int newdmg = health - bottomLimit
- DamageInfo_SetDamage( damageInfo, newdmg )
- //printt( "setting damage to ", newdmg )
- }
-}
-
-void function DebugDamageInfo( entity ent, var damageInfo )
-{
- printt( "damage to " + ent + ": " + DamageInfo_GetDamage( damageInfo ) )
- int damageType = DamageInfo_GetCustomDamageType( damageInfo )
- printt( "explosive: " + ( damageType & DF_EXPLOSION ) )
- printt( "bullet: " + ( damageType & DF_BULLET ) )
- printt( "gib: " + ( damageType & DF_GIB ) )
-
- vector dampos = DamageInfo_GetDamagePosition( damageInfo )
- vector org = DamageInfo_GetInflictor( damageInfo ).GetOrigin()
- DebugDrawLine( dampos, org, 255, 0, 0, true, 10.0 )
- DebugDrawLine( org, ent.GetOrigin(), 255, 255, 0, true, 10.0 )
-}
-
-vector function RandomVecInDome( vector dir )
-{
- vector angles = VectorToAngles( dir )
- vector forward = AnglesToForward( angles )
- vector right = AnglesToRight( angles )
- vector up = AnglesToUp( angles )
-
- float offsetRight = RandomFloatRange( -1, 1 )
- float offsetUp = RandomFloatRange( -1, 1 )
- float offsetForward = RandomFloat( 1.0 )
-
- vector endPos = < 0, 0, 0 >
- endPos += forward * offsetForward
- endPos += up * offsetUp
- endPos += right * offsetRight
- endPos.Norm()
-
- return endPos
-}
-
-float function GetAnimEventTime( asset modelname, string anim, string event )
-{
- entity dummy = CreatePropDynamic( modelname )
- dummy.Hide()
-
- float duration = dummy.GetSequenceDuration( anim )
- float frac = dummy.GetScriptedAnimEventCycleFrac( anim, event )
-
- dummy.Destroy()
-
- //this might cause some issues in R2 - but we'll fix them as we go - it's important this doesn't silently fail
- Assert( frac > 0.0, "event: " + event + " doesn't exist in animation: " + anim )
- Assert( frac < 1.0, "event: " + event + " doesn't exist in animation: " + anim )
-
- return duration * frac
-}
-
-void function SetDeathFuncName( entity npc, string functionNameString )
-{
- Assert( npc.kv.deathScriptFuncName == "", "deathScriptFuncName was already set" )
- npc.kv.deathScriptFuncName = functionNameString
-}
-
-void function ClearDeathFuncName( entity npc )
-{
- npc.kv.deathScriptFuncName = ""
-}
-
-/*function PushSunLightAngles( x, y, z )
-{
- entity clight = GetEnt( "env_cascade_light" )
- Assert( clight )
-
- clight.PushAngles( x, y, z )
-}
-
-function PopSunLightAngles()
-{
- entity clight = GetEnt( "env_cascade_light" )
- Assert( clight )
-
- clight.PopAngles()
-}*/
-
-entity function GetPilotAntiPersonnelWeapon( entity player )
-{
- array<entity> weaponsArray = player.GetMainWeapons()
- foreach( weapon in weaponsArray )
- {
- int weaponType = weapon.GetWeaponType()
- if ( weaponType == WT_SIDEARM || weaponType == WT_ANTITITAN )
- continue;
-
- return weapon
- }
-
- return null
-}
-
-entity function GetPilotSideArmWeapon( entity player )
-{
- array<entity> weaponsArray = player.GetMainWeapons()
- foreach( weapon in weaponsArray )
- {
- if ( weapon.GetWeaponType() == WT_SIDEARM )
- return weapon
- }
-
- return null
-}
-
-entity function GetPilotAntiTitanWeapon( entity player )
-{
- array<entity> weaponsArray = player.GetMainWeapons()
- foreach( weapon in weaponsArray )
- {
- if ( weapon.GetWeaponType() == WT_ANTITITAN )
- return weapon
- }
-
- return null
-}
-
-bool function PilotHasSniperWeapon( entity player )
-{
- array<entity> weaponsArray = player.GetMainWeapons()
- foreach ( weapon in weaponsArray )
- {
- if ( IsValid( weapon ) && weapon.GetWeaponInfoFileKeyField( "is_sniper" ) == 1 )
- return true
- }
-
- return false
-}
-
-bool function PilotActiveWeaponIsSniper( entity player )
-{
- entity weapon = player.GetActiveWeapon()
-
- if ( IsValid( weapon ) && weapon.GetWeaponInfoFileKeyField( "is_sniper" ) == 1 )
- return true
-
- return false
-}
-
-void function ScreenFadeToColor( entity player, float r, float g, float b, float a, float fadeTime = 1.7, float holdTime = 0.0 )
-{
- Assert( IsValid( player ) )
-
- ScreenFade( player, r, g, b, a, fadeTime, holdTime, FFADE_OUT | FFADE_PURGE )
-}
-
-
-void function ScreenFadeFromColor( entity player, float r, float g, float b, float a, float fadeTime = 2.0, float holdTime = 2.0 )
-{
- Assert( IsValid( player ) )
-
- ScreenFade( player, r, g, b, a, fadeTime, holdTime, FFADE_IN | FFADE_PURGE )
-}
-
-void function ScreenFadeToBlack( entity player, float fadeTime, float holdTime )
-{
- Assert( IsValid( player ) )
-
- ScreenFade( player, 0, 0, 1, 255, fadeTime, holdTime, FFADE_OUT | FFADE_PURGE )
-}
-
-void function ScreenFadeFromBlack( entity player, float fadeTime = 2.0, float holdTime = 2.0 )
-{
- Assert( IsValid( player ) )
-
- ScreenFade( player, 0, 1, 0, 255, fadeTime, holdTime, FFADE_IN | FFADE_PURGE )
-}
-
-void function ScreenFadeToBlackForever( entity player, float fadeTime = 1.7 )
-{
- Assert( IsValid( player ) )
-
- ScreenFade( player, 0, 0, 1, 255, fadeTime, 0, FFADE_OUT | FFADE_STAYOUT )
-}
-
-/*******************************************************
-/ Server Effects
-/
-/ CreateServerEffect_Friendly( effectName, team )
-/ CreateServerEffect_Enemy( effectName, team )
-/ CreateServerEffect_Owner( effectName, owner )
-/ SetServerEffectControlPoint( effectEnt, controlPoint, vecValue )
-/ StartServerEffect( effectEnt )
-/ StartServerEffectInWorld( effectEnt, origin, angles )
-/ StartServerEffectOnEntity( effectEnt, ent, tag = null )
-/
-*******************************************************/
-
-// NOTE: this does not play the effect, use StartEffectOnEntity
-entity function CreateServerEffect_Friendly( asset effectName, int team )
-{
- entity friendlyEffect = _CreateServerEffect( effectName, 2 ) // ENTITY_VISIBLE_TO_FRIENDLY
- friendlyEffect.kv.TeamNum = team
- friendlyEffect.kv.teamnumber = team
-
- return friendlyEffect
-}
-
-// NOTE: this does not play the effect, use StartEffectOnEntity
-entity function CreateServerEffect_Enemy( asset effectName, int team )
-{
- entity enemyEffect = _CreateServerEffect( effectName, 4 ) // ENTITY_VISIBLE_TO_ENEMY
- enemyEffect.kv.TeamNum = team
- enemyEffect.kv.teamnumber = team
-
- return enemyEffect
-}
-
-// NOTE: this does not play the effect, use StartEffectOnEntity
-entity function CreateServerEffect_Owner( asset effectName, entity owner )
-{
- Assert( IsValid( owner ) )
-
- entity ownerEffect = _CreateServerEffect( effectName, 1 ) // ENTITY_VISIBLE_TO_OWNER
- ownerEffect.kv.TeamNum = owner.GetTeam()
- ownerEffect.SetOwner( owner )
-
- return ownerEffect
-}
-
-entity function _CreateServerEffect( asset effectName, int visFlags )
-{
- entity serverEffect = CreateEntity( "info_particle_system" )
- serverEffect.SetOrigin( <0, 0, 0> )
- serverEffect.SetAngles( <0, 0, 0> )
- serverEffect.SetValueForEffectNameKey( effectName )
- serverEffect.kv.start_active = 1
- serverEffect.kv.VisibilityFlags = visFlags
-
- thread _ServerEffectCleanup( serverEffect )
- return serverEffect
-}
-
-entity function SetServerEffectControlPoint( entity effectEnt, int controlPoint, vector vecValue ) // for now, only support static
-{
- entity helper = CreateEntity( "info_placement_helper" )
- helper.SetOrigin( vecValue )
- effectEnt.SetControlPointEnt( controlPoint, helper )
- effectEnt.e.fxControlPoints.append( helper )
-
- return helper
-}
-
-void function StartServerEffect( entity effectEnt )
-{
- DispatchSpawn( effectEnt )
-}
-
-void function StartServerEffectInWorld( entity effectEnt, vector origin, vector angles )
-{
- effectEnt.SetOrigin( origin )
- effectEnt.SetAngles( angles )
- DispatchSpawn( effectEnt )
-}
-
-void function StartServerEffectOnEntity( entity effectEnt, entity ent, string tag = "" )
-{
- Assert( IsValid( effectEnt ) )
- Assert( IsValid( ent ) )
-
- if ( tag != "" )
- {
- int attachID = ent.LookupAttachment( tag )
- vector origin = ent.GetAttachmentOrigin( attachID )
- vector angles = ent.GetAttachmentAngles( attachID )
-
- origin = ClampToWorldspace( origin )
- effectEnt.SetOrigin( origin )
- effectEnt.SetAngles( angles )
- effectEnt.SetParent( ent, tag, true )
- }
- else
- {
- effectEnt.SetParent( ent )
- }
-
- DispatchSpawn( effectEnt )
-}
-
-void function _ServerEffectCleanup( entity effectEnt )
-{
- effectEnt.WaitSignal( "OnDestroy" )
-
- foreach ( entity controlPoint in effectEnt.e.fxControlPoints )
- {
- controlPoint.Destroy()
- }
-}
-
-float function GetYaw( vector org1, vector org2 )
-{
- vector vec = org2 - org1
- vector angles = VectorToAngles( vec )
- return angles.y
-}
-
-void function HideName( entity ent )
-{
- ent.SetNameVisibleToFriendly( false )
- ent.SetNameVisibleToEnemy( false )
- ent.SetNameVisibleToNeutral( false )
- ent.SetNameVisibleToOwner( false )
-}
-
-void function ShowName( entity ent )
-{
- ent.SetNameVisibleToFriendly( true )
- ent.SetNameVisibleToEnemy( true )
- ent.SetNameVisibleToNeutral( true )
- ent.SetNameVisibleToOwner( true )
-}
-
-void function ShowNameToAllExceptOwner( entity ent )
-{
- ent.SetNameVisibleToFriendly( true )
- ent.SetNameVisibleToEnemy( true )
- ent.SetNameVisibleToNeutral( true )
- ent.SetNameVisibleToOwner( false )
-}
-
-void function EmitSoundOnEntityToTeamExceptPlayer( entity ent, string sound, int team, entity excludePlayer )
-{
- array<entity> players = GetPlayerArrayOfTeam( team )
-
- foreach ( player in players )
- {
- if ( player == excludePlayer )
- continue
-
- EmitSoundOnEntityOnlyToPlayer( ent, player, sound )
- }
-}
-
-#if DEV
-// DEV function to toggle player view between the skybox and the real world.
-void function ToggleSkyboxView( float scale = 0.001 )
-{
- entity player = GetEntByIndex( 1 )
-
- entity skyboxCamLevel = GetEnt( "skybox_cam_level" )
-
- Assert( IsValid( skyboxCamLevel ), "Could not find a sky_camera entity named \"skybox_cam_level\" in this map." )
-
- vector skyOrigin = skyboxCamLevel.GetOrigin()
-
- if ( !file.isSkyboxView )
- {
- if ( !player.IsNoclipping() )
- {
- ClientCommand( player, "noclip" )
- wait( 0.25 )
- }
-
- ClientCommand( player, "sv_noclipspeed 0.1" )
- file.isSkyboxView = true
- vector offset = player.GetOrigin()
- offset *= scale
-
- player.SetOrigin( skyOrigin + offset - < 0.0, 0.0, 60.0 - (60.0 * scale) > )
- }
- else
- {
- ClientCommand( player, "sv_noclipspeed 5" )
- file.isSkyboxView = false
- vector offset = player.GetOrigin() - skyOrigin + < 0.0, 0.0, 60.0 - (60.0 * scale) >
- offset *= 1.0 / scale
-
- offset = ClampToWorldspace( offset )
-
- player.SetOrigin( offset )
- }
-}
-
-void function DamageRange( float value, float headShotMultiplier, int playerHealth = 200 )
-{
- printt( "Damage Range: ", value, headShotMultiplier )
-
- float bodyShot = value
- float headShot = value * headShotMultiplier
-
- int maxHeadshots = 0
-
- int simHealth = playerHealth
- while ( simHealth > 0 )
- {
- simHealth = (simHealth.tofloat() - headShot).tointeger()
- maxHeadshots++
- }
-
- printt( "HeadShots: BodyShots: Total:" )
-
- simHealth = playerHealth
- int numHeadshots = 0
- while ( numHeadshots < maxHeadshots )
- {
- simHealth = playerHealth
- for ( int hsIdx = 0; hsIdx < numHeadshots; hsIdx++ )
- {
- simHealth = (simHealth.tofloat() - headShot).tointeger()
- }
-
- int numBodyShots = 0
- while ( simHealth > 0 )
- {
- simHealth = (simHealth.tofloat() - bodyShot).tointeger()
- numBodyShots++
- }
- printt( format( "%i %i %i", numHeadshots, numBodyShots, numHeadshots + numBodyShots ) )
- numHeadshots++
- }
-
- printt( format( "%i %i %i", numHeadshots, 0, numHeadshots ) )
-}
-
-#endif // DEV
-
-void function MuteAll( entity player, int fadeOutTime = 2 )
-{
- //DumpStack(2)
- Assert( player.IsPlayer() )
-
- Assert( fadeOutTime >= 1 && fadeOutTime <= 4 , "Only have 4 kinds of fadeout to play, time must be in the range [1,4]" )
-
- string fadeoutSoundString
-
- switch( fadeOutTime )
- {
- case 1:
- fadeoutSoundString = "1_second_fadeout"
- break
-
- case 2:
- fadeoutSoundString = "2_second_fadeout"
- break
-
- case 3:
- fadeoutSoundString = "3_second_fadeout"
- break
-
- case 4:
- fadeoutSoundString = "4_second_fadeout"
- break
-
- default:
- unreachable
-
- }
-
- printt( "Apply " + fadeoutSoundString + " to player: " + player )
-
- EmitSoundOnEntityOnlyToPlayer( player, player, fadeoutSoundString )
-}
-
-//Mutes all except halftime sounds and dialogue
-void function MuteHalfTime( entity player )
-{
- Assert( player.IsPlayer() )
- printt( "Apply HalfTime_fadeout to player: " + player )
- EmitSoundOnEntityOnlyToPlayer( player, player, "HalfTime_fadeout" )
-}
-
-void function UnMuteAll( entity player )
-{
- //DumpStack(2)
- Assert( player.IsPlayer() )
-
- //Just stop all the possible fadeout sounds.
- printt( "Stopping all fadeout for player: " + player )
- StopSoundOnEntity( player, "1_second_fadeout" )
- StopSoundOnEntity( player, "2_second_fadeout" )
- StopSoundOnEntity( player, "3_second_fadeout" )
- StopSoundOnEntity( player, "4_second_fadeout" )
- StopSoundOnEntity( player, "HalfTime_fadeout" )
-}
-
-void function AllPlayersMuteAll( int time = MUTEALLFADEIN )
-{
- array<entity> players = GetPlayerArray()
-
- foreach ( player in players )
- MuteAll( player, time )
-}
-
-void function AllPlayersUnMuteAll()
-{
- array<entity> players = GetPlayerArray()
-
- foreach ( player in players )
- UnMuteAll( player )
-}
-
-void function TakeAmmoFromPlayer( entity player )
-{
- array<entity> mainWeapons = player.GetMainWeapons()
- array<entity> offhandWeapons = player.GetOffhandWeapons()
-
- foreach ( weapon in mainWeapons )
- {
- weapon.SetWeaponPrimaryAmmoCount( 0 )
-
- if ( weapon.GetWeaponPrimaryClipCountMax() > 0 )
- weapon.SetWeaponPrimaryClipCount( 0 )
- }
-
- foreach ( weapon in offhandWeapons )
- {
- weapon.SetWeaponPrimaryAmmoCount( 0 )
-
- if ( weapon.GetWeaponPrimaryClipCountMax() > 0 )
- weapon.SetWeaponPrimaryClipCount( 0 )
- }
-}
-
-
-bool function NearFlagSpawnPoint( vector dropPoint )
-{
- if ( "flagSpawnPoint" in level && IsValid( level.flagSpawnPoint ) )
- {
- vector fspOrigin = expect entity( level.flagSpawnPoint ).GetOrigin()
- if ( Distance( fspOrigin, dropPoint ) < SAFE_TITANFALL_DISTANCE_CTF )
- return true
- }
-
- if ( "flagReturnPoint" in level && IsValid( level.flagReturnPoint ) )
- {
- vector fspOrigin = expect entity( level.flagReturnPoint ).GetOrigin()
- if ( Distance( fspOrigin, dropPoint ) < SAFE_TITANFALL_DISTANCE_CTF )
- return true
- }
-
- if ( "flagSpawnPoints" in level )
- {
- foreach ( flagSpawnPoint in svGlobal.flagSpawnPoints )
- {
- vector fspOrigin = flagSpawnPoint.GetOrigin()
- if ( Distance( fspOrigin, dropPoint ) < SAFE_TITANFALL_DISTANCE_CTF )
- return true
- }
- }
-
- return false
-}
-
-bool function HasCinematicFlag( entity player, int flag )
-{
- Assert( player.IsPlayer() )
- Assert( IsValid( player ) )
- return ( player.GetCinematicEventFlags() & flag ) != 0
-}
-
-void function AddCinematicFlag( entity player, int flag )
-{
- Assert( player.IsPlayer() )
- Assert( IsValid( player ) )
- player.SetCinematicEventFlags( player.GetCinematicEventFlags() | flag )
- player.Signal( "CE_FLAGS_CHANGED" )
-}
-
-void function RemoveCinematicFlag( entity player, int flag )
-{
- Assert( player.IsPlayer() )
- Assert( IsValid( player ) )
- player.SetCinematicEventFlags( player.GetCinematicEventFlags() & ( ~flag ) )
- player.Signal( "CE_FLAGS_CHANGED" )
-}
-
-void function SkyScaleDefault( entity ent, float time = 1.0 )
-{
- if ( IsValid( ent ) )
- ent.LerpSkyScale( SKYSCALE_DEFAULT, time )
-}
-
-void function MoveSpawn( string targetName, vector origin, vector angles )
-{
- entity ent = GetEnt( targetName )
- ent.SetOrigin( origin )
- ent.SetAngles( angles )
-}
-
-/*
-function CheckDailyChallengeAchievement( entity player )
-{
- if ( player.GetPersistentVar( "cu8achievement.ach_allDailyChallengesForDay" ) == true )
- return
-
- int maxRefs = PersistenceGetArrayCount( "activeDailyChallenges" )
- int todaysDailiesComplete = 0
- int today = Daily_GetDayForCurrentTime()
- for ( int i = 0; i < maxRefs; i++ )
- {
- int day = player.GetPersistentVarAsInt( "activeDailyChallenges[" + i + "].day" )
- if ( day != today )
- continue
-
- local ref = player.GetPersistentVar( "activeDailyChallenges[" + i + "].ref" )
- if ( !IsChallengeComplete( ref, player ) )
- continue
-
- todaysDailiesComplete++
- }
-
- if ( todaysDailiesComplete >= 3 )
- player.SetPersistentVar( "cu8achievement.ach_allDailyChallengesForDay", true )
-}
-*/
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// Get an array of all linked entities targeted to one after the other down the chain
-array<entity> function GetEntityTargetChain_Deprecated( entity ent )
-{
- array<entity> entityChain = []
- entity currentEnt = ent
- entity nextEnt
-
- while ( true )
- {
- nextEnt = GetEnt( currentEnt.GetTarget_Deprecated() )
- if ( IsValid( nextEnt ) )
- entityChain.append( nextEnt )
- else
- return entityChain
- currentEnt = nextEnt
- }
-
- unreachable
-}
-
-void function PlayImpactFXTable( vector origin, entity owner, string impactFX, int flags = 0 )
-{
- Explosion(
- origin, //center,
- owner, //attacker,
- owner, //inflictor,flags
- 0, //damage,
- 0, //damageHeavyArmor,
- 1, //innerRadius,
- 1, //outerRadius,
- flags, //flags,
- origin, //projectileLaunchOrigin,
- 0, //explosionForce,
- damageTypes.explosive, //scriptDamageFlags,
- -1, //scriptDamageSourceIdentifier,
- impactFX ) //impactEffectTableName
-}
-
-void function SetSignalDelayed( entity ent, string signal, float delay )
-{
- thread __SetSignalDelayedThread( ent, signal, delay )
-}
-
-void function __SetSignalDelayedThread( entity ent, string signal, float delay )
-{
- EndSignal( ent, signal ) // so that if we call this again with the same signal on the same ent we won't get multiple signal events.
-
- wait delay
- if ( IsValid( ent ) )
- Signal( ent, signal )
-}
-
-#if DEV
-table function GetPlayerPos( entity player = null )
-{
- if ( !player )
- player = gp()[0]
-
- vector org = player.GetOrigin()
- vector vec = player.GetViewVector()
- vector ang = VectorToAngles( vec )
-
- return { origin = org, angles = ang }
-}
-
-string function GetScriptPos( entity player = null )
-{
- table playerPos = GetPlayerPos( player )
- vector origin = expect vector( playerPos.origin )
- vector angles = expect vector( playerPos.angles )
-
- string returnStr = CreateOriginAnglesString( origin, <0, angles.y, 0> )
- return returnStr
-}
-
-string function CreateOriginAnglesString( vector origin, vector angles )
-{
- string returnStr = "< " + origin.x + ", " + origin.y + ", " + origin.z + " >, < " + angles.x + ", " + angles.y + ", " + angles.z + " >"
- return returnStr
-}
-
-void function DistCheck_SetTestPoint()
-{
- svGlobal.distCheckTestPoint = expect vector( GetPlayerPos().origin )
- printt( "DistCheck test point set to:", svGlobal.distCheckTestPoint )
-}
-
-void function DistCheck()
-{
- vector here = expect vector( GetPlayerPos().origin )
- float dist = Distance( here, svGlobal.distCheckTestPoint )
- printt( "Distance:", dist, "units from", svGlobal.distCheckTestPoint )
-}
-#endif // DEV
-
-void function ClearChildren( entity parentEnt ) //Probably should have code give us a GetChildren() function that returns a list instead of having to iterate through NextMovePeer
-{
- entity childEnt = parentEnt.FirstMoveChild()
- entity nextChildEnt
-
- while ( childEnt != null )
- {
- nextChildEnt = childEnt.NextMovePeer()
- childEnt.ClearParent()
-
- childEnt = nextChildEnt
- }
-}
-
-void function ForceTimeLimitDone()
-{
- level.devForcedWin = true
- level.devForcedTimeLimit = true
- svGlobal.levelEnt.Signal( "devForcedWin" )
- ServerCommand( "mp_enabletimelimit 1" )
- ServerCommand( "mp_enablematchending 1" )
-}
-
-
-void function UpdateBadRepPresent()
-{
- array<entity> players = GetPlayerArray()
- bool found = false
-/* always set to false for now
- foreach ( player in players )
- {
- if ( player.HasBadReputation() )
- {
- found = true
- break
- }
- }
-*/
- level.nv.badRepPresent = found
- level.ui.badRepPresent = found
-}
-
-void function Dev_PrintMessage( entity player, string text, string subText = "", float duration = 7.0, string soundAlias = "" )
-{
- #if DEV
- // Build the message on the client
- string sendMessage
- for ( int textType = 0 ; textType < 2 ; textType++ )
- {
- sendMessage = textType == 0 ? text : subText
-
- for ( int i = 0; i < sendMessage.len(); i++ )
- {
- Remote_CallFunction_NonReplay( player, "Dev_BuildClientMessage", textType, sendMessage[i] )
- }
- }
- Remote_CallFunction_NonReplay( player, "Dev_PrintClientMessage", duration )
- if ( soundAlias != "" )
- EmitSoundOnEntity( player, soundAlias )
- #endif
-}
-
-bool function IsAttackDefendBased() //If needed to, we can make this a .nv and then move this function into utility_shared
-{
- return expect bool( level.attackDefendBased )
-}
-
-bool function IsRoundBasedUsingTeamScore() //If needed to, we can make this a .nv and then move this function into utility_shared
-{
- return IsRoundBased() && expect bool( level.roundBasedUsingTeamScore )
-}
-
-bool function ShouldResetRoundBasedTeamScore()
-{
- return IsRoundBased() && svGlobal.roundBasedTeamScore_RoundReset
-}
-
-void function CreateZipline( vector startPos, vector endPos )
-{
- string startpointName = UniqueString( "rope_startpoint" )
- string endpointName = UniqueString( "rope_endpoint" )
-
- entity rope_start = CreateEntity( "move_rope" )
- SetTargetName( rope_start, startpointName )
- rope_start.kv.NextKey = endpointName
- rope_start.kv.MoveSpeed = 64
- rope_start.kv.Slack = 25
- rope_start.kv.Subdiv = "2"
- rope_start.kv.Width = "2"
- rope_start.kv.Type = "0"
- rope_start.kv.TextureScale = "1"
- rope_start.kv.RopeMaterial = "cable/zipline.vmt"
- rope_start.kv.PositionInterpolator = 2
- rope_start.kv.Zipline = "1"
- rope_start.kv.ZiplineAutoDetachDistance = "150"
- rope_start.kv.ZiplineSagEnable = "0"
- rope_start.kv.ZiplineSagHeight = "50"
- rope_start.SetOrigin( startPos )
-
- entity rope_end = CreateEntity( "keyframe_rope" )
- SetTargetName( rope_end, endpointName )
- rope_end.kv.MoveSpeed = 64
- rope_end.kv.Slack = 25
- rope_end.kv.Subdiv = "2"
- rope_end.kv.Width = "2"
- rope_end.kv.Type = "0"
- rope_end.kv.TextureScale = "1"
- rope_end.kv.RopeMaterial = "cable/zipline.vmt"
- rope_end.kv.PositionInterpolator = 2
- rope_end.kv.Zipline = "1"
- rope_end.kv.ZiplineAutoDetachDistance = "150"
- rope_end.kv.ZiplineSagEnable = "0"
- rope_end.kv.ZiplineSagHeight = "50"
- rope_end.SetOrigin( endPos )
-
- DispatchSpawn( rope_start )
- DispatchSpawn( rope_end )
-}
-
-string function GetNPCTitanSettingFile( entity titan )
-{
- Assert( titan.IsTitan(), titan + " is not a titan" )
- return titan.ai.titanSettings.titanSetFile
-}
-
-void function DecodeBitField( int bitField )
-{
- for ( int bitIndex = 0; bitIndex < 32; bitIndex++ )
- {
- if ( bitField & (1 << bitIndex) )
- {
- printt( "Comparison: ", bitField, "& ( 1 <<", bitIndex, ") = ", bitField & (1 << bitIndex) )
- printt( "BIT SET: ", bitIndex, bitField, 1 << bitIndex )
- }
- }
-}
-
-void function DropWeapon( entity npc )
-{
- entity weapon = npc.GetActiveWeapon()
- if ( !weapon )
- return
-
- string name = weapon.GetWeaponClassName()
-
- // giving the weapon you have drops a new one in its place
- npc.GiveWeapon( name )
- npc.TakeActiveWeapon()
-}
-
-void function TestGiveGunTo( int index, string weaponName )
-{
- entity ent = GetEntByIndex( index )
- if ( !ent )
- {
- printt( "No entity for index:", index )
- return;
- }
-
- TakePrimaryWeapon( ent )
- ent.GiveWeapon( weaponName )
- ent.SetActiveWeaponByName( weaponName )
-}
-
-string function GetEditorClass( entity self )
-{
- if ( self.HasKey( "editorclass" ) )
- return expect string( self.kv.editorclass )
-
- return ""
-}
-
-bool function TitanHasRegenningShield( entity soul )
-{
- if ( !TitanShieldRegenEnabled() )
- return false
-
- if ( !TitanShieldDecayEnabled() )
- return true
-
- if ( SoulHasPassive( soul, ePassives.PAS_SHIELD_BOOST ) )
- return true
-
- return false
-}
-
-void function DelayShieldDecayTime( entity soul, float delay )
-{
- soul.e.nextShieldDecayTime = Time() + delay
-}
-
-void function HighlightWeapon( entity weapon )
-{
-#if HAS_WEAPON_PICKUP_HIGHLIGHT
- if ( weapon.IsLoadoutPickup() )
- {
- Highlight_SetOwnedHighlight( weapon, "sp_loadout_pickup" )
- Highlight_SetNeutralHighlight( weapon, "sp_loadout_pickup" )
- }
- else
- {
- Highlight_SetOwnedHighlight( weapon, "weapon_drop_active" )
- Highlight_SetNeutralHighlight( weapon, "weapon_drop_normal" )
- }
-#endif // #if HAS_WEAPON_PICKUP_HIGHLIGHT
-}
-
-void function WaitTillLookingAt( entity player, entity ent, bool doTrace, float degrees, float minDist = 0, float timeOut = 0, entity trigger = null, string failsafeFlag = "" )
-{
- EndSignal( ent, "OnDestroy" )
- EndSignal( player, "OnDeath" )
-
- //trigger = the trigger ther player must be touching while doing the check
- //failsafeFlag = bypass everything if this flag gets set
-
- if ( failsafeFlag != "" )
- EndSignal( level, failsafeFlag )
-
- float minDistSqr = minDist * minDist
- Assert( minDistSqr >= 0 )
- float timeoutTime = Time() + timeOut
-
- while( true )
- {
-
- if ( timeOut > 0 && Time() > timeoutTime )
- break
-
- if ( failsafeFlag != "" && Flag( failsafeFlag ) )
- break
-
- // Within range?
- if ( minDistSqr > 0 && DistanceSqr( player.GetOrigin(), ent.GetOrigin() ) > minDistSqr )
- {
- WaitFrame()
- continue
- }
-
- // Touching trigger?
- if ( ( trigger != null ) && ( !trigger.IsTouching( player ) ) )
- {
- WaitFrame()
- continue
- }
-
- if ( PlayerCanSee( player, ent, doTrace, degrees ) )
- break
-
- WaitFrame()
- }
-}
-
-void function SetTargetName( entity ent, string name )
-{
- ent.SetValueForKey( "targetname", name )
-}
-
-ZipLine function CreateZipLine( vector start, vector end, int autoDetachDistance = 150, float ziplineMoveSpeedScale = 1.0 )
-{
- string midpointName = UniqueString( "rope_midpoint" )
- string endpointName = UniqueString( "rope_endpoint" )
-
- entity rope_start = CreateEntity( "move_rope" )
- rope_start.kv.NextKey = midpointName
- rope_start.kv.MoveSpeed = 0
- rope_start.kv.ZiplineMoveSpeedScale = ziplineMoveSpeedScale
- rope_start.kv.Slack = 0
- rope_start.kv.Subdiv = 0
- rope_start.kv.Width = "2"
- rope_start.kv.TextureScale = "1"
- rope_start.kv.RopeMaterial = "cable/zipline.vmt"
- rope_start.kv.PositionInterpolator = 2
- rope_start.kv.Zipline = "1"
- rope_start.kv.ZiplineAutoDetachDistance = string( autoDetachDistance )
- rope_start.kv.ZiplineSagEnable = "0"
- rope_start.kv.ZiplineSagHeight = "0"
- rope_start.SetOrigin( start )
-
- entity rope_mid = CreateEntity( "keyframe_rope" )
- SetTargetName( rope_mid, midpointName )
- rope_start.kv.NextKey = endpointName
- rope_mid.SetOrigin( ( start + end ) * 0.5 )
- //rope_mid.SetOrigin( start )
-
- entity rope_end = CreateEntity( "keyframe_rope" )
- SetTargetName( rope_end, endpointName )
- rope_end.SetOrigin( end )
-
- // Dispatch spawn entities
- DispatchSpawn( rope_start )
- DispatchSpawn( rope_mid )
- DispatchSpawn( rope_end )
-
- ZipLine zipLine
- zipLine.start = rope_start
- zipLine.mid = rope_mid
- zipLine.end = rope_end
-
- return zipLine
-}
-
-entity function GetPlayerFromEntity( entity ent )
-{
- entity player = null
-
- if ( ent.IsPlayer() )
- {
- player = ent
- }
- else if ( ent.IsNPC() )
- {
- player = ent.GetBossPlayer()
- }
- else
- {
- player = ent.GetOwner()
- if ( !player || !player.IsPlayer() )
- return null
- }
-
- if ( IsValid_ThisFrame( player ) )
- return player
-
- return null
-}
-
-void function SetHumanRagdollImpactTable( entity ent )
-{
- ent.SetRagdollImpactFX( HUMAN_RAGDOLL_IMPACT_TABLE_IDX )
-}
-
-bool function ScriptManagedEntArrayContains( int handle, entity ent )
-{
- array< entity > ents = GetScriptManagedEntArray( handle )
- foreach ( ent in ents )
- {
- if ( ent == ent )
- return true
- }
-
- return false
-}
-
-void function HideCrit( entity ent )
-{
- int bodyGroupIndex = ent.FindBodyGroup( "hitpoints" )
-
- if ( bodyGroupIndex == -1 )
- {
- return
- }
-
- ent.SetBodygroup( bodyGroupIndex, 1 )
-}
-
-void function ShowCrit( entity ent )
-{
- int bodyGroupIndex = ent.FindBodyGroup( "hitpoints" )
-
- if ( bodyGroupIndex == -1 )
- {
- return
- }
-
- ent.SetBodygroup( bodyGroupIndex, 0 )
-}
-
-
-#if DEV
-void function TeleportEnemyBotToView()
-{
- entity player = gp()[0]
-
- TraceResults traceResults = PlayerViewTrace( player )
-
- if ( traceResults.fraction >= 1.0 )
- return
-
- array<entity> players = GetPlayerArrayOfEnemies_Alive( player.GetTeam() )
- foreach ( enemy in players )
- {
- if ( !enemy.IsBot() )
- continue
-
- enemy.SetOrigin( traceResults.endPos )
- return
- }
-}
-
-void function TeleportEntityToView( entity ent )
-{
- entity player = gp()[0]
-
- TraceResults traceResults = PlayerViewTrace( player )
-
- if ( traceResults.fraction >= 1.0 )
- return
-
- ent.SetOrigin( traceResults.endPos )
- //traceResults.surfaceNormal
-}
-
-void function TeleportFriendlyBotToView()
-{
- entity player = gp()[0]
-
- TraceResults traceResults = PlayerViewTrace( player )
-
- if ( traceResults.fraction >= 1.0 )
- return
-
- array<entity> players = GetPlayerArrayOfTeam_Alive( player.GetTeam() )
- foreach ( enemy in players )
- {
- if ( !enemy.IsBot() )
- continue
-
- enemy.SetOrigin( traceResults.endPos )
- return
- }
-}
-
-void function TeleportBotToAbove()
-{
- entity player = gp()[0]
-
- array<entity> players = GetPlayerArray_AlivePilots()
- foreach ( enemy in players )
- {
- if ( !enemy.IsBot() )
- continue
-
- enemy.SetOrigin( player.GetOrigin() + < 0, 0, 512 > )
- return
- }
-}
-
-TraceResults function PlayerViewTrace( entity player, float distance = 10000 )
-{
- vector eyePosition = player.EyePosition()
- vector viewVector = player.GetViewVector()
-
- TraceResults traceResults = TraceLine( eyePosition, eyePosition + viewVector * distance, player, TRACE_MASK_SHOT_BRUSHONLY, TRACE_COLLISION_GROUP_NONE )
-
- return traceResults
-}
-#endif
-
-void function ClearPlayerAnimViewEntity( entity player, float time = 0.3 )
-{
- entity viewEnt = player.GetFirstPersonProxy()
- viewEnt.HideFirstPersonProxy()
- viewEnt.Anim_Stop()
-
- player.AnimViewEntity_SetLerpOutTime( time )
- player.AnimViewEntity_Clear()
- player.p.currViewConeFunction = null
-}
-
-
-void function BrushMoves( entity brush )
-{
- float moveTime = float( brush.kv.move_time )
- int movedir = int( brush.kv.movedirection )
-
- BrushMovesInDirection( brush, movedir, moveTime )
-}
-
-
-void function BrushMovesInDirection( entity ent, int dir, float moveTime = 0, float blendIn = 0, float blendOut = 0, float lip = 8 )
-{
- entity mover = CreateOwnedScriptMover( ent )
- OnThreadEnd(
- function() : ( ent, mover )
- {
- if ( IsValid( ent ) )
- ent.ClearParent()
- if ( IsValid( mover ) )
- mover.Destroy()
- }
- )
-
- dir %= 360
- if ( dir > 180 )
- dir -= 360
- else if ( dir < -180 )
- dir += 360
-
- string moveAxis = GetMoveAxisFromDir( dir )
-
- ent.SetParent( mover )
- vector origin = ent.GetOrigin()
- float moveAmount
- if ( ent.HasKey( "move_amount" ) )
- {
- moveAmount = float( ent.kv.move_amount ) - lip
- switch ( moveAxis )
- {
- case "x":
- case "y":
- if ( dir < 0 )
- moveAmount *= -1
- break
-
- case "z":
- if ( dir == -1 )
- moveAmount *= -1
- break
- }
- }
- else
- {
- switch ( moveAxis )
- {
- case "x":
- moveAmount = GetEntWidth( ent ) - lip
- if ( dir < 0 )
- moveAmount *= -1
- break
-
- case "y":
- moveAmount = GetEntDepth( ent ) - lip
- if ( dir < 0 )
- moveAmount *= -1
- break
-
- case "z":
- moveAmount = GetEntHeight( ent ) - lip
- if ( dir == -1 )
- moveAmount *= -1
- break
- }
- }
-
- switch ( moveAxis )
- {
- case "x":
- origin.x += moveAmount
- break
- case "y":
- origin.y += moveAmount
- break
- case "z":
- origin.z += moveAmount
- break
- }
-
- if ( moveTime > 0 )
- {
- mover.NonPhysicsMoveTo( origin, moveTime, blendIn, blendOut )
- wait moveTime
- }
- else
- {
- mover.SetOrigin( origin )
- }
-}
-
-string function GetMoveAxisFromDir( int dir )
-{
- if ( dir == 1 || dir == -1 )
- return "z"
-
- if ( dir % 180 == 0 )
- return "x"
-
- return "y"
-}
-
-
-float function GetEntHeight( entity ent )
-{
- return ent.GetBoundingMaxs().z - ent.GetBoundingMins().z
-}
-
-float function GetEntWidth( entity ent )
-{
- return ent.GetBoundingMaxs().x - ent.GetBoundingMins().x
-}
-
-float function GetEntDepth( entity ent )
-{
- return ent.GetBoundingMaxs().y - ent.GetBoundingMins().y
-}
-
-void function PushEntWithVelocity( entity ent, vector velocity )
-{
- if ( !ent.IsPlayer() && !ent.IsNPC() )
- return
-
- if ( !IsAlive( ent ) )
- return
-
- float scale = 1.0
- float pushbackScale = 1.0
- if ( ent.IsTitan() )
- {
- entity soul = ent.GetTitanSoul()
- if ( soul != null ) // defensive fix
- {
- string settings = GetSoulPlayerSettings( soul )
- var scale = Dev_GetPlayerSettingByKeyField_Global( settings, "pushbackScale" )
- if ( scale != null )
- {
- pushbackScale = expect float( scale )
- }
- }
- }
-
- scale = 1.0 - StatusEffect_Get( ent, eStatusEffect.pushback_dampen )
- scale = scale * pushbackScale
-
- velocity *= scale
-
- ent.SetVelocity( velocity )
-}
-
-
-
-bool function IsPlayerMalePilot( entity player )
-{
- Assert( player.IsPlayer() )
-
- if ( !IsPilot( player ) )
- return false
-
- return !IsPlayerFemale( player )
-}
-
-bool function IsPlayerFemalePilot( entity player )
-{
- Assert( player.IsPlayer() )
-
- if ( !IsPilot( player ) )
- return false
-
- return IsPlayerFemale( player )
-}
-
-bool function IsFacingEnemy( entity guy, entity enemy, int viewAngle = 75 )
-{
- vector dir = enemy.GetOrigin() - guy.GetOrigin()
- dir = Normalize( dir )
- float dot = DotProduct( guy.GetPlayerOrNPCViewVector(), dir )
- float yaw = DotToAngle( dot )
-
- return ( yaw < viewAngle )
-}
-
-void function SetSquad( entity guy, string squadName )
-{
- Assert( IsValid( guy ) )
-
- if ( guy.kv.squadname == squadName )
- return
-
- // we only want squads containing NPCs of the same class
- #if HAS_AI_SQUAD_LIMITS
- Assert( SquadValidForClass( squadName, guy.GetClassName() ), "Can't put AI " + guy + " in squad " + squadName + ", because it contains one or more AI with a different class." )
- Assert( SquadCanAcceptNewMembers( guy, squadName ), "Can't add AI " + guy + " to squad " + squadName + ", because that squad already has " + SQUAD_SIZE + " slots filled or reserved." )
- #endif
-
- guy.SetSquad( squadName )
-}
-
-void function PushPlayersApart( entity target, entity attacker, float speed )
-{
- vector dif = Normalize( target.GetOrigin() - attacker.GetOrigin() )
- dif *= speed
- PushPlayerAway( target, dif )
- PushPlayerAway( attacker, -dif )
-}
-
-void function PushPlayerAway( entity target, vector velocity )
-{
- #if MP
- if ( !target.IsPlayer() && !target.IsNPC() )
- return
- #endif
-
- vector result = velocity // + target.GetVelocity()
- result.z = max( 200, fabs( velocity.z ) )
- target.SetVelocity( result )
- //DebugDrawLine( target.GetOrigin(), target.GetOrigin() + result * 5, 255, 0, 0, true, 5.0 )
-}
-
-
-int function SortBySpawnTime( entity ent1, entity ent2 )
-{
- if ( ent1.e.spawnTime > ent2.e.spawnTime )
- return 1
-
- if ( ent2.e.spawnTime > ent1.e.spawnTime )
- return -1
-
- return 0
-}
-
-void function HolsterAndDisableWeapons( entity player )
-{
- player.HolsterWeapon()
- DisableOffhandWeapons( player )
-}
-
-void function HolsterViewModelAndDisableWeapons( entity player ) //Note that this skips the first person holster animation, and it appears to 3p observers you still have a gun out
-{
- player.DisableWeaponViewModel()
- DisableOffhandWeapons( player )
-}
-
-
-void function DeployAndEnableWeapons( entity player )
-{
- player.DeployWeapon()
- EnableOffhandWeapons( player )
-}
-
-void function DeployViewModelAndEnableWeapons( entity player )
-{
- if ( IsAlive( player ) )
- player.EnableWeaponViewModel()
- EnableOffhandWeapons( player )
-}
-
-//Investigate: This might be getting called without enableoffhandweapons being called. If so, Server_TurnOffhandWeaponsDisabledOn() should be used instead of this stack system.
-void function DisableOffhandWeapons( entity player )
-{
- player.Server_TurnOffhandWeaponsDisabledOn()
- player.p.disableOffhandWeaponsStackCount++
-}
-
-void function EnableOffhandWeapons( entity player )
-{
- player.p.disableOffhandWeaponsStackCount--
- if ( player.p.disableOffhandWeaponsStackCount <= 0 )
- player.Server_TurnOffhandWeaponsDisabledOff()
-
- Assert( player.p.disableOffhandWeaponsStackCount >= 0, "Warning! Called EnableOffhandWeapons() but the weapons aren't disabled!" )
-}
-
-void function PushEntWithDamageInfoAndDistanceScale( entity ent, var damageInfo, float nearRange, float farRange, float nearScale, float farScale, float forceMultiplier_dotBase = 0.5 )
-{
- float scale = GraphCapped( DamageInfo_GetDistFromAttackOrigin( damageInfo ), nearRange, farRange, nearScale, farScale )
-
- if ( scale > 0 )
- PushEntWithDamageInfo( ent, damageInfo, forceMultiplier_dotBase, scale )
-}
-
-void function PushEntWithDamageInfo( entity ent, var damageInfo, float forceMultiplier_dotBase = 0.5, float forceMultiplier_dotScale = 0.5 )
-{
- int source = DamageInfo_GetDamageSourceIdentifier( damageInfo )
- switch ( source )
- {
- case eDamageSourceId.mp_titanweapon_vortex_shield:
- case eDamageSourceId.mp_titanweapon_vortex_shield_ion:
- return
- }
-
- entity projectile = DamageInfo_GetInflictor( damageInfo )
- if ( !IsValid( projectile ) )
- return
-
- vector attackDirection = Normalize( projectile.GetVelocity() )
- float damage = DamageInfo_GetDamage( damageInfo )
-
- PushEntWithDamageFromDirection( ent, damage, attackDirection, forceMultiplier_dotBase, forceMultiplier_dotScale )
-}
-
-void function PushEntWithDamageFromDirection( entity ent, float damage, vector attackDirection, float forceMultiplier_dotBase = 0.5, float forceMultiplier_dotScale = 0.5 )
-{
-
- float speed
- if ( damage < 900 )
- speed = GraphCapped( damage, 0, 900, 0, 650 )
- else
- speed = GraphCapped( damage, 900, 1400, 650, 1400 )
-
- vector direction = attackDirection + <0,0,0>
- direction.z *= 0.25
- vector force = direction * speed
-
- force += < 0, 0, fabs( direction.z ) * 0.25 >
-
- vector velocity = ent.GetVelocity()
- vector baseVel = Normalize( velocity + <0,0,0> )
-
- float dot = DotProduct( baseVel, attackDirection ) * -1
- float dotMultiplier
- if ( dot > 0 )
- {
- dot *= forceMultiplier_dotScale
- }
- else
- {
- dot = 0
- }
-
- force *= ( forceMultiplier_dotBase + dot )
- //printt( "force " + Length( force ) )
- velocity += force
- PushEntWithVelocity( ent, velocity )
-}
-
-
-void function SetPlayerAnimViewEntity( entity player, entity model )
-{
- // clear any attempts to hide the view anim entity
- player.Signal( "NewViewAnimEntity" )
- player.AnimViewEntity_SetEntity( model )
-}
-
-
-void function RandomizeHead( entity model ) //Randomize head across all available heads
-{
- int headIndex = model.FindBodyGroup( "head" )
- if ( headIndex == -1 )
- {
- //printt( "HeadIndex == -1, returning" )
- return
- }
- int numOfHeads = model.GetBodyGroupModelCount( headIndex ) - 1 // last one is no head
- //printt( "Num of Heads: " + numOfHeads )
-
- if ( HasTeamSkin( model ) )
- {
- RandomizeHeadByTeam( model, headIndex, numOfHeads )
- return
- }
- else
- {
- int randomHeadIndex = RandomInt( numOfHeads )
- //printt( "Set head to: : " + randomHeadIndex )
- model.SetBodygroup( headIndex, randomHeadIndex )
- }
-}
-
-bool function HasTeamSkin( entity model )
-{
- return "teamSkin" in model.CreateTableFromModelKeyValues()
-}
-
-void function RandomizeHeadByTeam( entity model, int headIndex, int numOfHeads ) //Randomize head across heads available to a particular team. Assumes for a model all imc heads are first, then all militia heads are later.
-{
- float midPoint = float( numOfHeads / 2 )
-
- int randomHeadIndex = 0
- if ( model.GetTeam() == TEAM_IMC )
- {
- randomHeadIndex = RandomInt( midPoint )
- }
- else if ( model.GetTeam() == TEAM_MILITIA )
- {
- randomHeadIndex = RandomIntRange( midPoint, numOfHeads )
- }
- //printt( "Model ", model.GetModelName(), " is using ", numOfHeads, " randomHeadIndex")
-
- //printt( "Set head to: : " + randomHeadIndex )
- model.SetBodygroup( headIndex, randomHeadIndex )
-}
-
-void function TakeWeaponsForArray( entity ent, array<entity> weapons )
-{
- foreach ( weapon in weapons )
- {
- ent.TakeWeaponNow( weapon.GetWeaponClassName() )
- }
-}
-
-void function ScaleHealth( entity ent, float scale )
-{
- Assert( IsAlive( ent ) )
-
- int maxHealth = ent.GetMaxHealth()
- float healthRatio = float( ent.GetHealth() ) / maxHealth
- maxHealth = int( maxHealth * scale )
- ent.SetHealth( maxHealth * healthRatio )
- ent.SetMaxHealth( maxHealth )
-}
-
-void function TeleportPlayerToEnt( entity player, entity org )
-{
- if ( !IsValid( player ) )
- return
- Assert( player.IsPlayer() )
- player.SetOrigin( org.GetOrigin() )
- player.SetAngles( org.GetAngles() )
-}
-
-float function ShieldModifyDamage( entity ent, var damageInfo )
-{
- entity victim
- if ( ent.IsTitan() )
- victim = ent.GetTitanSoul()
- else
- victim = ent
-
- int shieldHealth = victim.GetShieldHealth()
-
- float damage = DamageInfo_GetDamage( damageInfo )
-
- int damageSourceIdentifier = DamageInfo_GetDamageSourceIdentifier( damageInfo )
- ShieldDamageModifier damageModifier = GetShieldDamageModifier( damageInfo )
- damage *= damageModifier.damageScale
-
- float healthFrac = GetHealthFrac( victim )
-
- float permanentDamage = (damage * damageModifier.permanentDamageFrac * healthFrac)
-
- float shieldDamage
-
- if ( damageSourceIdentifier == eDamageSourceId.titanEmpField )
- {
- shieldDamage = min( 1000.0, float( shieldHealth ) )
- }
- else
- {
- if ( damageModifier.normalizeShieldDamage )
- shieldDamage = damage * 0.5
- else
- shieldDamage = damage - permanentDamage
-
- // if ( IsSoul( victim ) && SoulHasPassive( victim, ePassives.PAS_SHIELD_BOOST ) )
- // shieldDamage *= SHIELD_BOOST_DAMAGE_DAMPEN
-
- if ( IsSoul( victim ) && SoulHasPassive( victim, ePassives.PAS_BERSERKER ) )
- shieldDamage *= BERSERKER_INCOMING_DAMAGE_DAMPEN
- }
-
- float newShieldHealth = shieldHealth - shieldDamage
-
- victim.SetShieldHealth( max( 0, newShieldHealth ) )
-
- if ( shieldHealth > 0 && newShieldHealth <= 0 )
- {
- if ( ent.IsPlayer() )
- {
- EmitSoundOnEntityExceptToPlayer( ent, ent, "titan_energyshield_down_3P" )
- EmitSoundOnEntityOnlyToPlayer( ent, ent, "titan_energyshield_down_1P" )
- }
- else if ( ent.GetScriptName() == "fw_team_tower" )
- {
- EmitSoundOnEntity( ent, "TitanWar_Harvester_ShieldDown" )
-
- #if FACTION_DIALOGUE_ENABLED
- PlayFactionDialogueToTeam( "fortwar_baseShieldDownFriendly", ent.GetTeam() )
- PlayFactionDialogueToTeam( "fortwar_baseShieldDownEnemy", GetOtherTeam( ent.GetTeam() ) )
- #endif
- }
- else
- {
- EmitSoundOnEntity( ent, "titan_energyshield_down_3P" )
- }
- }
-
- DamageInfo_AddCustomDamageType( damageInfo, DF_SHIELD_DAMAGE )
-
- if ( newShieldHealth < 0 )
- {
- DamageInfo_SetDamage( damageInfo, fabs( newShieldHealth ) + permanentDamage )
- }
- else
- {
- if ( permanentDamage == 0 )
- {
- entity attacker = DamageInfo_GetAttacker( damageInfo )
- vector damageOrigin = GetDamageOrigin( damageInfo, ent )
- int damageType = DamageInfo_GetCustomDamageType( damageInfo )
- int attackerEHandle = attacker.GetEncodedEHandle()
- int damageSourceId = DamageInfo_GetDamageSourceIdentifier( damageInfo )
-
- if ( attacker.IsPlayer() )
- attacker.NotifyDidDamage( ent, DamageInfo_GetHitBox( damageInfo ), DamageInfo_GetDamagePosition( damageInfo ), damageType, shieldDamage, DamageInfo_GetDamageFlags( damageInfo ), DamageInfo_GetHitGroup( damageInfo ), DamageInfo_GetWeapon( damageInfo ), DamageInfo_GetDistFromAttackOrigin( damageInfo ) )
- if ( ent.IsPlayer() )
- Remote_CallFunction_Replay( ent, "ServerCallback_TitanTookDamage", shieldDamage, damageOrigin.x, damageOrigin.y, damageOrigin.z, damageType, damageSourceId, attackerEHandle, null, false, 0 )
- }
- DamageInfo_SetDamage( damageInfo, permanentDamage )
- }
-
- float actualShieldDamage = min( shieldHealth, shieldDamage )
-
- if ( actualShieldDamage > 0 )
- {
- foreach ( func in ent.e.entPostShieldDamageCallbacks )
- {
- func( ent, damageInfo, actualShieldDamage )
- }
- }
-
- return actualShieldDamage
-}
-
-ShieldDamageModifier function GetShieldDamageModifier( var damageInfo )
-{
- ShieldDamageModifier damageModifier
-
- // Disabling Shield Damage Modifiers and rebalancing the weapons. The below mechanics seem cool in an R1 style system though so leaving them commented out.
- // NOTE: Changing Damage Scale has a buggy interaction with permanent damage that must be fixed if we re-enable this.
- /*
- int damageSourceIdentifier = DamageInfo_GetDamageSourceIdentifier( damageInfo )
-
- switch ( damageSourceIdentifier )
- {
- case eDamageSourceId.mp_weapon_thermite_grenade:
- damageModifier.permanentDamageFrac = 0.9
- break
- }
-
- if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_ELECTRICAL )
- {
- // amped version
- if ( damageSourceIdentifier == eDamageSourceId.mp_titanweapon_xo16 )
- damageModifier.damageScale *= 1.5
-
- // amped version
- if ( damageSourceIdentifier == eDamageSourceId.mp_titanweapon_triple_threat )
- damageModifier.damageScale *= 1.5
-
- if ( damageSourceIdentifier == eDamageSourceId.mp_titanweapon_arc_cannon )
- damageModifier.damageScale *= 1.5
- }
- */
-
- if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_ELECTRICAL )
- {
- int damageSourceIdentifier = DamageInfo_GetDamageSourceIdentifier( damageInfo )
- // Vanguard Arc Rounds
- if ( damageSourceIdentifier == eDamageSourceId.mp_titanweapon_xo16_vanguard )
- damageModifier.damageScale *= 1.5
- }
-
-
- return damageModifier
-}
-
-
-
-void function AddCallback_NPCLeeched( void functionref( entity, entity ) callbackFunc )
-{
- Assert( !( svGlobal.onLeechedCustomCallbackFunc.contains( callbackFunc ) ) )
- svGlobal.onLeechedCustomCallbackFunc.append( callbackFunc )
-}
-
-void function MessageToPlayer( entity player, int eventID, entity ent = null, var eventVal = null )
-{
- var eHandle = null
- if ( ent )
- eHandle = ent.GetEncodedEHandle()
-
- Remote_CallFunction_NonReplay( player, "ServerCallback_EventNotification", eventID, eHandle, eventVal )
- //SendHudMessage( player, message, 0.33, 0.28, 255, 255, 255, 255, 0.15, 3.0, 0.5 )
-}
-
-
-void function MessageToTeam( int team, int eventID, entity excludePlayer = null, entity ent = null, var eventVal = null )
-{
- array<entity> players = GetPlayerArray()
-
- foreach ( player in players )
- {
- if ( player.GetTeam() != team )
- continue
-
- if ( player == excludePlayer )
- continue
-
- MessageToPlayer( player, eventID, ent, eventVal )
- }
-}
-
-void function MessageToAll( int eventID, entity excludePlayer = null, entity ent = null, var eventVal = null )
-{
- array<entity> players = GetPlayerArray()
-
- foreach ( player in players )
- {
- if ( player == excludePlayer )
- continue
-
- MessageToPlayer( player, eventID, ent, eventVal )
- }
-}
-
-
-
-string function ReloadScriptsInternal()
-{
- reloadingScripts = true
- reloadedScripts = true
- ReloadingScriptsBegin()
-
- if ( IsMenuLevel() )
- {
- reloadingScripts = false
- ReloadingScriptsEnd()
- return ""
- }
-
- TitanEmbark_Init()
-
- ReloadScriptCallbacks()
-
- reloadingScripts = false
- ReloadingScriptsEnd()
-
- return ( "reloaded server scripts" )
-}
-
-string function ReloadScripts()
-{
- ServerCommand( "fs_report_sync_opens 0" ) // makes reload scripts slow
- delaythread ( 0 ) ReloadScriptsInternal()
-
- return ( "reloaded server scripts" )
-}
-
-int function GameTime_TimeLimitSeconds()
-{
- if ( IsRoundBased() )
- {
- return ( GetRoundTimeLimit_ForGameMode() * 60.0 ).tointeger()
- }
- else
- {
- if ( IsSuddenDeathGameMode() && GetGameState() == eGameState.SuddenDeath )
- return ( GetTimeLimit_ForGameMode() * 60.0 ).tointeger() + ( GetSuddenDeathTimeLimit_ForGameMode() * 60.0 ).tointeger()
- else
- return ( GetTimeLimit_ForGameMode() * 60.0 ).tointeger()
- }
- unreachable
-}
-
-int function GetSuddenDeathTimeLimit_ForGameMode()
-{
- string mode = GameRules_GetGameMode()
- string playlistString = "suddendeath_timelimit"
-
- return GetCurrentPlaylistVarInt( playlistString, 4 )
-}
-
-int function GameTime_TimeLimitMinutes()
-{
- if ( IsRoundBased() )
- return floor( GetRoundTimeLimit_ForGameMode() ).tointeger()
- else
- return floor( GetTimeLimit_ForGameMode() ).tointeger()
- unreachable
-}
-
-int function GameTime_TimeLeftMinutes()
-{
- if ( GetGameState() == eGameState.WaitingForPlayers )
- return 0
- if ( GetGameState() == eGameState.Prematch )
- return int( ( expect float( GetServerVar( "gameStartTime" ) ) - Time()) / 60.0 )
-
- return floor( GameTime_TimeLimitMinutes() - GameTime_PlayingTime() / 60 ).tointeger()
-}
-
-int function GameTime_TimeLeftSeconds()
-{
- if ( GetGameState() == eGameState.Prematch )
- return int( expect float( GetServerVar( "gameStartTime" ) ) - Time() )
-
- return floor( GameTime_TimeLimitSeconds() - GameTime_PlayingTime() ).tointeger()
-}
-
-int function GameTime_Seconds()
-{
- return floor( Time() ).tointeger()
-}
-
-int function GameTime_Minutes()
-{
- return int( floor( GameTime_Seconds() / 60 ) )
-}
-
-float function GameTime_PlayingTime()
-{
- return GameTime_PlayingTimeSince( Time() )
-}
-
-float function GameTime_PlayingTimeSince( float sinceTime )
-{
- int gameState = GetGameState()
-
- // temp fix because i have no fucking clue why this crashes
-
- if ( gameState < eGameState.Playing )
- return 0
-
- if ( IsRoundBased() )
- {
- if ( gameState > eGameState.SuddenDeath )
- return (expect float( GetServerVar( "roundEndTime" ) ) - expect float( GetServerVar( "roundStartTime" ) ) )
- else
- return sinceTime - expect float( GetServerVar( "roundStartTime" ) )
-
- }
- else
- {
- if ( gameState > eGameState.SuddenDeath )
- return (expect float( GetServerVar( "gameEndTime" ) ) - expect float( GetServerVar( "gameStartTime" ) ) )
- else
- return sinceTime - expect float( GetServerVar( "gameStartTime" ) )
- }
-
- unreachable
-}
-
-float function GameTime_TimeSpentInCurrentState()
-{
- return Time() - expect float( GetServerVar( "gameStateChangeTime" ) )
-}
-
-int function GameScore_GetFirstToScoreLimit()
-{
- return expect int( level.firstToScoreLimit )
-}
-
-bool function GameScore_AllowPointsOverLimit()
-{
- return svGlobal.allowPointsOverLimit
-}
-
-int function GameScore_GetWinningTeam()
-{
- if ( GameScore_GetFirstToScoreLimit() )
- return GameScore_GetFirstToScoreLimit()
-
- if ( IsRoundBased() )
- {
- if ( GameRules_GetTeamScore2( TEAM_IMC ) > GameRules_GetTeamScore2( TEAM_MILITIA ) )
- return TEAM_IMC
- else if ( GameRules_GetTeamScore2( TEAM_MILITIA ) > GameRules_GetTeamScore2( TEAM_IMC ) )
- return TEAM_MILITIA
- }
- else
- {
- if ( GameRules_GetTeamScore( TEAM_IMC ) > GameRules_GetTeamScore( TEAM_MILITIA ) )
- return TEAM_IMC
- else if ( GameRules_GetTeamScore( TEAM_MILITIA ) > GameRules_GetTeamScore( TEAM_IMC ) )
- return TEAM_MILITIA
- }
-
- return TEAM_UNASSIGNED
-}
-
-int function GameScore_GetWinningTeam_ThisRound()
-{
- if ( GameScore_GetFirstToScoreLimit() )
- return GameScore_GetFirstToScoreLimit()
-
- Assert ( IsRoundBased() )
-
- if ( GameRules_GetTeamScore( TEAM_IMC ) > GameRules_GetTeamScore( TEAM_MILITIA ) )
- return TEAM_IMC
- else if ( GameRules_GetTeamScore( TEAM_MILITIA ) > GameRules_GetTeamScore( TEAM_IMC ) )
- return TEAM_MILITIA
-
- return TEAM_UNASSIGNED
-}
-
-#if DEV
-void function KillIMC()
-{
- array<entity> enemies = GetNPCArrayOfTeam( TEAM_IMC )
- foreach ( enemy in enemies )
- {
- enemy.Die()
- }
-}
-
-void function killtitans()
-{
- printt( "Script command: Kill all titans" )
- array<entity> titans = GetTitanArray()
- foreach ( titan in titans )
- titan.Die()
-}
-
-void function killminions()
-{
- printt( "Script command: Kill all minions" )
- array<entity> minions = GetAllMinions()
- foreach ( minion in minions )
- {
- minion.Die()
- }
-}
-#endif
-
-
-array<entity> function GetTeamMinions( int team )
-{
- array<entity> ai = GetNPCArrayByClass( "npc_soldier" )
- ai.extend( GetNPCArrayByClass( "npc_spectre" ) )
-
- for ( int i = 0; i < ai.len(); i++ )
- {
- if ( ai[i].GetTeam() != team )
- {
- ai.remove(i)
- i--
- }
- }
-
- return ai
-}
-
-array<entity> function GetAllMinions()
-{
- array<entity> ai = GetNPCArrayByClass( "npc_soldier" )
- ai.extend( GetNPCArrayByClass( "npc_spectre" ) )
- ai.extend( GetNPCArrayByClass( "npc_drone" ) )
-
- return ai
-}
-
-
-bool function GameScore_IsLowScoreDifference()
-{
- int winningTeam = GameScore_GetWinningTeam()
-
- if ( !winningTeam )
- return true
-
- int losingTeam = GetOtherTeam( winningTeam )
-
- int winningTeamScore
- int losingTeamScore
-
- if ( IsRoundBased() )
- {
- winningTeamScore = GameRules_GetTeamScore2( winningTeam )
- losingTeamScore = GameRules_GetTeamScore2( losingTeam )
- }
- else
- {
- winningTeamScore = GameRules_GetTeamScore( winningTeam )
- losingTeamScore = GameRules_GetTeamScore( losingTeam )
- }
-
- return ( winningTeamScore - losingTeamScore < 2 )
-}
-
-bool function IsFastPilot( entity player )
-{
- Assert( IsPilot( player ), "Pilot only check" )
-
- if ( player.IsWallHanging() )
- return false
-
- if ( player.IsWallRunning() )
- return true
-
- if ( !player.IsOnGround() )
- return true
-
- if ( LengthSqr( player.GetSmoothedVelocity() ) > 180*180 || LengthSqr( player.GetVelocity() ) > 180*180 )
- return true
-
- return false
-}
-
-void function KillPlayer( entity player, int damageSource )
-{
- #if DEV
- printt( "Played Killed from script: " )
- DumpStack()
- #endif
-
- Assert( IsAlive( player ) )
- Assert( player.IsPlayer() )
- player.Die( svGlobal.worldspawn, svGlobal.worldspawn, { damageSourceId = damageSource, scriptType=DF_SKIP_DAMAGE_PROT | DF_SKIPS_DOOMED_STATE } )
-}
-
-
-//////////////////////////////////////////////////////////
-void function TurretChangeTeam( entity turret, int team )
-{
- if ( team != TEAM_UNASSIGNED )
- {
- // If a turret is on some player's team it should never be invulnerable
- MakeTurretVulnerable( turret )
- }
-
- SetTeam( turret, team )
-
- // refresh the turret client side particle effects
- UpdateTurretClientSideParticleEffects( turret )
-}
-
-void function MakeTurretInvulnerable( entity turret )
-{
- Assert( IsValid( turret ) )
- turret.SetInvulnerable()
- turret.SetNoTarget(true)
- turret.SetNoTargetSmartAmmo(true)
-}
-
-void function MakeTurretVulnerable( entity turret )
-{
- Assert( IsValid( turret ) )
- turret.ClearInvulnerable()
- turret.SetNoTarget(false)
- turret.SetNoTargetSmartAmmo(false)
-}
-
-
-void function UpdateTurretClientSideParticleEffects( entity turret )
-{
- if ( !IsValid( turret ) )
- return
-
- int turretEHandle = turret.GetEncodedEHandle()
- array<entity> players = GetPlayerArray()
- foreach( player in players )
- {
- Remote_CallFunction_Replay( player, "ServerCallback_TurretRefresh", turretEHandle )
- }
-}
-
-
-
-bool function TakePrimaryWeapon( entity player )
-{
- array<entity> weapons = player.GetMainWeapons()
- foreach ( index, weaponEnt in weapons )
- {
- int weaponType = weaponEnt.GetWeaponType()
- if ( weaponType == WT_SIDEARM || weaponType == WT_ANTITITAN )
- continue;
-
- string weapon = weaponEnt.GetWeaponClassName()
- player.TakeWeaponNow( weapon )
- return true
- }
- return false
-}
-
-bool function TakeSecondaryWeapon( entity player )
-{
- array<entity> weapons = player.GetMainWeapons()
- foreach ( index, weaponEnt in weapons )
- {
- if ( weaponEnt.GetWeaponType() != WT_ANTITITAN )
- continue
-
- string weapon = weaponEnt.GetWeaponClassName()
- player.TakeWeaponNow( weapon )
- return true
- }
- return false
-}
-
-bool function TakeSidearmWeapon( entity player )
-{
- array<entity> weapons = player.GetMainWeapons()
- foreach ( index, weaponEnt in weapons )
- {
- if ( weaponEnt.GetWeaponType() != WT_SIDEARM )
- continue
-
- string weapon = weaponEnt.GetWeaponClassName()
- player.TakeWeaponNow( weapon )
- return true
- }
- return false
-}
-
-void function TakeAllWeapons( entity ent )
-{
- if ( ent.IsPlayer() )
- {
- ent.RemoveAllItems()
- array<entity> weapons = ent.GetMainWeapons()
- foreach ( weapon in weapons )
- {
- Assert( 0, ent + " still has weapon " + weapon.GetWeaponClassName() + " after doing takeallweapons" )
- }
- }
- else
- {
- array<entity> weapons = ent.GetMainWeapons()
- TakeWeaponsForArray( ent, weapons )
-
- weapons = ent.GetOffhandWeapons()
- foreach ( index, weapon in clone weapons )
- {
- ent.TakeOffhandWeapon( index )
- }
- TakeWeaponsForArray( ent, weapons )
- }
-}
-
-
-void function SetSpawnflags( entity ent, int spawnFlags )
-{
- ent.kv.spawnflags = spawnFlags
-}
-
-
-void function DestroyAfterDelay( entity ent, float delay )
-{
- Assert( IsNewThread(), "Must be threaded off" )
-
- ent.EndSignal( "OnDestroy" )
-
- wait( delay )
-
- ent.Destroy()
-}
-
-void function UnlockAchievement( entity player, int achievementID )
-{
- Assert( IsValid( player ), "Can't unlock achievement on invalid player entity" )
- Assert( player.IsPlayer(), "Can't unlock achivement on non-player entity" )
- Assert( achievementID > 0 && achievementID < achievements.MAX_ACHIVEMENTS, "Tried to unlock achievement with invalid enum value" )
-
- Remote_CallFunction_UI( player, "ScriptCallback_UnlockAchievement", achievementID )
-}
-
-void function UpdateHeroStatsForPlayer( entity player )
-{
- if ( !IsValid( player ) )
- return
- Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateHeroStats" )
-}
-
-void function TestDeathFall()
-{
- entity trigger = GetEntByScriptName( "DeathFallTrigger" )
- table results = WaitSignal( trigger, "OnTrigger" )
- printt( "DEATH FALL TRIGGERED" )
- PrintTable( results )
-}
-
-bool function PlayerHasTitan( entity player )
-{
- entity titan
- if ( player.IsTitan() )
- titan = player
- else
- titan = player.GetPetTitan()
-
- if ( IsAlive( titan ) )
- return true
-
- return false
-}