aboutsummaryrefslogtreecommitdiff
path: root/Northstar.CustomServers/scripts/vscripts/weapons/_vortex.nut
diff options
context:
space:
mode:
Diffstat (limited to 'Northstar.CustomServers/scripts/vscripts/weapons/_vortex.nut')
-rw-r--r--Northstar.CustomServers/scripts/vscripts/weapons/_vortex.nut1983
1 files changed, 0 insertions, 1983 deletions
diff --git a/Northstar.CustomServers/scripts/vscripts/weapons/_vortex.nut b/Northstar.CustomServers/scripts/vscripts/weapons/_vortex.nut
deleted file mode 100644
index f1e46a531..000000000
--- a/Northstar.CustomServers/scripts/vscripts/weapons/_vortex.nut
+++ /dev/null
@@ -1,1983 +0,0 @@
-untyped
-
-global function Vortex_Init
-
-global function CreateVortexSphere
-global function DestroyVortexSphereFromVortexWeapon
-global function EnableVortexSphere
-#if SERVER
-global function ValidateVortexImpact
-global function TryVortexAbsorb
-global function SetVortexSphereBulletHitRules
-global function SetVortexSphereProjectileHitRules
-#endif
-global function VortexDrainedByImpact
-global function VortexPrimaryAttack
-global function GetVortexSphereCurrentColor
-global function GetShieldTriLerpColor
-global function IsVortexing
-#if SERVER
-global function Vortex_HandleElectricDamage
-global function VortexSphereDrainHealthForDamage
-global function Vortex_CreateImpactEventData
-global function Vortex_SpawnHeatShieldPingFX
-#endif
-
-global function Vortex_SetTagName
-global function Vortex_SetBulletCollectionOffset
-
-global function CodeCallback_OnVortexHitBullet
-global function CodeCallback_OnVortexHitProjectile
-
-const AMPED_WALL_IMPACT_FX = $"P_impact_xo_shield_cp"
-
-global const PROTO_AMPED_WALL = "proto_amped_wall"
-global const GUN_SHIELD_WALL = "gun_shield_wall"
-const PROX_MINE_MODEL = $"models/weapons/caber_shot/caber_shot_thrown.mdl"
-
-const VORTEX_SPHERE_COLOR_CHARGE_FULL = <115, 247, 255> // blue
-const VORTEX_SPHERE_COLOR_CHARGE_MED = <200, 128, 80> // orange
-const VORTEX_SPHERE_COLOR_CHARGE_EMPTY = <200, 80, 80> // red
-const VORTEX_SPHERE_COLOR_PAS_ION_VORTEX = <115, 174, 255> // blue
-const AMPED_DAMAGE_SCALAR = 1.5
-
-const VORTEX_SPHERE_COLOR_CROSSOVERFRAC_FULL2MED = 0.75 // from zero to this fraction, fade between full and medium charge colors
-const VORTEX_SPHERE_COLOR_CROSSOVERFRAC_MED2EMPTY = 0.95 // from "full2med" to this fraction, fade between medium and empty charge colors
-
-const VORTEX_BULLET_ABSORB_COUNT_MAX = 32
-const VORTEX_PROJECTILE_ABSORB_COUNT_MAX = 32
-
-const VORTEX_TIMED_EXPLOSIVE_FUSETIME = 2.75 // fuse time for absorbed projectiles
-const VORTEX_TIMED_EXPLOSIVE_FUSETIME_WARNINGFRAC = 0.75 // wait this fraction of the fuse time before warning the player it's about to explode
-
-const VORTEX_EXP_ROUNDS_RETURN_SPREAD_XY = 0.15
-const VORTEX_EXP_ROUNDS_RETURN_SPREAD_Z = 0.075
-
-const VORTEX_ELECTRIC_DAMAGE_CHARGE_DRAIN_MIN = 0.1 // fraction of charge time
-const VORTEX_ELECTRIC_DAMAGE_CHARGE_DRAIN_MAX = 0.3
-
-//The shotgun spams a lot of pellets that deal too much damage if they return full damage.
-const VORTEX_SHOTGUN_DAMAGE_RATIO = 0.25
-
-
-const SHIELD_WALL_BULLET_FX = $"P_impact_xo_shield_cp"
-const SHIELD_WALL_EXPMED_FX = $"P_impact_exp_med_xo_shield_CP"
-
-const SIGNAL_ID_BULLET_HIT_THINK = "signal_id_bullet_hit_think"
-
-const VORTEX_EXPLOSIVE_WARNING_SFX_LOOP = "Weapon_Vortex_Gun.ExplosiveWarningBeep"
-
-const VORTEX_PILOT_WEAPON_WEAKNESS_DAMAGESCALE = 6.0
-
-// These match the strings in the WeaponEd dropdown box for vortex_refire_behavior
-global const VORTEX_REFIRE_NONE = ""
-global const VORTEX_REFIRE_ABSORB = "absorb"
-global const VORTEX_REFIRE_BULLET = "bullet"
-global const VORTEX_REFIRE_EXPLOSIVE_ROUND = "explosive_round"
-global const VORTEX_REFIRE_ROCKET = "rocket"
-global const VORTEX_REFIRE_GRENADE = "grenade"
-global const VORTEX_REFIRE_GRENADE_LONG_FUSE = "grenade_long_fuse"
-
-const VortexIgnoreClassnames = {
- ["mp_titancore_flame_wave"] = true,
- ["mp_ability_grapple"] = true,
- ["mp_ability_shifter"] = true,
-}
-
-table vortexImpactWeaponInfo
-
-const DEG_COS_60 = cos( 60 * DEG_TO_RAD )
-
-function Vortex_Init()
-{
- PrecacheParticleSystem( SHIELD_WALL_BULLET_FX )
- GetParticleSystemIndex( SHIELD_WALL_BULLET_FX )
- PrecacheParticleSystem( SHIELD_WALL_EXPMED_FX )
- GetParticleSystemIndex( SHIELD_WALL_EXPMED_FX )
- PrecacheParticleSystem( AMPED_WALL_IMPACT_FX )
- GetParticleSystemIndex( AMPED_WALL_IMPACT_FX )
-
- RegisterSignal( SIGNAL_ID_BULLET_HIT_THINK )
- RegisterSignal( "VortexStopping" )
-
- RegisterSignal( "VortexAbsorbed" )
- RegisterSignal( "VortexFired" )
- RegisterSignal( "Script_OnDamaged" )
-}
-
-#if SERVER
-var function VortexBulletHitRules_Default( entity vortexSphere, var damageInfo )
-{
- return damageInfo
-}
-
-bool function VortexProjectileHitRules_Default( entity vortexSphere, entity attacker, bool takesDamageByDefault )
-{
- return takesDamageByDefault
-}
-
-void function SetVortexSphereBulletHitRules( entity vortexSphere, var functionref( entity, var ) customRules )
-{
- vortexSphere.e.BulletHitRules = customRules
-}
-
-void function SetVortexSphereProjectileHitRules( entity vortexSphere, bool functionref( entity, entity, bool ) customRules )
-{
- vortexSphere.e.ProjectileHitRules = customRules
-}
-#endif
-function CreateVortexSphere( entity vortexWeapon, bool useCylinderCheck, bool blockOwnerWeapon, int sphereRadius = 40, int bulletFOV = 180 )
-{
- entity owner = vortexWeapon.GetWeaponOwner()
- Assert( owner )
-
- #if SERVER
- //printt( "util ent:", vortexWeapon.GetWeaponUtilityEntity() )
- Assert ( !vortexWeapon.GetWeaponUtilityEntity(), "Tried to create more than one vortex sphere on a vortex weapon!" )
-
- entity vortexSphere = CreateEntity( "vortex_sphere" )
- Assert( vortexSphere )
-
- int spawnFlags = SF_ABSORB_BULLETS | SF_BLOCK_NPC_WEAPON_LOF
-
- if ( useCylinderCheck )
- {
- spawnFlags = spawnFlags | SF_ABSORB_CYLINDER
- vortexSphere.kv.height = sphereRadius * 2
- }
-
- if ( blockOwnerWeapon )
- spawnFlags = spawnFlags | SF_BLOCK_OWNER_WEAPON
-
- vortexSphere.kv.spawnflags = spawnFlags
-
- vortexSphere.kv.enabled = 0
- vortexSphere.kv.radius = sphereRadius
- vortexSphere.kv.bullet_fov = bulletFOV
- vortexSphere.kv.physics_pull_strength = 25
- vortexSphere.kv.physics_side_dampening = 6
- vortexSphere.kv.physics_fov = 360
- vortexSphere.kv.physics_max_mass = 2
- vortexSphere.kv.physics_max_size = 6
- Assert( owner.IsNPC() || owner.IsPlayer(), "Vortex script expects the weapon owner to be a player or NPC." )
-
- SetVortexSphereBulletHitRules( vortexSphere, VortexBulletHitRules_Default )
- SetVortexSphereProjectileHitRules( vortexSphere, VortexProjectileHitRules_Default )
-
- DispatchSpawn( vortexSphere )
-
- vortexSphere.SetOwner( owner )
-
- if ( owner.IsNPC() )
- {
- vortexSphere.SetParent( owner, "PROPGUN" )
- vortexSphere.SetLocalOrigin( Vector( 0, 35, 0 ) )
- }
- else
- {
- vortexSphere.SetParent( owner )
- vortexSphere.SetLocalOrigin( Vector( 0, 10, -30 ) )
- }
- vortexSphere.SetAbsAngles( Vector( 0, 0, 0 ) ) //Setting local angles on a parented object is not supported
-
- vortexSphere.SetOwnerWeapon( vortexWeapon )
- vortexWeapon.SetWeaponUtilityEntity( vortexSphere )
- #endif
-
- SetVortexAmmo( vortexWeapon, 0 )
-}
-
-
-function EnableVortexSphere( entity vortexWeapon )
-{
- string tagname = GetVortexTagName( vortexWeapon )
- entity weaponOwner = vortexWeapon.GetWeaponOwner()
- local hasBurnMod = vortexWeapon.GetWeaponSettingBool( eWeaponVar.is_burn_mod )
-
- #if SERVER
- entity vortexSphere = vortexWeapon.GetWeaponUtilityEntity()
- Assert( vortexSphere )
- vortexSphere.FireNow( "Enable" )
-
- thread SetPlayerUsingVortex( weaponOwner, vortexWeapon )
-
- Vortex_CreateAbsorbFX_ControlPoints( vortexWeapon )
-
- // world (3P) version of the vortex sphere FX
- vortexSphere.s.worldFX <- CreateEntity( "info_particle_system" )
-
- if ( hasBurnMod )
- {
- if ( "fxChargingControlPointBurn" in vortexWeapon.s )
- vortexSphere.s.worldFX.SetValueForEffectNameKey( expect asset( vortexWeapon.s.fxChargingControlPointBurn ) )
- }
- else
- {
- if ( "fxChargingControlPoint" in vortexWeapon.s )
- vortexSphere.s.worldFX.SetValueForEffectNameKey( expect asset( vortexWeapon.s.fxChargingControlPoint ) )
- }
-
- vortexSphere.s.worldFX.kv.start_active = 1
- vortexSphere.s.worldFX.SetOwner( weaponOwner )
- vortexSphere.s.worldFX.SetParent( vortexWeapon, tagname )
- vortexSphere.s.worldFX.kv.VisibilityFlags = (ENTITY_VISIBLE_TO_FRIENDLY | ENTITY_VISIBLE_TO_ENEMY) // not owner only
- vortexSphere.s.worldFX.kv.cpoint1 = vortexWeapon.s.vortexSphereColorCP.GetTargetName()
- vortexSphere.s.worldFX.SetStopType( "destroyImmediately" )
-
- DispatchSpawn( vortexSphere.s.worldFX )
- #endif
-
- SetVortexAmmo( vortexWeapon, 0 )
-
- #if CLIENT
- if ( IsLocalViewPlayer( weaponOwner ) )
- {
- local fxAlias = null
-
- if ( hasBurnMod )
- {
- if ( "fxChargingFPControlPointBurn" in vortexWeapon.s )
- fxAlias = vortexWeapon.s.fxChargingFPControlPointBurn
- }
- else
- {
- if ( "fxChargingFPControlPoint" in vortexWeapon.s )
- fxAlias = vortexWeapon.s.fxChargingFPControlPoint
- }
-
- if ( fxAlias )
- {
- int sphereClientFXHandle = vortexWeapon.PlayWeaponEffectReturnViewEffectHandle( fxAlias, $"", tagname )
- thread VortexSphereColorUpdate( vortexWeapon, sphereClientFXHandle )
- }
- }
- #elseif SERVER
- asset fxAlias = $""
-
- if ( hasBurnMod )
- {
- if ( "fxChargingFPControlPointReplayBurn" in vortexWeapon.s )
- fxAlias = expect asset( vortexWeapon.s.fxChargingFPControlPointReplayBurn )
- }
- else
- {
- if ( "fxChargingFPControlPointReplay" in vortexWeapon.s )
- fxAlias = expect asset( vortexWeapon.s.fxChargingFPControlPointReplay )
- }
-
- if ( fxAlias != $"" )
- vortexWeapon.PlayWeaponEffect( fxAlias, $"", tagname )
-
- thread VortexSphereColorUpdate( vortexWeapon )
- #endif
-}
-
-
-function DestroyVortexSphereFromVortexWeapon( entity vortexWeapon )
-{
- DisableVortexSphereFromVortexWeapon( vortexWeapon )
-
- #if SERVER
- DestroyVortexSphere( vortexWeapon.GetWeaponUtilityEntity() )
- vortexWeapon.SetWeaponUtilityEntity( null )
- #endif
-}
-
-void function DestroyVortexSphere( entity vortexSphere )
-{
- if ( IsValid( vortexSphere ) )
- {
- vortexSphere.s.worldFX.Destroy()
- vortexSphere.Destroy()
- }
-}
-
-
-function DisableVortexSphereFromVortexWeapon( entity vortexWeapon )
-{
- vortexWeapon.Signal( "VortexStopping" )
-
- // server cleanup
- #if SERVER
- DisableVortexSphere( vortexWeapon.GetWeaponUtilityEntity() )
- Vortex_CleanupAllEffects( vortexWeapon )
- Vortex_ClearImpactEventData( vortexWeapon )
- #endif
-
- // client & server cleanup
-
- if ( vortexWeapon.GetWeaponSettingBool( eWeaponVar.is_burn_mod ) )
- {
- if ( "fxChargingFPControlPointBurn" in vortexWeapon.s )
- vortexWeapon.StopWeaponEffect( expect asset( vortexWeapon.s.fxChargingFPControlPointBurn ), $"" )
- if ( "fxChargingFPControlPointReplayBurn" in vortexWeapon.s )
- vortexWeapon.StopWeaponEffect( expect asset( vortexWeapon.s.fxChargingFPControlPointReplayBurn ), $"" )
- }
- else
- {
- if ( "fxChargingFPControlPoint" in vortexWeapon.s )
- vortexWeapon.StopWeaponEffect( expect asset( vortexWeapon.s.fxChargingFPControlPoint ), $"" )
- if ( "fxChargingFPControlPointReplay" in vortexWeapon.s )
- vortexWeapon.StopWeaponEffect( expect asset( vortexWeapon.s.fxChargingFPControlPointReplay ), $"" )
- }
-}
-
-void function DisableVortexSphere( entity vortexSphere )
-{
- if ( IsValid( vortexSphere ) )
- {
- vortexSphere.FireNow( "Disable" )
- vortexSphere.Signal( SIGNAL_ID_BULLET_HIT_THINK )
- }
-
-}
-
-
-#if SERVER
-function Vortex_CreateAbsorbFX_ControlPoints( entity vortexWeapon )
-{
- entity player = vortexWeapon.GetWeaponOwner()
- Assert( player )
-
- // vortex swirling incoming rounds FX location control point
- if ( !( "vortexBulletEffectCP" in vortexWeapon.s ) )
- vortexWeapon.s.vortexBulletEffectCP <- null
- vortexWeapon.s.vortexBulletEffectCP = CreateEntity( "info_placement_helper" )
- SetTargetName( expect entity( vortexWeapon.s.vortexBulletEffectCP ), UniqueString( "vortexBulletEffectCP" ) )
- vortexWeapon.s.vortexBulletEffectCP.kv.start_active = 1
-
- DispatchSpawn( vortexWeapon.s.vortexBulletEffectCP )
-
- vector offset = GetBulletCollectionOffset( vortexWeapon )
- vector origin = player.OffsetPositionFromView( player.EyePosition(), offset )
-
- vortexWeapon.s.vortexBulletEffectCP.SetOrigin( origin )
- vortexWeapon.s.vortexBulletEffectCP.SetParent( player )
-
- // vortex sphere color control point
- if ( !( "vortexSphereColorCP" in vortexWeapon.s ) )
- vortexWeapon.s.vortexSphereColorCP <- null
- vortexWeapon.s.vortexSphereColorCP = CreateEntity( "info_placement_helper" )
- SetTargetName( expect entity( vortexWeapon.s.vortexSphereColorCP ), UniqueString( "vortexSphereColorCP" ) )
- vortexWeapon.s.vortexSphereColorCP.kv.start_active = 1
-
- DispatchSpawn( vortexWeapon.s.vortexSphereColorCP )
-}
-
-
-function Vortex_CleanupAllEffects( entity vortexWeapon )
-{
- Assert( IsServer() )
-
- Vortex_CleanupImpactAbsorbFX( vortexWeapon )
-
- if ( ( "vortexBulletEffectCP" in vortexWeapon.s ) && IsValid_ThisFrame( expect entity( vortexWeapon.s.vortexBulletEffectCP ) ) )
- vortexWeapon.s.vortexBulletEffectCP.Destroy()
-
- if ( ( "vortexSphereColorCP" in vortexWeapon.s ) && IsValid_ThisFrame( expect entity( vortexWeapon.s.vortexSphereColorCP ) ) )
- vortexWeapon.s.vortexSphereColorCP.Destroy()
-}
-#endif // SERVER
-
-
-function SetPlayerUsingVortex( entity weaponOwner, entity vortexWeapon )
-{
- weaponOwner.EndSignal( "OnDeath" )
-
- weaponOwner.s.isVortexing <- true
-
- vortexWeapon.WaitSignal( "VortexStopping" )
-
- OnThreadEnd
- (
- function() : ( weaponOwner )
- {
- if ( IsValid_ThisFrame( weaponOwner ) && "isVortexing" in weaponOwner.s )
- {
- delete weaponOwner.s.isVortexing
- }
- }
- )
-}
-
-
-function IsVortexing( entity ent )
-{
- Assert( IsServer() )
-
- if ( "isVortexing" in ent.s )
- return true
-}
-
-
-#if SERVER
-function Vortex_HandleElectricDamage( entity ent, entity attacker, damage, entity weapon )
-{
- if ( !IsValid( ent ) )
- return damage
-
- if ( !ent.IsTitan() )
- return damage
-
- if ( !ent.IsPlayer() && !ent.IsNPC() )
- return damage
-
- if ( !IsVortexing( ent ) )
- return damage
-
- entity vortexWeapon = ent.GetActiveWeapon()
- if ( !IsValid( vortexWeapon ) )
- return damage
-
- entity vortexSphere = vortexWeapon.GetWeaponUtilityEntity()
- if ( !IsValid( vortexSphere ) )
- return damage
-
- if ( !IsValid( vortexWeapon ) || !IsValid( vortexSphere ) )
- return damage
-
- // vortex FOV check
- //printt( "sphere FOV:", vortexSphere.kv.bullet_fov )
- local sphereFOV = vortexSphere.kv.bullet_fov.tointeger()
- entity attackerWeapon = attacker.GetActiveWeapon()
- int attachIdx = attackerWeapon.LookupAttachment( "muzzle_flash" )
- vector beamOrg = attackerWeapon.GetAttachmentOrigin( attachIdx )
- vector firingDir = beamOrg - vortexSphere.GetOrigin()
- firingDir = Normalize( firingDir )
- vector vortexDir = AnglesToForward( vortexSphere.GetAngles() )
-
- float dot = DotProduct( vortexDir, firingDir )
-
- float degCos = DEG_COS_60
- if ( sphereFOV != 120 )
- deg_cos( sphereFOV * 0.5 )
-
- // not in the vortex cone
- if ( dot < degCos )
- return damage
-
- if ( "fxElectricalExplosion" in vortexWeapon.s )
- {
- entity fxRef = CreateEntity( "info_particle_system" )
- fxRef.SetValueForEffectNameKey( expect asset( vortexWeapon.s.fxElectricalExplosion ) )
- fxRef.kv.start_active = 1
- fxRef.SetStopType( "destroyImmediately" )
- //fxRef.kv.VisibilityFlags = ENTITY_VISIBLE_TO_OWNER // HACK this turns on owner only visibility. Uncomment when we hook up dedicated 3P effects
- fxRef.SetOwner( ent )
- fxRef.SetOrigin( vortexSphere.GetOrigin() )
- fxRef.SetParent( ent )
-
- DispatchSpawn( fxRef )
- fxRef.Kill_Deprecated_UseDestroyInstead( 1 )
- }
-
- return 0
-}
-
-// this function handles all incoming vortex impact events
-bool function TryVortexAbsorb( entity vortexSphere, entity attacker, vector origin, int damageSourceID, entity weapon, string weaponName, string impactType, entity projectile = null, damageType = null, reflect = false )
-{
- if ( weaponName in VortexIgnoreClassnames )
- return false
-
- entity vortexWeapon = vortexSphere.GetOwnerWeapon()
- entity owner = vortexWeapon.GetWeaponOwner()
-
- // keep cycling the oldest hitscan bullets out
- if( !reflect )
- {
- if ( impactType == "hitscan" )
- Vortex_ClampAbsorbedBulletCount( vortexWeapon )
- else
- Vortex_ClampAbsorbedProjectileCount( vortexWeapon )
- }
-
- // vortex spheres tag refired projectiles with info about the original projectile for accurate duplication when re-absorbed
- if ( projectile )
- {
-
- // specifically for tether, since it gets moved to the vortex area and can get absorbed in the process, then destroyed
- if ( !IsValid( projectile ) )
- return false
-
- entity projOwner = projectile.GetOwner()
- if ( IsValid( projOwner ) && projOwner.GetTeam() == owner.GetTeam() )
- return false
-
- if ( projectile.proj.hasBouncedOffVortex )
- return false
-
- if ( projectile.ProjectileGetWeaponInfoFileKeyField( "projectile_ignores_vortex" ) == "fall_vortex" )
- {
- vector velocity = projectile.GetVelocity()
- vector multiplier = < -0.25, -0.25, -0.25 >
- velocity = < velocity.x * multiplier.x, velocity.y * multiplier.y, velocity.z * multiplier.z >
- projectile.SetVelocity( velocity )
- projectile.proj.hasBouncedOffVortex = true
- return false
- }
-
- // if ( projectile.GetParent() == owner )
- // return false
-
- if ( "originalDamageSource" in projectile.s )
- {
- damageSourceID = expect int( projectile.s.originalDamageSource )
-
- // Vortex Volley Achievement
- if ( IsValid( owner ) && owner.IsPlayer() )
- {
- //if ( PlayerProgressionAllowed( owner ) )
- // SetAchievement( owner, "ach_vortexVolley", true )
- }
- }
-
- // Max projectile stat tracking
- int projectilesInVortex = 1
- projectilesInVortex += vortexWeapon.w.vortexImpactData.len()
-
- if ( IsValid( owner ) && owner.IsPlayer() )
- {
- if ( PlayerProgressionAllowed( owner ) )
- {
- int record = owner.GetPersistentVarAsInt( "mostProjectilesCollectedInVortex" )
- if ( projectilesInVortex > record )
- owner.SetPersistentVar( "mostProjectilesCollectedInVortex", projectilesInVortex )
- }
-
- var impact_sound_1p = projectile.ProjectileGetWeaponInfoFileKeyField( "vortex_impact_sound_1p" )
- if ( impact_sound_1p != null )
- EmitSoundOnEntityOnlyToPlayer( vortexSphere, owner, impact_sound_1p )
- }
-
- var impact_sound_3p = projectile.ProjectileGetWeaponInfoFileKeyField( "vortex_impact_sound_3p" )
- if ( impact_sound_3p != null )
- EmitSoundAtPosition( TEAM_UNASSIGNED, origin, impact_sound_3p )
- }
- else
- {
- if ( IsValid( owner ) && owner.IsPlayer() )
- {
- var impact_sound_1p = GetWeaponInfoFileKeyField_Global( weaponName, "vortex_impact_sound_1p" )
- if ( impact_sound_1p != null )
- EmitSoundOnEntityOnlyToPlayer( vortexSphere, owner, impact_sound_1p )
- }
-
- var impact_sound_3p = GetWeaponInfoFileKeyField_Global( weaponName, "vortex_impact_sound_3p" )
- if ( impact_sound_3p != null )
- EmitSoundAtPosition( TEAM_UNASSIGNED, origin, impact_sound_3p )
- }
-
- local impactData = Vortex_CreateImpactEventData( vortexWeapon, attacker, origin, damageSourceID, weaponName, impactType )
-
- VortexDrainedByImpact( vortexWeapon, weapon, projectile, damageType )
- Vortex_NotifyAttackerDidDamage( expect entity( impactData.attacker ), owner, impactData.origin )
-
- if ( impactData.refireBehavior == VORTEX_REFIRE_ABSORB )
- return true
-
- if ( vortexWeapon.GetWeaponClassName() == "mp_titanweapon_heat_shield" )
- return true
-
- if ( !Vortex_ScriptCanHandleImpactEvent( impactData ) )
- return false
-
- Vortex_StoreImpactEvent( vortexWeapon, impactData )
-
- VortexImpact_PlayAbsorbedFX( vortexWeapon, impactData )
-
- if ( impactType == "hitscan" )
- vortexSphere.AddBulletToSphere();
- else
- vortexSphere.AddProjectileToSphere();
-
- local maxShotgunPelletsToIgnore = VORTEX_BULLET_ABSORB_COUNT_MAX * ( 1 - VORTEX_SHOTGUN_DAMAGE_RATIO )
- if ( IsPilotShotgunWeapon( weaponName ) && ( vortexWeapon.s.shotgunPelletsToIgnore + 1 ) < maxShotgunPelletsToIgnore )
- vortexWeapon.s.shotgunPelletsToIgnore += ( 1 - VORTEX_SHOTGUN_DAMAGE_RATIO )
-
- if ( reflect )
- {
- local attackParams = {}
- attackParams.pos <- owner.EyePosition()
- attackParams.dir <- owner.GetPlayerOrNPCViewVector()
-
- int bulletsFired = VortexReflectAttack( vortexWeapon, attackParams, expect vector( impactData.origin ) )
-
- Vortex_CleanupImpactAbsorbFX( vortexWeapon )
- Vortex_ClearImpactEventData( vortexWeapon )
-
- while ( vortexSphere.GetBulletAbsorbedCount() > 0 )
- vortexSphere.RemoveBulletFromSphere();
-
- while ( vortexSphere.GetProjectileAbsorbedCount() > 0 )
- vortexSphere.RemoveProjectileFromSphere();
- }
-
- return true
-}
-#endif // SERVER
-
-function VortexDrainedByImpact( entity vortexWeapon, entity weapon, entity projectile, damageType )
-{
- if ( vortexWeapon.HasMod( "unlimited_charge_time" ) )
- return
- if ( vortexWeapon.HasMod( "vortex_extended_effect_and_no_use_penalty" ) )
- return
-
- float amount
- if ( projectile )
- amount = projectile.GetProjectileWeaponSettingFloat( eWeaponVar.vortex_drain )
- else
- amount = weapon.GetWeaponSettingFloat( eWeaponVar.vortex_drain )
-
- if ( amount <= 0.0 )
- return
-
- if ( vortexWeapon.GetWeaponClassName() == "mp_titanweapon_vortex_shield_ion" )
- {
- entity owner = vortexWeapon.GetWeaponOwner()
- int totalEnergy = owner.GetSharedEnergyTotal()
- owner.TakeSharedEnergy( int( float( totalEnergy ) * amount ) )
- }
- else
- {
- float frac = min ( vortexWeapon.GetWeaponChargeFraction() + amount, 1.0 )
- vortexWeapon.SetWeaponChargeFraction( frac )
- }
-}
-
-
-function VortexSlowOwnerFromAttacker( entity player, entity attacker, vector velocity, float multiplier )
-{
- vector damageForward = player.GetOrigin() - attacker.GetOrigin()
- damageForward.z = 0
- damageForward.Norm()
-
- vector velForward = player.GetVelocity()
- velForward.z = 0
- velForward.Norm()
-
- float dot = DotProduct( velForward, damageForward )
- if ( dot >= -0.5 )
- return
-
- dot += 0.5
- dot *= -2.0
-
- vector negateVelocity = velocity * -multiplier
- negateVelocity *= dot
-
- velocity += negateVelocity
- player.SetVelocity( velocity )
-}
-
-
-#if SERVER
-function Vortex_ClampAbsorbedBulletCount( entity vortexWeapon )
-{
- if ( GetBulletsAbsorbedCount( vortexWeapon ) >= ( VORTEX_BULLET_ABSORB_COUNT_MAX - 1 ) )
- Vortex_RemoveOldestAbsorbedBullet( vortexWeapon )
-}
-
-function Vortex_ClampAbsorbedProjectileCount( entity vortexWeapon )
-{
- if ( GetProjectilesAbsorbedCount( vortexWeapon ) >= ( VORTEX_PROJECTILE_ABSORB_COUNT_MAX - 1 ) )
- Vortex_RemoveOldestAbsorbedProjectile( vortexWeapon )
-}
-
-function Vortex_RemoveOldestAbsorbedBullet( entity vortexWeapon )
-{
- entity vortexSphere = vortexWeapon.GetWeaponUtilityEntity()
-
- local bulletImpacts = Vortex_GetHitscanBulletImpacts( vortexWeapon )
- local impactDataToRemove = bulletImpacts[ 0 ] // since it's an array, the first one will be the oldest
-
- Vortex_RemoveImpactEvent( vortexWeapon, impactDataToRemove )
-
- vortexSphere.RemoveBulletFromSphere()
-}
-
-function Vortex_RemoveOldestAbsorbedProjectile( entity vortexWeapon )
-{
- entity vortexSphere = vortexWeapon.GetWeaponUtilityEntity()
-
- local projImpacts = Vortex_GetProjectileImpacts( vortexWeapon )
- local impactDataToRemove = projImpacts[ 0 ] // since it's an array, the first one will be the oldest
-
- Vortex_RemoveImpactEvent( vortexWeapon, impactDataToRemove )
-
- vortexSphere.RemoveProjectileFromSphere()
-}
-
-function Vortex_CreateImpactEventData( entity vortexWeapon, entity attacker, vector origin, int damageSourceID, string weaponName, string impactType )
-{
- entity player = vortexWeapon.GetWeaponOwner()
- local impactData = {}
-
- impactData.attacker <- attacker
- impactData.origin <- origin
- impactData.damageSourceID <- damageSourceID
- impactData.weaponName <- weaponName
- impactData.impactType <- impactType
-
- impactData.refireBehavior <- VORTEX_REFIRE_NONE
- impactData.absorbSFX <- "Vortex_Shield_AbsorbBulletSmall"
- impactData.absorbSFX_1p_vs_3p <- null
-
- impactData.team <- null
- // sets a team even if the attacker disconnected
- if ( IsValid_ThisFrame( attacker ) )
- {
- impactData.team = attacker.GetTeam()
- }
- else
- {
- // default to opposite team
- if ( player.GetTeam() == TEAM_IMC )
- impactData.team = TEAM_MILITIA
- else
- impactData.team = TEAM_IMC
- }
-
- impactData.absorbFX <- null
- impactData.absorbFX_3p <- null
- impactData.fxEnt_absorb <- null
-
- impactData.explosionradius <- null
- impactData.explosion_damage <- null
- impactData.impact_effect_table <- -1
- // -- everything from here down relies on being able to read a megaweapon file
- if ( !( impactData.weaponName in vortexImpactWeaponInfo ) )
- {
- vortexImpactWeaponInfo[ impactData.weaponName ] <- {}
- vortexImpactWeaponInfo[ impactData.weaponName ].absorbFX <- GetWeaponInfoFileKeyFieldAsset_Global( impactData.weaponName, "vortex_absorb_effect" )
- vortexImpactWeaponInfo[ impactData.weaponName ].absorbFX_3p <- GetWeaponInfoFileKeyFieldAsset_Global( impactData.weaponName, "vortex_absorb_effect_third_person" )
- vortexImpactWeaponInfo[ impactData.weaponName ].refireBehavior <- GetWeaponInfoFileKeyField_Global( impactData.weaponName, "vortex_refire_behavior" )
- vortexImpactWeaponInfo[ impactData.weaponName ].absorbSound <- GetWeaponInfoFileKeyField_Global( impactData.weaponName, "vortex_absorb_sound" )
- vortexImpactWeaponInfo[ impactData.weaponName ].absorbSound_1p_vs_3p <- GetWeaponInfoFileKeyField_Global( impactData.weaponName, "vortex_absorb_sound_1p_vs_3p" )
- vortexImpactWeaponInfo[ impactData.weaponName ].explosionradius <- GetWeaponInfoFileKeyField_Global( impactData.weaponName, "explosionradius" )
- vortexImpactWeaponInfo[ impactData.weaponName ].explosion_damage_heavy_armor <- GetWeaponInfoFileKeyField_Global( impactData.weaponName, "explosion_damage_heavy_armor" )
- vortexImpactWeaponInfo[ impactData.weaponName ].explosion_damage <- GetWeaponInfoFileKeyField_Global( impactData.weaponName, "explosion_damage" )
- vortexImpactWeaponInfo[ impactData.weaponName ].impact_effect_table <- GetWeaponInfoFileKeyField_Global( impactData.weaponName, "impact_effect_table" )
- vortexImpactWeaponInfo[ impactData.weaponName ].grenade_ignition_time <- GetWeaponInfoFileKeyField_Global( impactData.weaponName, "grenade_ignition_time" )
- vortexImpactWeaponInfo[ impactData.weaponName ].grenade_fuse_time <- GetWeaponInfoFileKeyField_Global( impactData.weaponName, "grenade_fuse_time" )
- }
-
- impactData.absorbFX = vortexImpactWeaponInfo[ impactData.weaponName ].absorbFX
- impactData.absorbFX_3p = vortexImpactWeaponInfo[ impactData.weaponName ].absorbFX_3p
- if ( impactData.absorbFX )
- Assert( impactData.absorbFX_3p, "Missing 3rd person absorb effect for " + impactData.weaponName )
- impactData.refireBehavior = vortexImpactWeaponInfo[ impactData.weaponName ].refireBehavior
-
- local absorbSound = vortexImpactWeaponInfo[ impactData.weaponName ].absorbSound
- if ( absorbSound )
- impactData.absorbSFX = absorbSound
-
- local absorbSound_1p_vs_3p = vortexImpactWeaponInfo[ impactData.weaponName ].absorbSound_1p_vs_3p
- if ( absorbSound_1p_vs_3p )
- impactData.absorbSFX_1p_vs_3p = absorbSound_1p_vs_3p
-
- // info we need for refiring (some types of) impacts
- impactData.explosionradius = vortexImpactWeaponInfo[ impactData.weaponName ].explosionradius
- impactData.explosion_damage = vortexImpactWeaponInfo[ impactData.weaponName ].explosion_damage_heavy_armor
- if ( impactData.explosion_damage == null )
- impactData.explosion_damage = vortexImpactWeaponInfo[ impactData.weaponName ].explosion_damage
- impactData.impact_effect_table = vortexImpactWeaponInfo[ impactData.weaponName ].impact_effect_table
-
- return impactData
-}
-
-function Vortex_ScriptCanHandleImpactEvent( impactData )
-{
- if ( impactData.refireBehavior == VORTEX_REFIRE_NONE )
- return false
-
- if ( !impactData.absorbFX )
- return false
-
- if ( impactData.impactType == "projectile" && !impactData.impact_effect_table )
- return false
-
- return true
-}
-
-function Vortex_StoreImpactEvent( entity vortexWeapon, impactData )
-{
- vortexWeapon.w.vortexImpactData.append( impactData )
-}
-
-// safely removes data for a single impact event
-function Vortex_RemoveImpactEvent( entity vortexWeapon, impactData )
-{
- Vortex_ImpactData_KillAbsorbFX( impactData )
-
- vortexWeapon.w.vortexImpactData.fastremovebyvalue( impactData )
-}
-
-function Vortex_GetAllImpactEvents( entity vortexWeapon )
-{
- return vortexWeapon.w.vortexImpactData
-}
-
-function Vortex_ClearImpactEventData( entity vortexWeapon )
-{
- vortexWeapon.w.vortexImpactData = []
-}
-
-function VortexImpact_PlayAbsorbedFX( entity vortexWeapon, impactData )
-{
- // generic shield ping FX
- Vortex_SpawnShieldPingFX( vortexWeapon, impactData )
-
- // specific absorb FX
- impactData.fxEnt_absorb = Vortex_SpawnImpactAbsorbFX( vortexWeapon, impactData )
-}
-
-// FX played when something first enters the vortex sphere
-function Vortex_SpawnShieldPingFX( entity vortexWeapon, impactData )
-{
- entity player = vortexWeapon.GetWeaponOwner()
- Assert( player )
-
- local absorbSFX = impactData.absorbSFX
- //printt( "SFX absorb sound:", absorbSFX )
- if ( vortexWeapon.GetWeaponSettingBool( eWeaponVar.is_burn_mod ) )
- EmitSoundOnEntity( vortexWeapon, "Vortex_Shield_Deflect_Amped" )
- else
- {
- EmitSoundOnEntity( vortexWeapon, absorbSFX )
- if ( impactData.absorbSFX_1p_vs_3p != null )
- {
- if ( IsValid( impactData.attacker ) && impactData.attacker.IsPlayer() )
- {
- EmitSoundOnEntityOnlyToPlayer( vortexWeapon, impactData.attacker, impactData.absorbSFX_1p_vs_3p )
- }
- }
- }
-
- entity pingFX = CreateEntity( "info_particle_system" )
-
- if ( vortexWeapon.GetWeaponSettingBool( eWeaponVar.is_burn_mod ) )
- {
- if ( "fxBulletHitBurn" in vortexWeapon.s )
- pingFX.SetValueForEffectNameKey( expect asset( vortexWeapon.s.fxBulletHitBurn ) )
- }
- else
- {
- if ( "fxBulletHit" in vortexWeapon.s )
- pingFX.SetValueForEffectNameKey( expect asset( vortexWeapon.s.fxBulletHit ) )
- }
-
- pingFX.kv.start_active = 1
-
- DispatchSpawn( pingFX )
-
- pingFX.SetOrigin( impactData.origin )
- pingFX.SetParent( player )
- pingFX.Kill_Deprecated_UseDestroyInstead( 0.25 )
-}
-
-function Vortex_SpawnHeatShieldPingFX( entity vortexWeapon, impactData, bool impactTypeIsBullet )
-{
- entity player = vortexWeapon.GetWeaponOwner()
- Assert( player )
-
- if ( impactTypeIsBullet )
- EmitSoundOnEntity( vortexWeapon, "heat_shield_stop_bullet" )
- else
- EmitSoundOnEntity( vortexWeapon, "heat_shield_stop_projectile" )
-
- entity pingFX = CreateEntity( "info_particle_system" )
-
- if ( "fxBulletHit" in vortexWeapon.s )
- pingFX.SetValueForEffectNameKey( expect asset( vortexWeapon.s.fxBulletHit ) )
-
- pingFX.kv.start_active = 1
-
- DispatchSpawn( pingFX )
-
- pingFX.SetOrigin( impactData.origin )
- pingFX.SetParent( player )
- pingFX.Kill_Deprecated_UseDestroyInstead( 0.25 )
-}
-
-function Vortex_SpawnImpactAbsorbFX( entity vortexWeapon, impactData )
-{
- // in case we're in the middle of cleaning the weapon up
- if ( !IsValid( vortexWeapon.s.vortexBulletEffectCP ) )
- return
-
- entity owner = vortexWeapon.GetWeaponOwner()
- Assert( owner )
-
- local fxRefs = []
-
- // owner
- {
- entity fxRef = CreateEntity( "info_particle_system" )
-
- fxRef.SetValueForEffectNameKey( expect asset( impactData.absorbFX ) )
- fxRef.kv.start_active = 1
- fxRef.SetStopType( "destroyImmediately" )
- fxRef.kv.VisibilityFlags = ENTITY_VISIBLE_TO_OWNER
- fxRef.kv.cpoint1 = vortexWeapon.s.vortexBulletEffectCP.GetTargetName()
-
- DispatchSpawn( fxRef )
-
- fxRef.SetOwner( owner )
- fxRef.SetOrigin( impactData.origin )
- fxRef.SetParent( owner )
-
- fxRefs.append( fxRef )
- }
-
- // everyone else
- {
- entity fxRef = CreateEntity( "info_particle_system" )
-
- fxRef.SetValueForEffectNameKey( expect asset( impactData.absorbFX_3p ) )
- fxRef.kv.start_active = 1
- fxRef.SetStopType( "destroyImmediately" )
- fxRef.kv.VisibilityFlags = (ENTITY_VISIBLE_TO_FRIENDLY | ENTITY_VISIBLE_TO_ENEMY) // other only visibility
- fxRef.kv.cpoint1 = vortexWeapon.s.vortexBulletEffectCP.GetTargetName()
-
- DispatchSpawn( fxRef )
-
- fxRef.SetOwner( owner )
- fxRef.SetOrigin( impactData.origin )
- fxRef.SetParent( owner )
-
- fxRefs.append( fxRef )
- }
-
- return fxRefs
-}
-
-function Vortex_CleanupImpactAbsorbFX( entity vortexWeapon )
-{
- foreach ( impactData in Vortex_GetAllImpactEvents( vortexWeapon ) )
- {
- Vortex_ImpactData_KillAbsorbFX( impactData )
- }
-}
-
-function Vortex_ImpactData_KillAbsorbFX( impactData )
-{
- foreach ( fxRef in impactData.fxEnt_absorb )
- {
- if ( !IsValid( fxRef ) )
- continue
-
- fxRef.Fire( "DestroyImmediately" )
- fxRef.Kill_Deprecated_UseDestroyInstead()
- }
-}
-
-bool function PlayerDiedOrDisconnected( entity player )
-{
- if ( !IsValid( player ) )
- return true
-
- if ( !IsAlive( player ) )
- return true
-
- if ( IsDisconnected( player ) )
- return true
-
- return false
-}
-
-#endif // SERVER
-
-int function VortexPrimaryAttack( entity vortexWeapon, WeaponPrimaryAttackParams attackParams )
-{
- entity vortexSphere = vortexWeapon.GetWeaponUtilityEntity()
- if ( !vortexSphere )
- return 0
-
- #if SERVER
- Assert( vortexSphere )
- #endif
-
- int totalfired = 0
- int totalAttempts = 0
-
- bool forceReleased = false
- // in this case, it's also considered "force released" if the charge time runs out
- if ( vortexWeapon.IsForceRelease() || vortexWeapon.GetWeaponChargeFraction() == 1 )
- forceReleased = true
-
- // PREDICTED REFIRES
- // bullet impact events don't individually fire back per event because we aggregate and then shotgun blast them
- int bulletsFired = Vortex_FireBackBullets( vortexWeapon, attackParams )
- totalfired += bulletsFired
-
- // UNPREDICTED REFIRES
- #if SERVER
- //printt( "server: force released?", forceReleased )
-
- local unpredictedRefires = Vortex_GetProjectileImpacts( vortexWeapon )
-
- // HACK we don't actually want to refire them with a spiral but
- // this is to temporarily ensure compatibility with the Titan rocket launcher
- if ( !( "spiralMissileIdx" in vortexWeapon.s ) )
- vortexWeapon.s.spiralMissileIdx <- null
- vortexWeapon.s.spiralMissileIdx = 0
-
- foreach ( impactData in unpredictedRefires )
- {
- table fakeAttackParams = {pos = attackParams.pos, dir = attackParams.dir, firstTimePredicted = attackParams.firstTimePredicted, burstIndex = attackParams.burstIndex}
- bool didFire = DoVortexAttackForImpactData( vortexWeapon, fakeAttackParams, impactData, totalAttempts )
- if ( didFire )
- totalfired++
- totalAttempts++
- }
- //printt( "totalfired", totalfired )
- #else
- totalfired += GetProjectilesAbsorbedCount( vortexWeapon )
- #endif
-
- SetVortexAmmo( vortexWeapon, 0 )
-
- vortexWeapon.Signal( "VortexFired" )
-
- if ( forceReleased )
- DestroyVortexSphereFromVortexWeapon( vortexWeapon )
- else
- DisableVortexSphereFromVortexWeapon( vortexWeapon )
-
- return totalfired
-}
-
-int function Vortex_FireBackBullets( entity vortexWeapon, WeaponPrimaryAttackParams attackParams )
-{
- int bulletCount = GetBulletsAbsorbedCount( vortexWeapon )
- //Defensive Check - Couldn't repro error.
- if ( "shotgunPelletsToIgnore" in vortexWeapon.s )
- bulletCount = int( ceil( bulletCount - vortexWeapon.s.shotgunPelletsToIgnore ) )
-
- if ( bulletCount )
- {
- bulletCount = minint( bulletCount, MAX_BULLET_PER_SHOT )
-
- //if ( IsClient() && GetLocalViewPlayer() == vortexWeapon.GetWeaponOwner() )
- // printt( "vortex firing", bulletCount, "bullets" )
-
- float radius = LOUD_WEAPON_AI_SOUND_RADIUS_MP;
- vortexWeapon.EmitWeaponNpcSound( radius, 0.2 )
- int damageType = damageTypes.shotgun | DF_VORTEX_REFIRE
- if ( bulletCount == 1 )
- vortexWeapon.FireWeaponBullet( attackParams.pos, attackParams.dir, bulletCount, damageType )
- else
- ShotgunBlast( vortexWeapon, attackParams.pos, attackParams.dir, bulletCount, damageType )
- }
-
- return bulletCount
-}
-
-#if SERVER
-bool function Vortex_FireBackExplosiveRound( vortexWeapon, attackParams, impactData, sequenceID )
-{
- expect entity( vortexWeapon )
-
- // common projectile data
- float projSpeed = 8000.0
- int damageType = damageTypes.explosive | DF_VORTEX_REFIRE
-
- vortexWeapon.EmitWeaponSound( "Weapon.Explosion_Med" )
-
- vector attackPos
- //Requires code feature to properly fire tracers from offset positions.
- //if ( vortexWeapon.GetWeaponSettingBool( eWeaponVar.is_burn_mod ) )
- // attackPos = impactData.origin
- //else
- attackPos = Vortex_GenerateRandomRefireOrigin( vortexWeapon )
-
- vector fireVec = Vortex_GenerateRandomRefireVector( vortexWeapon, VORTEX_EXP_ROUNDS_RETURN_SPREAD_XY, VORTEX_EXP_ROUNDS_RETURN_SPREAD_Z )
-
- // fire off the bolt
- entity bolt = vortexWeapon.FireWeaponBolt( attackPos, fireVec, projSpeed, damageType, damageType, PROJECTILE_NOT_PREDICTED, sequenceID )
- if ( bolt )
- {
- bolt.kv.gravity = 0.3
-
- Vortex_ProjectileCommonSetup( bolt, impactData )
- }
-
- return true
-}
-
-bool function Vortex_FireBackProjectileBullet( vortexWeapon, attackParams, impactData, sequenceID )
-{
- expect entity( vortexWeapon )
-
- // common projectile data
- float projSpeed = 12000.0
- int damageType = damageTypes.bullet | DF_VORTEX_REFIRE
-
- vortexWeapon.EmitWeaponSound( "Weapon.Explosion_Med" )
-
- vector attackPos
- //Requires code feature to properly fire tracers from offset positions.
- //if ( vortexWeapon.GetWeaponSettingBool( eWeaponVar.is_burn_mod ) )
- // attackPos = impactData.origin
- //else
- attackPos = Vortex_GenerateRandomRefireOrigin( vortexWeapon )
-
- vector fireVec = Vortex_GenerateRandomRefireVector( vortexWeapon, 0.15, 0.1 )
- //printt( Time(), fireVec ) // print for bug with random
-
- // fire off the bolt
- entity bolt = vortexWeapon.FireWeaponBolt( attackPos, fireVec, projSpeed, damageType, damageType, PROJECTILE_NOT_PREDICTED, sequenceID )
- if ( bolt )
- {
- bolt.kv.gravity = 0.0
-
- Vortex_ProjectileCommonSetup( bolt, impactData )
- }
-
- return true
-}
-
-vector function Vortex_GenerateRandomRefireOrigin( entity vortexWeapon, float distFromCenter = 3.0 )
-{
- float distFromCenter_neg = distFromCenter * -1
-
- vector attackPos = expect vector( vortexWeapon.s.vortexBulletEffectCP.GetOrigin() )
-
- float x = RandomFloatRange( distFromCenter_neg, distFromCenter )
- float y = RandomFloatRange( distFromCenter_neg, distFromCenter )
- float z = RandomFloatRange( distFromCenter_neg, distFromCenter )
-
- attackPos = attackPos + Vector( x, y, z )
-
- return attackPos
-}
-
-vector function Vortex_GenerateRandomRefireVector( entity vortexWeapon, float vecSpread, float vecSpreadZ )
-{
- float x = RandomFloatRange( vecSpread * -1, vecSpread )
- float y = RandomFloatRange( vecSpread * -1, vecSpread )
- float z = RandomFloatRange( vecSpreadZ * -1, vecSpreadZ )
-
- vector fireVec = vortexWeapon.GetWeaponOwner().GetPlayerOrNPCViewVector() + Vector( x, y, z )
- return fireVec
-}
-
-bool function Vortex_FireBackRocket( vortexWeapon, attackParams, impactData, sequenceID )
-{
- expect entity( vortexWeapon )
-
- // TODO prediction for clients
- Assert( IsServer() )
-
- entity rocket = vortexWeapon.FireWeaponMissile( attackParams.pos, attackParams.dir, 1800.0, damageTypes.largeCaliberExp | DF_VORTEX_REFIRE, damageTypes.largeCaliberExp | DF_VORTEX_REFIRE, false, PROJECTILE_NOT_PREDICTED )
-
- if ( rocket )
- {
- rocket.kv.lifetime = RandomFloatRange( 2.6, 3.5 )
-
- InitMissileForRandomDriftForVortexLow( rocket, expect vector( attackParams.pos ), expect vector( attackParams.dir ) )
-
- Vortex_ProjectileCommonSetup( rocket, impactData )
- }
-
- return true
-}
-
-bool function Vortex_FireBackGrenade( entity vortexWeapon, attackParams, impactData, int attackSeedCount, float baseFuseTime )
-{
- float x = RandomFloatRange( -0.2, 0.2 )
- float y = RandomFloatRange( -0.2, 0.2 )
- float z = RandomFloatRange( -0.2, 0.2 )
-
- vector velocity = ( expect vector( attackParams.dir ) + Vector( x, y, z ) ) * 1500
- vector angularVelocity = Vector( RandomFloatRange( -1200, 1200 ), 100, 0 )
-
- bool hasIgnitionTime = vortexImpactWeaponInfo[ impactData.weaponName ].grenade_ignition_time > 0
- float fuseTime = hasIgnitionTime ? 0.0 : baseFuseTime
- const int HARDCODED_DAMAGE_TYPE = (damageTypes.explosive | DF_VORTEX_REFIRE)
-
- entity grenade = vortexWeapon.FireWeaponGrenade( attackParams.pos, velocity, angularVelocity, fuseTime, HARDCODED_DAMAGE_TYPE, HARDCODED_DAMAGE_TYPE, PROJECTILE_NOT_PREDICTED, true, true )
- if ( grenade )
- {
- Grenade_Init( grenade, vortexWeapon )
- Vortex_ProjectileCommonSetup( grenade, impactData )
- if ( hasIgnitionTime )
- grenade.SetGrenadeIgnitionDuration( vortexImpactWeaponInfo[ impactData.weaponName ].grenade_ignition_time )
- }
-
- return (grenade ? true : false)
-}
-
-bool function DoVortexAttackForImpactData( entity vortexWeapon, attackParams, impactData, int attackSeedCount )
-{
- bool didFire = false
- switch ( impactData.refireBehavior )
- {
- case VORTEX_REFIRE_EXPLOSIVE_ROUND:
- didFire = Vortex_FireBackExplosiveRound( vortexWeapon, attackParams, impactData, attackSeedCount )
- break
-
- case VORTEX_REFIRE_ROCKET:
- didFire = Vortex_FireBackRocket( vortexWeapon, attackParams, impactData, attackSeedCount )
- break
-
- case VORTEX_REFIRE_GRENADE:
- didFire = Vortex_FireBackGrenade( vortexWeapon, attackParams, impactData, attackSeedCount, 1.25 )
- break
-
- case VORTEX_REFIRE_GRENADE_LONG_FUSE:
- didFire = Vortex_FireBackGrenade( vortexWeapon, attackParams, impactData, attackSeedCount, 10.0 )
- break
-
- case VORTEX_REFIRE_BULLET:
- didFire = Vortex_FireBackProjectileBullet( vortexWeapon, attackParams, impactData, attackSeedCount )
- break
-
- case VORTEX_REFIRE_NONE:
- break
- }
-
- return didFire
-}
-
-function Vortex_ProjectileCommonSetup( entity projectile, impactData )
-{
- // custom tag it so it shows up correctly if it hits another vortex sphere
- projectile.s.originalDamageSource <- impactData.damageSourceID
-
- Vortex_SetImpactEffectTable_OnProjectile( projectile, impactData ) // set the correct impact effect table
-
- projectile.SetVortexRefired( true ) // This tells code the projectile was refired from the vortex so that it uses "projectile_vortex_vscript"
- projectile.SetModel( GetWeaponInfoFileKeyFieldAsset_Global( impactData.weaponName, "projectilemodel" ) )
- projectile.SetWeaponClassName( impactData.weaponName ) // causes the projectile to use its normal trail FX
-
- projectile.ProjectileSetDamageSourceID( impactData.damageSourceID ) // obit will show the owner weapon
-}
-
-// gives a refired projectile the correct impact effect table
-function Vortex_SetImpactEffectTable_OnProjectile( projectile, impactData )
-{
- //Getting more info for bug 207595, don't check into Staging.
- #if DEV
- printt( "impactData.impact_effect_table ", impactData.impact_effect_table )
- if ( impactData.impact_effect_table == "" )
- PrintTable( impactData )
- #endif
-
- local fxTableHandle = GetImpactEffectTable( impactData.impact_effect_table )
-
- projectile.SetImpactEffectTable( fxTableHandle )
-}
-#endif // SERVER
-
-// absorbed bullets are tracked with a special networked kv variable because clients need to know how many bullets to fire as well, when they are doing the client version of FireWeaponBullet
-int function GetBulletsAbsorbedCount( entity vortexWeapon )
-{
- if ( !vortexWeapon )
- return 0
-
- entity vortexSphere = vortexWeapon.GetWeaponUtilityEntity()
- if ( !vortexSphere )
- return 0
-
- return vortexSphere.GetBulletAbsorbedCount()
-}
-
-int function GetProjectilesAbsorbedCount( entity vortexWeapon )
-{
- if ( !vortexWeapon )
- return 0
-
- entity vortexSphere = vortexWeapon.GetWeaponUtilityEntity()
- if ( !vortexSphere )
- return 0
-
- return vortexSphere.GetProjectileAbsorbedCount()
-}
-
-#if SERVER
-function Vortex_GetProjectileImpacts( entity vortexWeapon )
-{
- local impacts = []
- foreach ( impactData in Vortex_GetAllImpactEvents( vortexWeapon ) )
- {
- if ( impactData.impactType == "projectile" )
- impacts.append( impactData )
- }
-
- return impacts
-}
-
-function Vortex_GetHitscanBulletImpacts( entity vortexWeapon )
-{
- local impacts = []
- foreach ( impactData in Vortex_GetAllImpactEvents( vortexWeapon ) )
- {
- if ( impactData.impactType == "hitscan" )
- impacts.append( impactData )
- }
-
- return impacts
-}
-
-int function GetHitscanBulletImpactCount( entity vortexWeapon )
-{
- int count = 0
- foreach ( impactData in Vortex_GetAllImpactEvents( vortexWeapon ) )
- {
- if ( impactData.impactType == "hitscan" )
- count++
- }
-
- return count
-}
-#endif // SERVER
-
-// // lets the damage callback communicate to the attacker that he hit a vortex shield
-function Vortex_NotifyAttackerDidDamage( entity attacker, entity vortexOwner, hitPos )
-{
- if ( !IsValid( attacker ) || !attacker.IsPlayer() )
- return
-
- if ( !IsValid( vortexOwner ) )
- return
-
- Assert( hitPos )
-
- attacker.NotifyDidDamage( vortexOwner, 0, hitPos, 0, 0, DAMAGEFLAG_VICTIM_HAS_VORTEX, 0, null, 0 )
-}
-
-function SetVortexAmmo( entity vortexWeapon, count )
-{
- entity owner = vortexWeapon.GetWeaponOwner()
- if ( !IsValid_ThisFrame( owner ) )
- return
- #if CLIENT
- if ( !IsLocalViewPlayer( owner ) )
- return
- #endif
-
- vortexWeapon.SetWeaponPrimaryAmmoCount( count )
-}
-
-
-// sets the RGB color value for the vortex sphere FX based on current charge fraction
-function VortexSphereColorUpdate( entity weapon, sphereClientFXHandle = null )
-{
- weapon.EndSignal( "VortexStopping" )
-
- #if CLIENT
- Assert( sphereClientFXHandle != null )
- #endif
- bool isIonVortex = weapon.GetWeaponClassName() == "mp_titanweapon_vortex_shield_ion"
- entity weaponOwner = weapon.GetWeaponOwner()
- float energyTotal = float ( weaponOwner.GetSharedEnergyTotal() )
- while( IsValid( weapon ) && IsValid( weaponOwner ) )
- {
- vector colorVec
- if ( isIonVortex )
- {
- float energyFrac = 1.0 - float( weaponOwner.GetSharedEnergyCount() ) / energyTotal
- if ( weapon.HasMod( "pas_ion_vortex" ) )
- colorVec = GetVortexSphereCurrentColor( energyFrac, VORTEX_SPHERE_COLOR_PAS_ION_VORTEX )
- else
- colorVec = GetVortexSphereCurrentColor( energyFrac )
- }
- else
- {
- colorVec = GetVortexSphereCurrentColor( weapon.GetWeaponChargeFraction() )
- }
-
-
- // update the world entity that is linked to the world FX playing on the server
- #if SERVER
- weapon.s.vortexSphereColorCP.SetOrigin( colorVec )
- #else
- // handles the server killing the vortex sphere without the client knowing right away,
- // for example if an explosive goes off and we short circuit the charge timer
- if ( !EffectDoesExist( sphereClientFXHandle ) )
- break
-
- EffectSetControlPointVector( sphereClientFXHandle, 1, colorVec )
- #endif
-
- WaitFrame()
- }
-}
-
-vector function GetVortexSphereCurrentColor( float chargeFrac, vector fullHealthColor = VORTEX_SPHERE_COLOR_CHARGE_FULL )
-{
- return GetTriLerpColor( chargeFrac, fullHealthColor, VORTEX_SPHERE_COLOR_CHARGE_MED, VORTEX_SPHERE_COLOR_CHARGE_EMPTY )
-}
-
-vector function GetShieldTriLerpColor( float frac )
-{
- return GetTriLerpColor( frac, VORTEX_SPHERE_COLOR_CHARGE_FULL, VORTEX_SPHERE_COLOR_CHARGE_MED, VORTEX_SPHERE_COLOR_CHARGE_EMPTY )
-}
-
-vector function GetTriLerpColor( float fraction, vector color1, vector color2, vector color3 )
-{
- float crossover1 = VORTEX_SPHERE_COLOR_CROSSOVERFRAC_FULL2MED // from zero to this fraction, fade between color1 and color2
- float crossover2 = VORTEX_SPHERE_COLOR_CROSSOVERFRAC_MED2EMPTY // from crossover1 to this fraction, fade between color2 and color3
-
- float r, g, b
-
- // 0 = full charge, 1 = no charge remaining
- if ( fraction < crossover1 )
- {
- r = Graph( fraction, 0, crossover1, color1.x, color2.x )
- g = Graph( fraction, 0, crossover1, color1.y, color2.y )
- b = Graph( fraction, 0, crossover1, color1.z, color2.z )
- return <r, g, b>
- }
- else if ( fraction < crossover2 )
- {
- r = Graph( fraction, crossover1, crossover2, color2.x, color3.x )
- g = Graph( fraction, crossover1, crossover2, color2.y, color3.y )
- b = Graph( fraction, crossover1, crossover2, color2.z, color3.z )
- return <r, g, b>
- }
- else
- {
- // for the last bit of overload timer, keep it max danger color
- r = color3.x
- g = color3.y
- b = color3.z
- return <r, g, b>
- }
-
- unreachable
-}
-
-// generic impact validation
-#if SERVER
-bool function ValidateVortexImpact( entity vortexSphere, entity projectile = null )
-{
- Assert( IsServer() )
-
- if ( !IsValid( vortexSphere ) )
- return false
-
- if ( !vortexSphere.GetOwnerWeapon() )
- return false
-
- entity vortexWeapon = vortexSphere.GetOwnerWeapon()
- if ( !IsValid( vortexWeapon ) )
- return false
-
- if ( projectile )
- {
- if ( !IsValid_ThisFrame( projectile ) )
- return false
-
- if ( projectile.ProjectileGetWeaponInfoFileKeyField( "projectile_ignores_vortex" ) == 1 )
- return false
-
- if ( projectile.ProjectileGetWeaponClassName() == "" )
- return false
-
- // TEMP HACK
- if ( projectile.ProjectileGetWeaponClassName() == "mp_weapon_tether" )
- return false
- }
-
- return true
-}
-#endif
-
-/********************************/
-/* Setting override functions */
-/********************************/
-
-function Vortex_SetTagName( entity weapon, string tagName )
-{
- Vortex_SetWeaponSettingOverride( weapon, "vortexTagName", tagName )
-}
-
-function Vortex_SetBulletCollectionOffset( entity weapon, vector offset )
-{
- Vortex_SetWeaponSettingOverride( weapon, "bulletCollectionOffset", offset )
-}
-
-function Vortex_SetWeaponSettingOverride( entity weapon, string setting, value )
-{
- if ( !( setting in weapon.s ) )
- weapon.s[ setting ] <- null
- weapon.s[ setting ] = value
-}
-
-string function GetVortexTagName( entity weapon )
-{
- if ( "vortexTagName" in weapon.s )
- return expect string( weapon.s.vortexTagName )
-
- return "vortex_center"
-}
-
-vector function GetBulletCollectionOffset( entity weapon )
-{
- if ( "bulletCollectionOffset" in weapon.s )
- return expect vector( weapon.s.bulletCollectionOffset )
-
- entity owner = weapon.GetWeaponOwner()
- if ( owner.IsTitan() )
- return Vector( 300.0, -90.0, -70.0 )
- else
- return Vector( 80.0, 17.0, -11.0 )
-
- unreachable
-}
-
-
-#if SERVER
-function VortexSphereDrainHealthForDamage( entity vortexSphere, damage )
-{
- // don't drain the health of vortex_spheres that are set to be invulnerable. This is the case for the Particle Wall
- if ( vortexSphere.IsInvulnerable() )
- return
-
- local result = {}
- result.damage <- damage
- vortexSphere.Signal( "Script_OnDamaged", result )
-
- int currentHealth = vortexSphere.GetHealth()
- Assert( damage >= 0 )
- // JFS to fix phone home bug; we never hit the assert above locally...
- damage = max( damage, 0 )
- vortexSphere.SetHealth( currentHealth - damage )
-
- entity vortexWeapon = vortexSphere.GetOwnerWeapon()
- if ( IsValid( vortexWeapon ) && vortexWeapon.HasMod( "fd_gun_shield_redirect" ) )
- {
- entity owner = vortexWeapon.GetWeaponOwner()
- if ( IsValid( owner ) && owner.IsTitan() )
- {
- entity soul = owner.GetTitanSoul()
- if ( IsValid( soul ) )
- {
- int shieldRestoreAmount = int( damage ) //Might need tuning
- soul.SetShieldHealth( min( soul.GetShieldHealth() + shieldRestoreAmount, soul.GetShieldHealthMax() ) )
- }
- }
- }
-
- UpdateShieldWallColorForFrac( vortexSphere.e.shieldWallFX, GetHealthFrac( vortexSphere ) )
-}
-#endif
-
-
-bool function CodeCallback_OnVortexHitBullet( entity weapon, entity vortexSphere, var damageInfo )
-{
- bool isAmpedWall = vortexSphere.GetTargetName() == PROTO_AMPED_WALL
- bool takesDamage = !isAmpedWall
- bool adjustImpactAngles = !(vortexSphere.GetTargetName() == GUN_SHIELD_WALL)
-
- #if SERVER
- if ( vortexSphere.e.BulletHitRules != null )
- {
- vortexSphere.e.BulletHitRules( vortexSphere, damageInfo )
- takesDamage = takesDamage && (DamageInfo_GetDamage( damageInfo ) > 0)
- }
- #endif
-
- vector damageAngles = vortexSphere.GetAngles()
-
- if ( adjustImpactAngles )
- damageAngles = AnglesCompose( damageAngles, Vector( 90, 0, 0 ) )
-
- int teamNum = vortexSphere.GetTeam()
-
- #if CLIENT
- vector damageOrigin = DamageInfo_GetDamagePosition( damageInfo )
- if ( !isAmpedWall )
- {
- // TODO: slightly change angles to match radius rotation of vortex cylinder
- int effectHandle = StartParticleEffectInWorldWithHandle( GetParticleSystemIndex( SHIELD_WALL_BULLET_FX ), damageOrigin, damageAngles )
- //local color = GetShieldTriLerpColor( 1 - GetHealthFrac( vortexSphere ) )
- vector color = GetShieldTriLerpColor( 0.0 )
- EffectSetControlPointVector( effectHandle, 1, color )
- }
-
- if ( takesDamage )
- {
- float damage = ceil( DamageInfo_GetDamage( damageInfo ) )
- int damageType = DamageInfo_GetCustomDamageType( damageInfo )
- DamageFlyout( damage, damageOrigin, vortexSphere, false, false )
- }
-
- if ( DamageInfo_GetAttacker( damageInfo ) && DamageInfo_GetAttacker( damageInfo ).IsTitan() )
- EmitSoundAtPosition( teamNum, DamageInfo_GetDamagePosition( damageInfo ), "TitanShieldWall.Heavy.BulletImpact_1P_vs_3P" )
- else
- EmitSoundAtPosition( teamNum, DamageInfo_GetDamagePosition( damageInfo ), "TitanShieldWall.Light.BulletImpact_1P_vs_3P" )
- #else
- if ( !isAmpedWall )
- {
- int fxId = GetParticleSystemIndex( SHIELD_WALL_BULLET_FX )
- PlayEffectOnVortexSphere( fxId, DamageInfo_GetDamagePosition( damageInfo ), damageAngles, vortexSphere )
- }
-
- entity weapon = DamageInfo_GetWeapon( damageInfo )
- float damage = ceil( DamageInfo_GetDamage( damageInfo ) )
-
- Assert( damage >= 0, "Bug 159851 - Damage should be greater than or equal to 0.")
- damage = max( 0.0, damage )
-
- if ( IsValid( weapon ) )
- damage = HandleWeakToPilotWeapons( vortexSphere, weapon.GetWeaponClassName(), damage )
-
- if ( takesDamage )
- {
- //JFS - Arc Round bug fix for Monarch. Projectiles vortex callback doesn't even have damageInfo, so the shield modifier here doesn't exist in VortexSphereDrainHealthForDamage like it should.
- ShieldDamageModifier damageModifier = GetShieldDamageModifier( damageInfo )
- damage *= damageModifier.damageScale
- VortexSphereDrainHealthForDamage( vortexSphere, damage )
- }
-
- if ( DamageInfo_GetAttacker( damageInfo ) && DamageInfo_GetAttacker( damageInfo ).IsTitan() )
- EmitSoundAtPosition( teamNum, DamageInfo_GetDamagePosition( damageInfo ), "TitanShieldWall.Heavy.BulletImpact_3P_vs_3P" )
- else
- EmitSoundAtPosition( teamNum, DamageInfo_GetDamagePosition( damageInfo ), "TitanShieldWall.Light.BulletImpact_3P_vs_3P" )
- #endif
-
- if ( isAmpedWall )
- {
- #if SERVER
- DamageInfo_ScaleDamage( damageInfo, AMPED_DAMAGE_SCALAR )
- #endif
- return false
- }
-
- return true
-}
-
-bool function OnVortexHitBullet_BubbleShieldNPC( entity vortexSphere, var damageInfo )
-{
- vector vortexOrigin = vortexSphere.GetOrigin()
- vector damageOrigin = DamageInfo_GetDamagePosition( damageInfo )
-
- float distSq = DistanceSqr( vortexOrigin, damageOrigin )
- if ( distSq < MINION_BUBBLE_SHIELD_RADIUS_SQR )
- return false//the damage is coming from INSIDE the sphere
-
- vector damageVec = damageOrigin - vortexOrigin
- vector damageAngles = VectorToAngles( damageVec )
- damageAngles = AnglesCompose( damageAngles, Vector( 90, 0, 0 ) )
-
- int teamNum = vortexSphere.GetTeam()
-
- #if CLIENT
- int effectHandle = StartParticleEffectInWorldWithHandle( GetParticleSystemIndex( SHIELD_WALL_BULLET_FX ), damageOrigin, damageAngles )
-
- vector color = GetShieldTriLerpColor( 0.9 )
- EffectSetControlPointVector( effectHandle, 1, color )
-
- if ( DamageInfo_GetAttacker( damageInfo ) && DamageInfo_GetAttacker( damageInfo ).IsTitan() )
- EmitSoundAtPosition( teamNum, DamageInfo_GetDamagePosition( damageInfo ), "TitanShieldWall.Heavy.BulletImpact_1P_vs_3P" )
- else
- EmitSoundAtPosition( teamNum, DamageInfo_GetDamagePosition( damageInfo ), "TitanShieldWall.Light.BulletImpact_1P_vs_3P" )
- #else
- int fxId = GetParticleSystemIndex( SHIELD_WALL_BULLET_FX )
- PlayEffectOnVortexSphere( fxId, DamageInfo_GetDamagePosition( damageInfo ), damageAngles, vortexSphere )
- //VortexSphereDrainHealthForDamage( vortexSphere, DamageInfo_GetWeapon( damageInfo ), null )
-
- if ( DamageInfo_GetAttacker( damageInfo ) && DamageInfo_GetAttacker( damageInfo ).IsTitan() )
- EmitSoundAtPosition( teamNum, DamageInfo_GetDamagePosition( damageInfo ), "TitanShieldWall.Heavy.BulletImpact_3P_vs_3P" )
- else
- EmitSoundAtPosition( teamNum, DamageInfo_GetDamagePosition( damageInfo ), "TitanShieldWall.Light.BulletImpact_3P_vs_3P" )
- #endif
- return true
-}
-
-bool function CodeCallback_OnVortexHitProjectile( entity weapon, entity vortexSphere, entity attacker, entity projectile, vector contactPos )
-{
- // code shouldn't call this on an invalid vortexsphere!
- if ( !IsValid( vortexSphere ) )
- return false
-
- var ignoreVortex = projectile.ProjectileGetWeaponInfoFileKeyField( "projectile_ignores_vortex" )
- if ( ignoreVortex != null )
- {
- #if SERVER
- if ( projectile.proj.hasBouncedOffVortex )
- return false
-
- vector velocity = projectile.GetVelocity()
- vector multiplier
-
- switch ( ignoreVortex )
- {
- case "drop":
- multiplier = < -0.25, -0.25, 0.0 >
- break
-
- case "fall_vortex":
- case "fall":
- multiplier = < -0.25, -0.25, -0.25 >
- break
-
- case "mirror":
- // bounce back, assume along xy axis
- multiplier = < -1.0, -1.0, 1.0 >
- break
-
- default:
- CodeWarning( "Unknown projectile_ignores_vortex " + ignoreVortex )
- break
- }
-
- velocity = < velocity.x * multiplier.x, velocity.y * multiplier.y, velocity.z * multiplier.z >
- projectile.proj.hasBouncedOffVortex = true
- projectile.SetVelocity( velocity )
- #endif
- return false
- }
-
- bool adjustImpactAngles = !(vortexSphere.GetTargetName() == GUN_SHIELD_WALL)
-
- vector damageAngles = vortexSphere.GetAngles()
-
- if ( adjustImpactAngles )
- damageAngles = AnglesCompose( damageAngles, Vector( 90, 0, 0 ) )
-
- asset projectileSettingFX = projectile.GetProjectileWeaponSettingAsset( eWeaponVar.vortex_impact_effect )
- asset impactFX = (projectileSettingFX != $"") ? projectileSettingFX : SHIELD_WALL_EXPMED_FX
-
- bool isAmpedWall = vortexSphere.GetTargetName() == PROTO_AMPED_WALL
- bool takesDamage = !isAmpedWall
-
- #if SERVER
- if ( vortexSphere.e.ProjectileHitRules != null )
- takesDamage = vortexSphere.e.ProjectileHitRules( vortexSphere, attacker, takesDamage )
- #endif
- // hack to let client know about amped wall, and to amp the shot
- if ( isAmpedWall )
- impactFX = AMPED_WALL_IMPACT_FX
-
- int teamNum = vortexSphere.GetTeam()
-
- #if CLIENT
- if ( !isAmpedWall )
- {
- int effectHandle = StartParticleEffectInWorldWithHandle( GetParticleSystemIndex( impactFX ), contactPos, damageAngles )
- //local color = GetShieldTriLerpColor( 1 - GetHealthFrac( vortexSphere ) )
- vector color = GetShieldTriLerpColor( 0.0 )
- EffectSetControlPointVector( effectHandle, 1, color )
- }
-
- var impact_sound_1p = projectile.ProjectileGetWeaponInfoFileKeyField( "vortex_impact_sound_1p" )
- if ( impact_sound_1p == null )
- impact_sound_1p = "TitanShieldWall.Explosive.BulletImpact_1P_vs_3P"
-
- EmitSoundAtPosition( teamNum, contactPos, impact_sound_1p )
- #else
- if ( !isAmpedWall )
- {
- int fxId = GetParticleSystemIndex( impactFX )
- PlayEffectOnVortexSphere( fxId, contactPos, damageAngles, vortexSphere )
- }
-
- float damage = float( projectile.GetProjectileWeaponSettingInt( eWeaponVar.damage_near_value ) )
- // once damageInfo is passed correctly we'll use that instead of looking up the values from the weapon .txt file.
- // local damage = ceil( DamageInfo_GetDamage( damageInfo ) )
-
- damage = HandleWeakToPilotWeapons( vortexSphere, projectile.ProjectileGetWeaponClassName(), damage )
- damage = damage + CalculateTitanSniperExtraDamage( projectile, vortexSphere )
-
- if ( takesDamage )
- {
- VortexSphereDrainHealthForDamage( vortexSphere, damage )
- if ( IsValid( attacker ) && attacker.IsPlayer() )
- attacker.NotifyDidDamage( vortexSphere, 0, contactPos, 0, damage, DF_NO_HITBEEP, 0, null, 0 )
- }
-
- var impact_sound_3p = projectile.ProjectileGetWeaponInfoFileKeyField( "vortex_impact_sound_3p" )
-
- if ( impact_sound_3p == null )
- impact_sound_3p = "TitanShieldWall.Explosive.BulletImpact_3P_vs_3P"
-
- EmitSoundAtPosition( teamNum, contactPos, impact_sound_3p )
-
- int damageSourceID = projectile.ProjectileGetDamageSourceID()
- switch ( damageSourceID )
- {
- case eDamageSourceId.mp_titanweapon_dumbfire_rockets:
- vector normal = projectile.GetVelocity() * -1
- normal = Normalize( normal )
- ClusterRocket_Detonate( projectile, normal )
- CreateNoSpawnArea( TEAM_INVALID, TEAM_INVALID, contactPos, ( CLUSTER_ROCKET_BURST_COUNT / 5.0 ) * 0.5 + 1.0, CLUSTER_ROCKET_BURST_RANGE + 100 )
- break
-
- case eDamageSourceId.mp_weapon_grenade_electric_smoke:
- ElectricGrenadeSmokescreen( projectile, FX_ELECTRIC_SMOKESCREEN_PILOT_AIR )
- break
-
- case eDamageSourceId.mp_weapon_grenade_emp:
-
- if ( StatusEffect_Get( vortexSphere, eStatusEffect.destroyed_by_emp ) )
- VortexSphereDrainHealthForDamage( vortexSphere, vortexSphere.GetHealth() )
- break
-
- case eDamageSourceId.mp_titanability_sonar_pulse:
- if ( IsValid( attacker ) && attacker.IsTitan() )
- {
- int team = attacker.GetTeam()
- PulseLocation( attacker, team, contactPos, false, false )
- array<string> mods = projectile.ProjectileGetMods()
- if ( mods.contains( "pas_tone_sonar" ) )
- thread DelayedPulseLocation( attacker, team, contactPos, false, false )
- }
- break
-
- }
- #endif
-
- // hack to let client know about amped wall, and to amp the shot
- if ( isAmpedWall )
- {
- #if SERVER
- projectile.proj.damageScale = AMPED_DAMAGE_SCALAR
- #endif
-
- return false
- }
-
- return true
-}
-
-bool function OnVortexHitProjectile_BubbleShieldNPC( entity vortexSphere, entity attacker, entity projectile, vector contactPos )
-{
- vector vortexOrigin = vortexSphere.GetOrigin()
-
- float dist = DistanceSqr( vortexOrigin, contactPos )
- if ( dist < MINION_BUBBLE_SHIELD_RADIUS_SQR )
- return false // the damage is coming from INSIDE THE SPHERE
-
- vector damageVec = Normalize( contactPos - vortexOrigin )
- vector damageAngles = VectorToAngles( damageVec )
- damageAngles = AnglesCompose( damageAngles, Vector( 90, 0, 0 ) )
-
- asset projectileSettingFX = projectile.GetProjectileWeaponSettingAsset( eWeaponVar.vortex_impact_effect )
- asset impactFX = (projectileSettingFX != $"") ? projectileSettingFX : SHIELD_WALL_EXPMED_FX
-
- int teamNum = vortexSphere.GetTeam()
-
- #if CLIENT
- int effectHandle = StartParticleEffectInWorldWithHandle( GetParticleSystemIndex( impactFX ), contactPos, damageAngles )
-
- vector color = GetShieldTriLerpColor( 0.9 )
- EffectSetControlPointVector( effectHandle, 1, color )
-
- EmitSoundAtPosition( teamNum, contactPos, "TitanShieldWall.Explosive.BulletImpact_1P_vs_3P" )
- #else
- int fxId = GetParticleSystemIndex( impactFX )
- PlayEffectOnVortexSphere( fxId, contactPos, damageAngles, vortexSphere )
-// VortexSphereDrainHealthForDamage( vortexSphere, null, projectile )
-
- EmitSoundAtPosition( teamNum, contactPos, "TitanShieldWall.Explosive.BulletImpact_3P_vs_3P" )
-
- if ( projectile.ProjectileGetDamageSourceID() == eDamageSourceId.mp_titanweapon_dumbfire_rockets )
- {
- vector normal = projectile.GetVelocity() * -1
- normal = Normalize( normal )
- ClusterRocket_Detonate( projectile, normal )
- CreateNoSpawnArea( TEAM_INVALID, TEAM_INVALID, contactPos, ( CLUSTER_ROCKET_BURST_COUNT / 5.0 ) * 0.5 + 1.0, CLUSTER_ROCKET_BURST_RANGE + 100 )
- }
- #endif
- return true
-}
-
-#if SERVER
-float function HandleWeakToPilotWeapons( entity vortexSphere, string weaponName, float damage )
-{
- if ( vortexSphere.e.proto_weakToPilotWeapons ) //needs code for real, but this is fine for prototyping
- {
- // is weapon a pilot weapon?
- local refType = GetWeaponInfoFileKeyField_Global( weaponName, "weaponClass" )
- if ( refType == "human" )
- {
- damage *= VORTEX_PILOT_WEAPON_WEAKNESS_DAMAGESCALE
- }
- }
-
- return damage
-}
-#endif
-
-// ???: reflectOrigin not used
-int function VortexReflectAttack( entity vortexWeapon, attackParams, vector reflectOrigin )
-{
- entity vortexSphere = vortexWeapon.GetWeaponUtilityEntity()
- if ( !vortexSphere )
- return 0
-
- #if SERVER
- Assert( vortexSphere )
- #endif
-
- int totalfired = 0
- int totalAttempts = 0
-
- bool forceReleased = false
- // in this case, it's also considered "force released" if the charge time runs out
- if ( vortexWeapon.IsForceRelease() || vortexWeapon.GetWeaponChargeFraction() == 1 )
- forceReleased = true
-
- //Requires code feature to properly fire tracers from offset positions.
- //if ( vortexWeapon.GetWeaponSettingBool( eWeaponVar.is_burn_mod ) )
- // attackParams.pos = reflectOrigin
-
- // PREDICTED REFIRES
- // bullet impact events don't individually fire back per event because we aggregate and then shotgun blast them
-
- //Remove the below script after FireWeaponBulletBroadcast
- //local bulletsFired = Vortex_FireBackBullets( vortexWeapon, attackParams )
- //totalfired += bulletsFired
- int bulletCount = GetBulletsAbsorbedCount( vortexWeapon )
- if ( bulletCount > 0 )
- {
- if ( "ampedBulletCount" in vortexWeapon.s )
- vortexWeapon.s.ampedBulletCount++
- else
- vortexWeapon.s.ampedBulletCount <- 1
- vortexWeapon.Signal( "FireAmpedVortexBullet" )
- totalfired += 1
- }
-
- // UNPREDICTED REFIRES
- #if SERVER
- //printt( "server: force released?", forceReleased )
-
- local unpredictedRefires = Vortex_GetProjectileImpacts( vortexWeapon )
-
- // HACK we don't actually want to refire them with a spiral but
- // this is to temporarily ensure compatibility with the Titan rocket launcher
- if ( !( "spiralMissileIdx" in vortexWeapon.s ) )
- vortexWeapon.s.spiralMissileIdx <- null
- vortexWeapon.s.spiralMissileIdx = 0
- foreach ( impactData in unpredictedRefires )
- {
- bool didFire = DoVortexAttackForImpactData( vortexWeapon, attackParams, impactData, totalAttempts )
- if ( didFire )
- totalfired++
- totalAttempts++
- }
- #endif
-
- SetVortexAmmo( vortexWeapon, 0 )
- vortexWeapon.Signal( "VortexFired" )
-
-#if SERVER
- vortexSphere.ClearAllBulletsFromSphere()
-#endif
-
- /*
- if ( forceReleased )
- DestroyVortexSphereFromVortexWeapon( vortexWeapon )
- else
- DisableVortexSphereFromVortexWeapon( vortexWeapon )
- */
-
- return totalfired
-} \ No newline at end of file