diff options
author | BobTheBob <32057864+BobTheBob9@users.noreply.github.com> | 2021-08-31 23:14:58 +0100 |
---|---|---|
committer | BobTheBob <32057864+BobTheBob9@users.noreply.github.com> | 2021-08-31 23:14:58 +0100 |
commit | 9a96d0bff56f1969c68bb52a2f33296095bdc67d (patch) | |
tree | 4175928e488632705692e3cccafa1a38dd854615 /Northstar.CustomServers/scripts/vscripts/weapons/_vortex.nut | |
parent | 27bd240871b7c0f2f49fef137718b2e3c208e3b4 (diff) | |
download | NorthstarMods-9a96d0bff56f1969c68bb52a2f33296095bdc67d.tar.gz NorthstarMods-9a96d0bff56f1969c68bb52a2f33296095bdc67d.zip |
move to new mod format
Diffstat (limited to 'Northstar.CustomServers/scripts/vscripts/weapons/_vortex.nut')
-rw-r--r-- | Northstar.CustomServers/scripts/vscripts/weapons/_vortex.nut | 1983 |
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 |