aboutsummaryrefslogtreecommitdiff
path: root/Northstar.Custom/mod/scripts/vscripts
diff options
context:
space:
mode:
authorMasterliberty <94194459+Masterliberty@users.noreply.github.com>2023-07-16 17:08:43 -0400
committerGitHub <noreply@github.com>2023-07-16 23:08:43 +0200
commit4c5cd0bf73b4672b0a5682aa2039fa16d7341893 (patch)
treec9ac4283929489af49f09a1a8f485888c9e6300d /Northstar.Custom/mod/scripts/vscripts
parent6cd9b2312bca0f4568c47568962a0601f36c8fd7 (diff)
downloadNorthstarMods-4c5cd0bf73b4672b0a5682aa2039fa16d7341893.tar.gz
NorthstarMods-4c5cd0bf73b4672b0a5682aa2039fa16d7341893.zip
Add Arc cannon (#600)v1.17.0-rc1
Adds the Arc Cannon from Titanfall1
Diffstat (limited to 'Northstar.Custom/mod/scripts/vscripts')
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut1
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut1085
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut223
3 files changed, 729 insertions, 580 deletions
diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut
index 79e64684..b8d4b1ba 100644
--- a/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut
+++ b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut
@@ -4,6 +4,7 @@ void function NorthstarCustomPrecache()
{
PrecacheWeapon( "mp_weapon_peacekraber" )
PrecacheWeapon( "mp_titanweapon_triplethreat" )
+ PrecacheWeapon( "mp_titanweapon_arc_cannon" )
PrecacheWeapon( "melee_pilot_kunai" )
RegisterWeaponDamageSources(
diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut
index 4268422e..cd58ef06 100644
--- a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut
+++ b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut
@@ -1,257 +1,218 @@
+untyped
+
+global function ArcCannon_Init
+
+global function ArcCannon_PrecacheFX
+global function ArcCannon_Start
+global function ArcCannon_Stop
+global function ArcCannon_ChargeBegin
+global function ArcCannon_ChargeEnd
+global function FireArcCannon
+global function ArcCannon_HideIdleEffect
+#if SERVER
+ global function AddToArcCannonTargets
+ global function RemoveArcCannonTarget
+ global function ConvertTitanShieldIntoBonusCharge
+#endif
+global function GetArcCannonChargeFraction
+
+global function IsEntANeutralMegaTurret
+global function CreateArcCannonBeam
+
// Aiming & Range
-const DEFAULT_ARC_CANNON_FOVDOT = 0.98 // First target must be within this dot to be zapped and start a chain
-const DEFAULT_ARC_CANNON_FOVDOT_MISSILE = 0.95 // First target must be within this dot to be zapped and start a chain ( if it's a missile, we allow more leaniency )
-const ARC_CANNON_RANGE_CHAIN = 400 // Max distance we can arc from one target to another
-const ARC_CANNON_TITAN_RANGE_CHAIN = 900 // Max distance we can arc from one target to another
-const ARC_CANNON_CHAIN_COUNT_MIN = 5 // Max number of chains at no charge
-const ARC_CANNON_CHAIN_COUNT_MAX = 5 // Max number of chains at full charge
-const ARC_CANNON_CHAIN_COUNT_NPC = 2 // Number of chains when an NPC fires the weapon
-const ARC_CANNON_FORK_COUNT_MAX = 1 // Number of forks that can come out of one target to other targets
-const ARC_CANNON_FORK_DELAY = 0.1
-
-const ARC_CANNON_RANGE_CHAIN_BURN = 400
-const ARC_CANNON_TITAN_RANGE_CHAIN_BURN = 900
-const ARC_CANNON_CHAIN_COUNT_MIN_BURN = 100 // Max number of chains at no charge
-const ARC_CANNON_CHAIN_COUNT_MAX_BURN = 100 // Max number of chains at full charge
-const ARC_CANNON_CHAIN_COUNT_NPC_BURN = 10 // Number of chains when an NPC fires the weapon
-const ARC_CANNON_FORK_COUNT_MAX_BURN = 10 // Number of forks that can come out of one target to other targets
-const ARC_CANNON_BEAM_LIFETIME_BURN = 1
+global const DEFAULT_ARC_CANNON_FOVDOT = 0.98 // First target must be within this dot to be zapped and start a chain
+global const DEFAULT_ARC_CANNON_FOVDOT_MISSILE = 0.95 // First target must be within this dot to be zapped and start a chain ( if it's a missile, we allow more leaniency )
+global const ARC_CANNON_RANGE_CHAIN = 400 // Max distance we can arc from one target to another
+global const ARC_CANNON_TITAN_RANGE_CHAIN = 900 // Max distance we can arc from one target to another
+global const ARC_CANNON_CHAIN_COUNT_MIN = 5 // Max number of chains at no charge
+global const ARC_CANNON_CHAIN_COUNT_MAX = 5 // Max number of chains at full charge
+global const ARC_CANNON_CHAIN_COUNT_NPC = 2 // Number of chains when an NPC fires the weapon
+global const ARC_CANNON_FORK_COUNT_MAX = 1 // Number of forks that can come out of one target to other targets
+global const ARC_CANNON_FORK_DELAY = 0.1
+
+global const ARC_CANNON_RANGE_CHAIN_BURN = 400
+global const ARC_CANNON_TITAN_RANGE_CHAIN_BURN = 900
+global const ARC_CANNON_CHAIN_COUNT_MIN_BURN = 100 // Max number of chains at no charge
+global const ARC_CANNON_CHAIN_COUNT_MAX_BURN = 100 // Max number of chains at full charge
+global const ARC_CANNON_CHAIN_COUNT_NPC_BURN = 10 // Number of chains when an NPC fires the weapon
+global const ARC_CANNON_FORK_COUNT_MAX_BURN = 10 // Number of forks that can come out of one target to other targets
+global const ARC_CANNON_BEAM_LIFETIME_BURN = 1
// Visual settings
-const ARC_CANNON_BOLT_RADIUS_MIN = 32 // Bolt radius at no charge ( not actually sure what this does to the beam lol )
-const ARC_CANNON_BOLT_RADIUS_MAX = 640 // Bold radius at full charge ( not actually sure what this does to the beam lol )
-const ARC_CANNON_BOLT_WIDTH_MIN = 1 // Bolt width at no charge
-const ARC_CANNON_BOLT_WIDTH_MAX = 26 // Bolt width at full charge
-const ARC_CANNON_BOLT_WIDTH_NPC = 8 // Bolt width when used by NPC
-const ARC_CANNON_BEAM_COLOR = "150 190 255"
-const ARC_CANNON_BEAM_LIFETIME = 0.75
+global const ARC_CANNON_BOLT_RADIUS_MIN = 32 // Bolt radius at no charge ( not actually sure what this does to the beam lol )
+global const ARC_CANNON_BOLT_RADIUS_MAX = 640 // Bold radius at full charge ( not actually sure what this does to the beam lol )
+global const ARC_CANNON_BOLT_WIDTH_MIN = 1 // Bolt width at no charge
+global const ARC_CANNON_BOLT_WIDTH_MAX = 26 // Bolt width at full charge
+global const ARC_CANNON_BOLT_WIDTH_NPC = 8 // Bolt width when used by NPC
+global const ARC_CANNON_BEAM_COLOR = "150 190 255"
+global const ARC_CANNON_BEAM_LIFETIME = 0.75
// Player Effects
-const ARC_CANNON_TITAN_SCREEN_SFX = "Weapon_R1_LaserMine.Activate"
-const ARC_CANNON_PILOT_SCREEN_SFX = "Weapon_R1_LaserMine.Activate"
-const ARC_CANNON_EMP_DURATION_MIN = 0.1
-const ARC_CANNON_EMP_DURATION_MAX = 1.8
-const ARC_CANNON_EMP_FADEOUT_DURATION = 0.4
-const ARC_CANNON_SCREEN_EFFECTS_MIN = 0.025
-const ARC_CANNON_SCREEN_EFFECTS_MAX = 0.075
-const ARC_CANNON_SCREEN_THRESHOLD = 0.3385
-const ARC_CANNON_SLOW_SCALE_MIN = 0.8
-const ARC_CANNON_SLOW_SCALE_MAX = 0.7
-const ARC_CANNON_3RD_PERSON_EFFECT_MIN_DURATION = 0.2
-
-// Rumble
-const ARC_CANNON_RUMBLE_CHARGE_MIN = 5
-const ARC_CANNON_RUMBLE_CHARGE_MAX = 50
-const ARC_CANNON_RUMBLE_TYPE_INDEX = 14 // These are defined in code, 14 = RUMBLE_FLAT_BOTH
+global const ARC_CANNON_TITAN_SCREEN_SFX = "Null_Remove_SoundHook"
+global const ARC_CANNON_PILOT_SCREEN_SFX = "Null_Remove_SoundHook"
+global const ARC_CANNON_EMP_DURATION_MIN = 0.1
+global const ARC_CANNON_EMP_DURATION_MAX = 1.8
+global const ARC_CANNON_EMP_FADEOUT_DURATION = 0.4
+global const ARC_CANNON_SCREEN_EFFECTS_MIN = 0.01
+global const ARC_CANNON_SCREEN_EFFECTS_MAX = 0.02
+global const ARC_CANNON_SCREEN_THRESHOLD = 0.3385
+global const ARC_CANNON_3RD_PERSON_EFFECT_MIN_DURATION = 0.2
// Damage
-const ARC_CANNON_DAMAGE_FALLOFF_SCALER = 0.75 // Amount of damage carried on to the next target in the chain lightning. If 0.75, then a target that would normally take 100 damage will take 75 damage if they are one chain deep, or 56 damage if 2 levels deep
-const ARC_CANNON_DAMAGE_CHARGE_RATIO = 0.85 // What amount of charge is required for full damage.
-const ARC_CANNON_DAMAGE_CHARGE_RATIO_BURN = 0.676 // What amount of charge is required for full damage.
-const ARC_CANNON_CAPACITOR_CHARGE_RATIO = 1.0
+global const ARC_CANNON_DAMAGE_FALLOFF_SCALER = 0.75 // Amount of damage carried on to the next target in the chain lightning. If 0.75, then a target that would normally take 100 damage will take 75 damage if they are one chain deep, or 56 damage if 2 levels deep
+global const ARC_CANNON_DAMAGE_CHARGE_RATIO = 0.85 // What amount of charge is required for full damage.
+global const ARC_CANNON_DAMAGE_CHARGE_RATIO_BURN = 0.676 // What amount of charge is required for full damage.
+global const ARC_CANNON_CAPACITOR_CHARGE_RATIO = 1.0
// Options
-const ARC_CANNON_TARGETS_MISSILES = 1 // 1 = arc cannon zaps missiles that are active, 0 = missiles are ignored by arc cannon
+global const ARC_CANNON_TARGETS_MISSILES = 1 // 1 = arc cannon zaps missiles that are active, 0 = missiles are ignored by arc cannon
//Mods
-const OVERCHARGE_MAX_SHIELD_DECAY = 0.2
-const OVERCHARGE_SHIELD_DECAY_MULTIPLIER = 0.04
-const OVERCHARGE_BONUS_CHARGE_FRACTION = 0.05
-
-const SPLITTER_DAMAGE_FALLOFF_SCALER = 0.6
-const SPLITTER_FORK_COUNT_MAX = 10
-
-const ARC_CANNON_SIGNAL_DEACTIVATED = "ArcCannonDeactivated"
-RegisterSignal( ARC_CANNON_SIGNAL_DEACTIVATED )
-
-const ARC_CANNON_SIGNAL_CHARGEEND = "ArcCannonChargeEnd"
-RegisterSignal( ARC_CANNON_SIGNAL_CHARGEEND )
-
-const ARC_CANNON_BEAM_EFFECT = "wpn_arc_cannon_beam"
-PrecacheParticleSystem( ARC_CANNON_BEAM_EFFECT )
-
-const ARC_CANNON_BEAM_EFFECT_MOD = "wpn_arc_cannon_beam_mod"
-PrecacheParticleSystem( ARC_CANNON_BEAM_EFFECT_MOD )
+global const OVERCHARGE_MAX_SHIELD_DECAY = 0.2
+global const OVERCHARGE_SHIELD_DECAY_MULTIPLIER = 0.04
+global const OVERCHARGE_BONUS_CHARGE_FRACTION = 0.05
+
+global const SPLITTER_DAMAGE_FALLOFF_SCALER = 0.6
+global const SPLITTER_FORK_COUNT_MAX = 10
+
+global const ARC_CANNON_SIGNAL_DEACTIVATED = "ArcCannonDeactivated"
+global const ARC_CANNON_SIGNAL_CHARGEEND = "ArcCannonChargeEnd"
+
+global const ARC_CANNON_BEAM_EFFECT = $"wpn_arc_cannon_beam"
+global const ARC_CANNON_BEAM_EFFECT_MOD = $"wpn_arc_cannon_beam_mod"
+
+global const ARC_CANNON_FX_TABLE = "exp_arc_cannon"
+
+global const ArcCannonTargetClassnames = {
+ [ "npc_drone" ] = true,
+ [ "npc_dropship" ] = true,
+ [ "npc_marvin" ] = true,
+ [ "npc_prowler" ] = true,
+ [ "npc_soldier" ] = true,
+ [ "npc_soldier_heavy" ] = true,
+ [ "npc_soldier_shield" ] = true,
+ [ "npc_spectre" ] = true,
+ [ "npc_stalker" ] = true,
+ [ "npc_super_spectre" ] = true,
+ [ "npc_titan" ] = true,
+ [ "npc_turret_floor" ] = true,
+ [ "npc_turret_mega" ] = true,
+ [ "npc_turret_sentry" ] = true,
+ [ "npc_frag_drone" ] = true,
+ [ "player" ] = true,
+ [ "prop_dynamic" ] = true,
+ [ "prop_script" ] = true,
+ [ "grenade_frag" ] = true,
+ [ "rpg_missile" ] = true,
+ [ "script_mover" ] = true,
+ [ "turret" ] = true,
+}
-const ARC_CANNON_FX_TABLE = "exp_arc_cannon"
-PrecacheImpactEffectTable( ARC_CANNON_FX_TABLE )
+struct {
+ array<string> missileCheckTargetnames = [
+ // "Arc Pylon",
+ "Arc Ball"
+ ]
+} file;
-if ( !reloadingScripts )
+function ArcCannon_Init()
{
- // Valid Arc Cannon Target Classnames
- level.arcCannonTargetClassnames <- {}
- level.arcCannonTargetClassnames[ "npc_turret_floor" ] <- true
- level.arcCannonTargetClassnames[ "npc_spectre" ] <- true
- level.arcCannonTargetClassnames[ "npc_soldier_shield" ] <- true
- level.arcCannonTargetClassnames[ "npc_soldier_heavy" ] <- true
- level.arcCannonTargetClassnames[ "npc_soldier" ] <- true
- level.arcCannonTargetClassnames[ "npc_cscanner" ] <- true
- level.arcCannonTargetClassnames[ "npc_titan" ] <- true
- level.arcCannonTargetClassnames[ "npc_marvin" ] <- true
- level.arcCannonTargetClassnames[ "player" ] <- true
- level.arcCannonTargetClassnames[ "script_mover" ] <- true
- level.arcCannonTargetClassnames[ "npc_grenade_frag" ] <- true
- level.arcCannonTargetClassnames[ "rpg_missile" ] <- true
- level.arcCannonTargetClassnames[ "npc_turret_mega" ] <- true
- level.arcCannonTargetClassnames[ "npc_turret_sentry" ] <- true
- level.arcCannonTargetClassnames[ "npc_dropship" ] <- true
- level.arcCannonTargetClassnames[ "prop_dynamic" ] <- true
-}
+ RegisterSignal( ARC_CANNON_SIGNAL_DEACTIVATED )
+ RegisterSignal( ARC_CANNON_SIGNAL_CHARGEEND )
+ PrecacheParticleSystem( ARC_CANNON_BEAM_EFFECT )
+ PrecacheParticleSystem( ARC_CANNON_BEAM_EFFECT_MOD )
+ PrecacheImpactEffectTable( ARC_CANNON_FX_TABLE )
-function main()
-{
- Globalize( ArcCannon_PrecacheFX )
- Globalize( ArcCannon_Start )
- Globalize( ArcCannon_Stop )
- Globalize( ArcCannon_ChargeBegin )
- Globalize( ArcCannon_ChargeEnd )
- Globalize( FireArcCannon )
- Globalize( ArcCannon_HideIdleEffect )
- Globalize( AddToArcCannonTargets )
- Globalize( ConvertTitanShieldIntoBonusCharge )
- Globalize( GetArcCannonChargeFraction )
- Globalize( StopChargeEffects )
-
- if( IsClient() )
- {
+ #if CLIENT
AddDestroyCallback( "mp_titanweapon_arc_cannon", ClientDestroyCallback_ArcCannon_Stop )
- }
- else
- {
+ #else
level._arcCannonTargetsArrayID <- CreateScriptManagedEntArray()
- }
+ #endif
- PrecacheParticleSystem( "impact_arc_cannon_titan" )
+ PrecacheParticleSystem( $"impact_arc_cannon_titan" )
}
-function ArcCannon_PrecacheFX( weapon )
+function ArcCannon_PrecacheFX()
{
- if ( WeaponIsPrecached( weapon ) )
- return
-
- PrecacheParticleSystem( "wpn_arc_cannon_electricity_fp" )
- PrecacheParticleSystem( "wpn_arc_cannon_electricity" )
-
- PrecacheParticleSystem( "wpn_ARC_knob_FP" )
- PrecacheParticleSystem( "wpn_ARC_knob" )
+ PrecacheParticleSystem( $"wpn_arc_cannon_electricity_fp" )
+ PrecacheParticleSystem( $"wpn_arc_cannon_electricity" )
- PrecacheParticleSystem( "wpn_arc_cannon_charge_fp" )
- PrecacheParticleSystem( "wpn_arc_cannon_charge" )
-
- PrecacheParticleSystem( "wpn_arc_cannon_charge_fp" )
- PrecacheParticleSystem( "wpn_arc_cannon_charge" )
-
- PrecacheParticleSystem( "wpn_muzzleflash_arc_cannon_fp" )
- PrecacheParticleSystem( "wpn_muzzleflash_arc_cannon" )
+ PrecacheParticleSystem( $"wpn_muzzleflash_arc_cannon_fp" )
+ PrecacheParticleSystem( $"wpn_muzzleflash_arc_cannon" )
}
function ArcCannon_Start( weapon )
{
- weapon.PlayWeaponEffectNoCull( "wpn_arc_cannon_electricity_fp", "wpn_arc_cannon_electricity", "muzzle_flash" )
- weapon.EmitWeaponSound( "arc_cannon_charged_loop" )
+ expect entity( weapon )
+ if ( !IsPilot( weapon.GetWeaponOwner() ) )
+ {
+ weapon.PlayWeaponEffectNoCull( $"wpn_arc_cannon_electricity_fp", $"wpn_arc_cannon_electricity", "muzzle_flash" )
+ weapon.EmitWeaponSound( "arc_cannon_charged_loop" )
+ }
+ else
+ {
+ weapon.EmitWeaponSound_1p3p( "Arc_Rifle_charged_Loop_1P", "Arc_Rifle_charged_Loop_3P" )
+ }
}
function ArcCannon_Stop( weapon, player = null )
{
+ expect entity( weapon )
weapon.Signal( ARC_CANNON_SIGNAL_DEACTIVATED )
- StopChargeEffects( weapon, player )
- weapon.StopWeaponEffect( "wpn_arc_cannon_electricity_fp", "wpn_arc_cannon_electricity" )
+ weapon.StopWeaponEffect( $"wpn_arc_cannon_electricity_fp", $"wpn_arc_cannon_electricity" )
weapon.StopWeaponSound( "arc_cannon_charged_loop" )
- weapon.StopWeaponSound( "arc_cannon_charge" )
}
-function ArcCannon_ChargeBegin( weapon )
+function ArcCannon_ChargeBegin( entity weapon )
{
- local weaponOwner = weapon.GetWeaponOwner()
- local weaponScriptScope = weapon.GetScriptScope()
- local useNormalChargeSounds = true
- if( weapon.HasMod( "overcharge" ) )
- {
- if ( weaponOwner.IsTitan() )
+ #if SERVER
+ if ( weapon.HasMod( "overcharge" ) )
{
- local soul = weaponOwner.GetTitanSoul()
- if ( soul.GetShieldHealth() > 0 )
+ entity weaponOwner = weapon.GetWeaponOwner()
+ if ( weaponOwner.IsTitan() )
{
- weapon.EmitWeaponSound( "arc_cannon_fastcharge" )
- useNormalChargeSounds = false
- }
- if ( IsServer() )
+ entity soul = weaponOwner.GetTitanSoul()
thread ConvertTitanShieldIntoBonusCharge( soul, weapon )
+ }
}
- }
+ #endif
- if ( useNormalChargeSounds )
- {
- weapon.EmitWeaponSound( "arc_cannon_charge" )
- }
-
- if( !("maxChargeTime" in weapon.s) )
- weapon.s.maxChargeTime <- weapon.GetWeaponModSetting( "charge_time" )
-
- weapon.PlayWeaponEffectNoCull( "wpn_arc_cannon_charge_fp", "wpn_arc_cannon_charge", "muzzle_flash" )
- local chargeTime = weapon.GetWeaponChargeTime()
-
- if ( IsClient() )
- {
+ #if CLIENT
if ( !weapon.ShouldPredictProjectiles() )
return
- if ( weaponOwner.IsPlayer() )
- weaponOwner.StartArcCannon();
-
- local handle = weapon.AllocateHandleForViewmodelEffect( "wpn_arc_cannon_charge_fp" )
- if ( handle )
- EffectSkipForwardToTime( handle, chargeTime )
-
- thread cl_ChargeRumble( weapon, ARC_CANNON_RUMBLE_TYPE_INDEX, ARC_CANNON_RUMBLE_CHARGE_MIN, ARC_CANNON_RUMBLE_CHARGE_MAX, ARC_CANNON_SIGNAL_CHARGEEND )
- }
- thread ChargeEffects( weapon )
+ entity weaponOwner = weapon.GetWeaponOwner()
+ Assert( weaponOwner.IsPlayer() )
+ weaponOwner.StartArcCannon();
+ #endif
}
-function ArcCannon_ChargeEnd( weapon, player = null )
+function ArcCannon_ChargeEnd( entity weapon, entity player = null )
{
- if ( IsClient() && weapon.GetWeaponOwner() == GetLocalViewPlayer() )
- {
- local weaponOwner
- if ( player != null )
- weaponOwner = player
- else
- weaponOwner = weapon.GetWeaponOwner()
-
- if ( IsValid( weaponOwner ) && weaponOwner.IsPlayer() )
- weaponOwner.StopArcCannon()
- }
- if( IsValid( weapon ) )
- StopChargeEffects( weapon )
-}
+ #if SERVER
+ if ( IsValid( weapon ) )
+ weapon.Signal( ARC_CANNON_SIGNAL_CHARGEEND )
+ #endif
-function StopChargeEffects( weapon, player = null )
-{
- weapon.Signal( ARC_CANNON_SIGNAL_CHARGEEND )
-
- local weaponScriptScope = weapon.GetScriptScope()
- weapon.StopWeaponSound( "arc_cannon_charge" )
- weapon.StopWeaponEffect( "wpn_arc_cannon_charge_fp", "wpn_arc_cannon_charge" )
- weapon.StopWeaponSound( "arc_cannon_fastcharge" )
- //weapon.StopWeaponEffect( "wpn_arc_cannon_charge_fp", "wpn_arc_cannon_charge" )
- weapon.StopWeaponEffect( "wpn_ARC_knob_FP", "wpn_ARC_knob" )
-}
-
-function ChargeEffects( weapon )
-{
- weapon.EndSignal( ARC_CANNON_SIGNAL_CHARGEEND )
- weapon.EndSignal( "OnDestroy" )
-
- local player = weapon.GetWeaponOwner()
-
- wait ( weapon.s.maxChargeTime * GetArcCannonChargeFraction( weapon ) )
+ #if CLIENT
+ if ( weapon.GetWeaponOwner() == GetLocalViewPlayer() )
+ {
+ entity weaponOwner
+ if ( player != null )
+ weaponOwner = player
+ else
+ weaponOwner = weapon.GetWeaponOwner()
- weapon.PlayWeaponEffectNoCull( "wpn_ARC_knob_FP", "wpn_ARC_knob", "SPINNING_KNOB" )
+ if ( IsValid( weaponOwner ) && weaponOwner.IsPlayer() )
+ weaponOwner.StopArcCannon()
+ }
+ #endif
}
-function ConvertTitanShieldIntoBonusCharge( soul, weapon )
+#if SERVER
+function ConvertTitanShieldIntoBonusCharge( entity soul, entity weapon )
{
weapon.EndSignal( ARC_CANNON_SIGNAL_CHARGEEND )
weapon.EndSignal( "OnDestroy" )
@@ -259,19 +220,19 @@ function ConvertTitanShieldIntoBonusCharge( soul, weapon )
local maxShieldDecay = OVERCHARGE_MAX_SHIELD_DECAY
local bonusChargeFraction = OVERCHARGE_BONUS_CHARGE_FRACTION
local shieldDecayMultiplier = OVERCHARGE_SHIELD_DECAY_MULTIPLIER
- local shieldHealthMax = soul.GetShieldHealthMax()
+ int shieldHealthMax = soul.GetShieldHealthMax()
local chargeRatio = GetArcCannonChargeFraction( weapon )
while( 1 )
{
- if( !IsValid( soul ) || !IsValid( weapon ) )
+ if ( !IsValid( soul ) || !IsValid( weapon ) )
break
- local baseCharge = weapon.GetWeaponChargeFraction() // + GetOverchargeBonusChargeFraction()
+ local baseCharge = GetWeaponChargeFrac( weapon ) // + GetOverchargeBonusChargeFraction()
local charge = clamp ( baseCharge * ( 1 / chargeRatio ), 0.0, 1.0 )
- if( charge < 1.0 || maxShieldDecay > 0)
+ if ( charge < 1.0 || maxShieldDecay > 0)
{
- local shieldHealth = soul.GetShieldHealth()
+ int shieldHealth = soul.GetShieldHealth()
//Slight inconsistency in server updates, this ensures it never takes too much.
if ( shieldDecayMultiplier > maxShieldDecay )
@@ -281,42 +242,27 @@ function ConvertTitanShieldIntoBonusCharge( soul, weapon )
local shieldDecayAmount = shieldHealthMax * shieldDecayMultiplier
local newShieldAmount = shieldHealth - shieldDecayAmount
soul.SetShieldHealth( max( newShieldAmount, 0 ) )
- soul.s.nextRegenTime = Time() + TITAN_SHIELD_REGEN_DELAY
+ soul.nextRegenTime = Time() + GetShieldRegenTime( soul )
- if( shieldDecayAmount > shieldHealth )
+ if ( shieldDecayAmount > shieldHealth )
bonusChargeFraction = bonusChargeFraction * ( shieldHealth / shieldDecayAmount )
weapon.SetWeaponChargeFraction( baseCharge + bonusChargeFraction )
}
wait 0.1
}
}
+#endif
-function FireArcCannon( weapon, attackParams )
+function FireArcCannon( entity weapon, WeaponPrimaryAttackParams attackParams )
{
local weaponScriptScope = weapon.GetScriptScope()
- local owner = weapon.GetWeaponOwner()
-
- local baseCharge = weapon.GetWeaponChargeFraction() // + GetOverchargeBonusChargeFraction()
- local charge = clamp ( baseCharge * ( 1 / GetArcCannonChargeFraction( weapon ) ), 0.0, 1.0 )
- local newVolume = GraphCapped( charge, 0.25, 1.0, 0.0, 1.0 )
- if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) )
- {
- weapon.EmitWeaponSound( "arc_cannon_fire_SmallShot_Amped" )
- weaponScriptScope.PlayWeaponSoundWithVolume( "arc_cannon_fire_BigShot_Amped", newVolume )
- }
- else
- {
- weapon.EmitWeaponSound( "arc_cannon_fire_SmallShot" )
- weaponScriptScope.PlayWeaponSoundWithVolume( "arc_cannon_Fire_BigShot", newVolume )
- }
-
- weapon.StopWeaponSound( "arc_cannon_charged_loop" )
+ local baseCharge = GetWeaponChargeFrac( weapon ) // + GetOverchargeBonusChargeFraction()
+ local charge = clamp( baseCharge * ( 1 / GetArcCannonChargeFraction( weapon ) ), 0.0, 1.0 )
+ float newVolume = GraphCapped( charge, 0.25, 1.0, 0.0, 1.0 )
weapon.EmitWeaponNpcSound( LOUD_WEAPON_AI_SOUND_RADIUS_MP, 0.2 )
- weapon.PlayWeaponEffect( "wpn_muzzleflash_arc_cannon_fp", "wpn_muzzleflash_arc_cannon", "muzzle_flash" )
-
- StopChargeEffects( weapon )
+ weapon.PlayWeaponEffect( $"wpn_muzzleflash_arc_cannon_fp", $"wpn_muzzleflash_arc_cannon", "muzzle_flash" )
local attachmentName = "muzzle_flash"
local attachmentIndex = weapon.LookupAttachment( attachmentName )
@@ -325,7 +271,7 @@ function FireArcCannon( weapon, attackParams )
//printt( "-------- FIRING ARC CANNON --------" )
- local firstTargetInfo = GetFirstArcCannonTarget( weapon, attackParams )
+ table firstTargetInfo = GetFirstArcCannonTarget( weapon, attackParams )
if ( !IsValid( firstTargetInfo.target ) )
FireArcNoTargets( weapon, attackParams, muzzleOrigin )
else
@@ -334,63 +280,71 @@ function FireArcCannon( weapon, attackParams )
return 1
}
-function GetFirstArcCannonTarget( weapon, attackParams )
+table function GetFirstArcCannonTarget( entity weapon, WeaponPrimaryAttackParams attackParams )
{
- local owner = weapon.GetWeaponOwner()
+ entity owner = weapon.GetWeaponOwner()
local coneHeight = weapon.GetMaxDamageFarDist()
- local angleToAxis = 8 // set this too high and auto-titans using it will error on GetVisibleEntitiesInCone
- local ignoredEntities = [ owner, weapon ]
- local traceMask = TRACE_MASK_SHOT
- local flags = VIS_CONE_ENTS_TEST_HITBOXES // | VIS_CONE_ENTS_IGNORE_VORTEX
+ local angleToAxis = 2 // set this too high and auto-titans using it will error on FindVisibleEntitiesInCone
+ array<entity> ignoredEntities = [ owner, weapon ]
+ int traceMask = TRACE_MASK_SHOT
+ int flags = VIS_CONE_ENTS_TEST_HITBOXES
local antilagPlayer = null
if ( owner.IsPlayer() )
{
- angleToAxis = owner.GetAttackSpreadAngle() * 0.095
+ angleToAxis = owner.GetAttackSpreadAngle() * 0.11
antilagPlayer = owner
}
- local results
- local ownerTeam = owner.GetTeam()
+ int ownerTeam = owner.GetTeam()
// Get a missile target and a non-missile target in the cone that the player can zap
// We do this in a separate check so we can use a wider cone to be more forgiving for targeting missiles
- local firstTargetInfo = {}
+ table firstTargetInfo = {}
firstTargetInfo.target <- null
firstTargetInfo.hitLocation <- null
- for ( local i = 0 ; i < 2 ; i++ )
+
+ for ( int i = 0; i < 2; i++ )
{
local missileCheck = i == 0
local coneAngle = angleToAxis
- if ( missileCheck )
- coneAngle *= 3.0
+ if ( missileCheck && owner.IsPlayer() ) // missile check only if owner is player
+ coneAngle *= 8.0
+
+ coneAngle = clamp( coneAngle, 0.1, 89.9 )
- results = GetVisibleEntitiesInCone( attackParams.pos, attackParams.dir, coneHeight, coneAngle, ignoredEntities, traceMask, flags, antilagPlayer, false, false )
- foreach( result in results )
+ array<VisibleEntityInCone> results = FindVisibleEntitiesInCone( attackParams.pos, attackParams.dir, coneHeight, coneAngle, ignoredEntities, traceMask, flags, antilagPlayer )
+ foreach ( result in results )
{
- local visibleEnt = result.entity
+ entity visibleEnt = result.ent
if ( !IsValid( visibleEnt ) )
continue
- local classname = IsServer() ? visibleEnt.GetClassname() : visibleEnt.GetSignifierName()
+ if ( visibleEnt.IsPhaseShifted() )
+ continue
- if ( !( classname in level.arcCannonTargetClassnames ) )
+ local classname = IsServer() ? visibleEnt.GetClassName() : visibleEnt.GetSignifierName()
+
+ if ( !( classname in ArcCannonTargetClassnames ) )
continue
if ( "GetTeam" in visibleEnt )
{
- local visibleEntTeam = visibleEnt.GetTeam()
+ int visibleEntTeam = visibleEnt.GetTeam()
if ( visibleEntTeam == ownerTeam )
continue
if ( IsEntANeutralMegaTurret( visibleEnt, ownerTeam ) )
continue
}
- if ( missileCheck && classname != "rpg_missile" )
+ expect string( classname )
+ string targetname = visibleEnt.GetTargetName()
+
+ if ( missileCheck && ( classname != "rpg_missile" && !file.missileCheckTargetnames.contains( targetname ) ) )
continue
- if ( !missileCheck && classname == "rpg_missile" )
+ if ( !missileCheck && ( classname == "rpg_missile" || file.missileCheckTargetnames.contains( targetname ) ) )
continue
firstTargetInfo.target = visibleEnt
@@ -399,50 +353,78 @@ function GetFirstArcCannonTarget( weapon, attackParams )
}
}
//Creating a whiz-by sound.
- weapon.FireWeaponBullet_Special( attackParams.pos, attackParams.dir, 1, 0, true, true, true, true )
+ weapon.FireWeaponBullet_Special( attackParams.pos, attackParams.dir, 1, 0, true, true, true, true, true, false, false )
return firstTargetInfo
}
-function FireArcNoTargets( weapon, attackParams, muzzleOrigin )
+function FireArcNoTargets( entity weapon, WeaponPrimaryAttackParams attackParams, muzzleOrigin )
{
Assert( IsValid( weapon ) )
- local player = weapon.GetWeaponOwner()
- local chargeFrac = weapon.GetWeaponChargeFraction()
+ entity player = weapon.GetWeaponOwner()
+ local chargeFrac = GetWeaponChargeFrac( weapon )
local beamVec = attackParams.dir * weapon.GetMaxDamageFarDist()
local playerEyePos = player.EyePosition()
- local traceResults = TraceLineHighDetail( playerEyePos, (playerEyePos + beamVec), weapon, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE )
+ TraceResults traceResults = TraceLineHighDetail( playerEyePos, (playerEyePos + beamVec), weapon, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE )
local beamEnd = traceResults.endPos
- local vortexHit = VortexBulletHitCheck( player, playerEyePos, beamEnd )
+ VortexBulletHit ornull vortexHit = VortexBulletHitCheck( player, playerEyePos, beamEnd )
if ( vortexHit )
{
- if( IsServer() )
- {
- local vortexWeapon = vortexHit.vortex.GetOwnerWeapon()
- if( vortexWeapon && vortexWeapon.GetClassname() == "mp_titanweapon_vortex_shield" )
- VortexDrainedByImpact( vortexWeapon, weapon, null, null )
- }
+ expect VortexBulletHit( vortexHit )
+ #if SERVER
+ entity vortexWeapon = vortexHit.vortex.GetOwnerWeapon()
+ string className = IsValid( vortexWeapon ) ? vortexWeapon.GetWeaponClassName() : ""
+ if ( vortexWeapon && ( className == "mp_titanweapon_vortex_shield" || className == "mp_titanweapon_vortex_shield_ion" ) )
+ {
+ float amount = expect float ( chargeFrac ) * 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 )
+ }
+ }
+ else if ( IsVortexSphere( vortexHit.vortex ) )
+ {
+ // do damage to vortex_sphere entities that isn't the titan "vortex shield"
+ local damageNear = weapon.GetWeaponInfoFileKeyField( "damage_near_value" )
+ local damage = damageNear * GraphCapped( chargeFrac, 0, 1, 0.0, 1.0 ) * 10 // do more damage the more charged the weapon is.
+ VortexSphereDrainHealthForDamage( vortexHit.vortex, damage )
+ if ( IsValid( player ) && player.IsPlayer() )
+ player.NotifyDidDamage( vortexHit.vortex, 0, vortexHit.hitPos, 0, damage, DF_NO_HITBEEP, 0, null, 0 )
+ }
+ #endif
beamEnd = vortexHit.hitPos
}
- local radius = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_RADIUS_MIN, ARC_CANNON_BOLT_RADIUS_MAX )
+ float radius = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_RADIUS_MIN, ARC_CANNON_BOLT_RADIUS_MAX )
local boltWidth = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_WIDTH_MIN, ARC_CANNON_BOLT_WIDTH_MAX )
if ( player.IsNPC() )
boltWidth = ARC_CANNON_BOLT_WIDTH_NPC
thread CreateArcCannonBeam( weapon, null, muzzleOrigin, beamEnd, player, ARC_CANNON_BEAM_LIFETIME, radius, boltWidth, 2, false, true )
- if( IsServer() )
- CreateExplosion( beamEnd, 0, 0, 1, 1, player, 0, null, -1, false, ARC_CANNON_FX_TABLE )
+
+ #if SERVER
+ PlayImpactFXTable( expect vector( beamEnd ), player, ARC_CANNON_FX_TABLE, SF_ENVEXPLOSION_INCLUDE_ENTITIES )
+ #endif
}
-function FireArcWithTargets( weapon, firstTargetInfo, attackParams, muzzleOrigin )
+function FireArcWithTargets( entity weapon, table firstTargetInfo, WeaponPrimaryAttackParams attackParams, muzzleOrigin )
{
local beamStart = muzzleOrigin
local beamEnd
- local player = weapon.GetWeaponOwner()
- local chargeFrac = weapon.GetWeaponChargeFraction()
- local radius = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_RADIUS_MIN, ARC_CANNON_BOLT_RADIUS_MAX )
- local boltWidth = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_WIDTH_MIN, ARC_CANNON_BOLT_WIDTH_MAX )
+ entity player = weapon.GetWeaponOwner()
+ local chargeFrac = GetWeaponChargeFrac( weapon )
+ float radius = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_RADIUS_MIN, ARC_CANNON_BOLT_RADIUS_MAX )
+ float boltWidth = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_WIDTH_MIN, ARC_CANNON_BOLT_WIDTH_MAX )
local maxChains
local minChains
@@ -468,7 +450,7 @@ function FireArcWithTargets( weapon, firstTargetInfo, attackParams, muzzleOrigin
if ( !player.IsNPC() )
maxChains = Graph( chargeFrac, 0, 1, minChains, maxChains )
- local zapInfo = {}
+ table zapInfo = {}
zapInfo.weapon <- weapon
zapInfo.player <- player
zapInfo.muzzleOrigin <- muzzleOrigin
@@ -478,11 +460,12 @@ function FireArcWithTargets( weapon, firstTargetInfo, attackParams, muzzleOrigin
zapInfo.chargeFrac <- chargeFrac
zapInfo.zappedTargets <- {}
zapInfo.zappedTargets[ firstTargetInfo.target ] <- true
+ zapInfo.dmgSourceID <- weapon.GetDamageSourceID()
local chainNum = 1
- thread ZapTargetRecursive( firstTargetInfo.target, zapInfo, zapInfo.muzzleOrigin, firstTargetInfo.hitLocation, chainNum )
+ thread ZapTargetRecursive( expect entity( firstTargetInfo.target), zapInfo, zapInfo.muzzleOrigin, expect vector( firstTargetInfo.hitLocation ), chainNum )
}
-function ZapTargetRecursive( target, zapInfo, beamStartPos, firstTargetBeamEndPos = null, chainNum = 1 )
+function ZapTargetRecursive( entity target, table zapInfo, beamStartPos, vector ornull firstTargetBeamEndPos = null, chainNum = 1 )
{
if ( !IsValid( target ) )
return
@@ -493,28 +476,30 @@ function ZapTargetRecursive( target, zapInfo, beamStartPos, firstTargetBeamEndPo
Assert( target in zapInfo.zappedTargets )
if ( chainNum > zapInfo.maxChains )
return
- local beamEndPos
+ vector beamEndPos
if ( firstTargetBeamEndPos == null )
beamEndPos = target.GetWorldSpaceCenter()
else
- beamEndPos = firstTargetBeamEndPos
+ beamEndPos = expect vector( firstTargetBeamEndPos )
waitthread ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum )
// Get other nearby targets we can chain to
- if ( IsServer() )
- {
- if ( !IsValid( target ) )
- return
+ #if SERVER
+ if ( !IsValid( zapInfo.weapon ) )
+ return
+
+ var noArcing = expect entity( zapInfo.weapon ).GetWeaponInfoFileKeyField( "disable_arc" )
- if ( !IsValid( zapInfo.weapon ) )
- return
+ if ( noArcing != null && noArcing == 1 )
+ return // no chaining on new arc cannon
- local chainTargets = GetArcCannonChainTargets( beamEndPos, target, zapInfo )
- foreach( chainTarget in chainTargets )
+ // NOTE: 'target' could be invalid at this point (no corpse)
+ array<entity> chainTargets = GetArcCannonChainTargets( beamEndPos, target, zapInfo )
+ foreach( entity chainTarget in chainTargets )
{
local newChainNum = chainNum
- if( !chainTarget.GetClassname() != "rpg_missile" )
+ if ( chainTarget.GetClassName() != "rpg_missile" )
newChainNum++
zapInfo.zappedTargets[ chainTarget ] <- true
thread ZapTargetRecursive( chainTarget, zapInfo, beamEndPos, null, newChainNum )
@@ -522,203 +507,257 @@ function ZapTargetRecursive( target, zapInfo, beamStartPos, firstTargetBeamEndPo
if ( IsValid( zapInfo.player ) && zapInfo.player.IsPlayer() && zapInfo.zappedTargets.len() >= 5 )
{
- if ( PlayerProgressionAllowed( zapInfo.player ) )
- zapInfo.player.SetPersistentVar( "ach_multikillArcRifle", true )
+ #if HAS_STATS
if ( chainNum == 5 )
- UpdatePlayerStat( zapInfo.player, "misc_stats", "arcCannonMultiKills", 1 )
+ UpdatePlayerStat( expect entity( zapInfo.player ), "misc_stats", "arcCannonMultiKills", 1 )
+ #endif
}
- }
+ #endif
}
function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 )
{
+ expect entity( target )
+ expect vector( beamStartPos )
+ expect vector( beamEndPos )
+
//DebugDrawLine( beamStartPos, beamEndPos, 255, 0, 0, true, 5.0 )
local boltWidth = zapInfo.boltWidth
if ( zapInfo.player.IsNPC() )
boltWidth = ARC_CANNON_BOLT_WIDTH_NPC
local firstBeam = ( chainNum == 1 )
- if( firstBeam && IsServer() )
- CreateExplosion( beamEndPos, 0, 0, 1, 1, zapInfo.player, 0, null, -1, false, ARC_CANNON_FX_TABLE )
+ #if SERVER
+ if ( firstBeam )
+ {
+ PlayImpactFXTable( beamEndPos, expect entity( zapInfo.player ), ARC_CANNON_FX_TABLE, SF_ENVEXPLOSION_INCLUDE_ENTITIES )
+ }
+ #endif
+
thread CreateArcCannonBeam( zapInfo.weapon, target, beamStartPos, beamEndPos, zapInfo.player, ARC_CANNON_BEAM_LIFETIME, zapInfo.radius, boltWidth, 5, true, firstBeam )
- if ( IsClient() )
- return
+ #if SERVER
+ local isMissile = ( target.GetClassName() == "rpg_missile" )
+ if ( !isMissile )
+ wait ARC_CANNON_FORK_DELAY
+ else
+ wait 0.05
- local isMissile = ( target.GetClassname() == "rpg_missile" )
- if( !isMissile )
- wait ARC_CANNON_FORK_DELAY
- else
- wait 0.05
+ local deathPackage = damageTypes.arcCannon
- local deathPackage = damageTypes.ArcCannon
+ float damageAmount
+ int damageMin
+ int damageMax
- local damageAmount
- local damageMin
- local damageMax
+ int damageFarValue = eWeaponVar.damage_far_value
+ int damageNearValue = eWeaponVar.damage_near_value
+ int damageFarValueTitanArmor = eWeaponVar.damage_far_value_titanarmor
+ int damageNearValueTitanArmor = eWeaponVar.damage_near_value_titanarmor
+ if ( zapInfo.player.IsNPC() )
+ {
+ damageFarValue = eWeaponVar.npc_damage_far_value
+ damageNearValue = eWeaponVar.npc_damage_near_value
+ damageFarValueTitanArmor = eWeaponVar.npc_damage_far_value_titanarmor
+ damageNearValueTitanArmor = eWeaponVar.npc_damage_near_value_titanarmor
+ }
- if ( IsValid( target ) && IsValid( zapInfo.player ) )
- {
- if ( target.GetArmorType() == ARMOR_TYPE_HEAVY )
+ if ( IsValid( target ) && IsValid( zapInfo.player ) )
{
+ bool hasFastPacitor = false
+ bool noArcing = false
+
if ( IsValid( zapInfo.weapon ) )
{
- damageMin = zapInfo.weapon.GetWeaponModSetting( "damage_far_value_titanarmor" )
- damageMax = zapInfo.weapon.GetWeaponModSetting( "damage_near_value_titanarmor" )
+ entity weap = expect entity( zapInfo.weapon )
+ hasFastPacitor = weap.GetWeaponInfoFileKeyField( "push_apart" ) != null && weap.GetWeaponInfoFileKeyField( "push_apart" ) == 1
+ noArcing = weap.GetWeaponInfoFileKeyField( "no_arcing" ) != null && weap.GetWeaponInfoFileKeyField( "no_arcing" ) == 1
}
- else
+
+ if ( target.GetArmorType() == ARMOR_TYPE_HEAVY )
{
- damageMin = GetWeaponInfoFileKeyField_Global( "mp_titanweapon_arc_cannon", "damage_far_value_titanarmor" )
- damageMax = GetWeaponInfoFileKeyField_Global( "mp_titanweapon_arc_cannon", "damage_near_value_titanarmor" )
+ if ( IsValid( zapInfo.weapon ) )
+ {
+ entity weapon = expect entity( zapInfo.weapon )
+ damageMin = weapon.GetWeaponSettingInt( damageFarValueTitanArmor )
+ damageMax = weapon.GetWeaponSettingInt( damageNearValueTitanArmor )
+ }
+ else
+ {
+ damageMin = 100
+ damageMax = zapInfo.player.IsNPC() ? 1200 : 800
+ }
}
-
- // Due to auto-titans not charging, they do very little damage with this weapon against one another.
- if ( zapInfo.player.IsNPC() )
+ else
{
- damageMin *= 7.0
- damageMax *= 7.0
+ if ( IsValid( zapInfo.weapon ) )
+ {
+ entity weapon = expect entity( zapInfo.weapon )
+ damageMin = weapon.GetWeaponSettingInt( damageFarValue )
+ damageMax = weapon.GetWeaponSettingInt( damageNearValue )
+ }
+ else
+ {
+ damageMin = 120
+ damageMax = zapInfo.player.IsNPC() ? 140 : 275
+ }
+
+ if ( target.IsNPC() )
+ {
+ damageMin *= 3 // more powerful against NPC humans so they die easy
+ damageMax *= 3
+ }
}
- // HACK; temp fix for non titan heavy armor targets (e.g. mega turret)
- }
- else
- {
- if ( IsValid( zapInfo.weapon ) )
+
+ local chargeRatio = GetArcCannonChargeFraction( zapInfo.weapon )
+ if ( IsValid( zapInfo.weapon ) && !zapInfo.weapon.GetWeaponSettingBool( eWeaponVar.charge_require_input ) )
{
- damageMin = zapInfo.weapon.GetWeaponModSetting( "damage_far_value" )
- damageMax = zapInfo.weapon.GetWeaponModSetting( "damage_near_value" )
+ // use distance for damage if the weapon auto-fires
+ entity weapon = expect entity( zapInfo.weapon )
+ float nearDist = weapon.GetWeaponSettingFloat( eWeaponVar.damage_near_distance )
+ float farDist = weapon.GetWeaponSettingFloat( eWeaponVar.damage_far_distance )
+
+ float dist = Distance( weapon.GetOrigin(), target.GetOrigin() )
+ damageAmount = GraphCapped( dist, farDist, nearDist, damageMin, damageMax )
}
else
{
- damageMin = GetWeaponInfoFileKeyField_Global( "mp_titanweapon_arc_cannon", "damage_far_value" )
- damageMax = GetWeaponInfoFileKeyField_Global( "mp_titanweapon_arc_cannon", "damage_near_value" )
+ // Scale damage amount based on how many chains deep we are
+ damageAmount = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, damageMin, damageMax )
}
+ local damageFalloff = ARC_CANNON_DAMAGE_FALLOFF_SCALER
+ if ( IsValid( zapInfo.weapon ) && zapInfo.weapon.HasMod( "splitter" ) )
+ damageFalloff = SPLITTER_DAMAGE_FALLOFF_SCALER
+ damageAmount *= pow( damageFalloff, chainNum - 1 )
+
+ local dmgSourceID = zapInfo.dmgSourceID
- if ( target.IsNPC() )
+ // Update Later - This shouldn't be done here, this is not where we determine if damage actually happened to the target
+ // move to Damaged callback instead
+ if ( damageAmount > 0 )
{
- damageMin *= 3.0 // more powerful against NPC humans so they die easy
- damageMax *= 3.0
- }
- }
+ float empDuration = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_EMP_DURATION_MIN, ARC_CANNON_EMP_DURATION_MAX )
+ if ( target.IsPlayer() && target.IsTitan() && !hasFastPacitor && !noArcing )
+ {
+ float empViewStrength = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_SCREEN_EFFECTS_MIN, ARC_CANNON_SCREEN_EFFECTS_MAX )
+
+ if ( target.IsTitan() && zapInfo.chargeFrac >= ARC_CANNON_SCREEN_THRESHOLD )
+ {
+ Remote_CallFunction_Replay( target, "ServerCallback_TitanEMP", empViewStrength, empDuration, ARC_CANNON_EMP_FADEOUT_DURATION )
+ EmitSoundOnEntityOnlyToPlayer( target, target, ARC_CANNON_TITAN_SCREEN_SFX )
+ }
+ else if ( zapInfo.chargeFrac >= ARC_CANNON_SCREEN_THRESHOLD )
+ {
+ StatusEffect_AddTimed( target, eStatusEffect.emp, empViewStrength, empDuration, ARC_CANNON_EMP_FADEOUT_DURATION )
+ EmitSoundOnEntityOnlyToPlayer( target, target, ARC_CANNON_PILOT_SCREEN_SFX )
+ }
+ }
- // Scale damage amount based on how many chains deep we are
- local chargeRatio = GetArcCannonChargeFraction( zapInfo.weapon )
- damageAmount = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, damageMin, damageMax )
- local damageFalloff = ARC_CANNON_DAMAGE_FALLOFF_SCALER
- if( IsValid( zapInfo.weapon ) && zapInfo.weapon.HasMod( "splitter" ) )
- damageFalloff = SPLITTER_DAMAGE_FALLOFF_SCALER
- damageAmount *= pow( damageFalloff, chainNum - 1 )
+ // Do 3rd person effect on the body
+ asset effect
+ string tag
+ target.TakeDamage( damageAmount, zapInfo.player, zapInfo.player, { origin = beamEndPos, force = Vector(0,0,0), scriptType = deathPackage, weapon = zapInfo.weapon, damageSourceId = dmgSourceID,criticalHitScale = zapInfo.weapon.GetWeaponSettingFloat( eWeaponVar.critical_hit_damage_scale ) } )
+ //vector dir = Normalize( beamEndPos - beamStartPos )
+ //vector velocity = dir * 600
+ //PushPlayerAway( target, velocity )
+ //PushPlayerAway( expect entity( zapInfo.player ), -velocity )
- local dmgSourceID = eDamageSourceId.mp_titanweapon_arc_cannon
+ if ( IsValid( zapInfo.weapon ) && hasFastPacitor )
+ {
+ if ( IsAlive( target ) && IsAlive( expect entity( zapInfo.player ) ) && target.IsTitan() )
+ {
+ float pushPercent = GraphCapped( damageAmount, damageMin, damageMax, 0.0, 1.0 )
- // Update Later - This shouldn't be done here, this is not where we determine if damage actually happened to the target
- // move to Damaged callback instead
- if( damageAmount > 0 )
- {
- local empDuration = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_EMP_DURATION_MIN, ARC_CANNON_EMP_DURATION_MAX )
+ if ( pushPercent > 0.6 )
+ PushPlayersApart( target, expect entity( zapInfo.player ), pushPercent * 400.0 )
+ }
+ }
- if ( target.IsPlayer() )
- {
- local empViewStrength = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_SCREEN_EFFECTS_MIN, ARC_CANNON_SCREEN_EFFECTS_MAX )
+ if ( zapInfo.chargeFrac < ARC_CANNON_SCREEN_THRESHOLD )
+ empDuration = ARC_CANNON_3RD_PERSON_EFFECT_MIN_DURATION
+ else
+ empDuration += ARC_CANNON_EMP_FADEOUT_DURATION
- if ( target.IsTitan() && zapInfo.chargeFrac >= ARC_CANNON_SCREEN_THRESHOLD )
+ if ( target.GetArmorType() == ARMOR_TYPE_HEAVY )
{
- Remote.CallFunction_Replay( target, "ServerCallback_TitanEMP", empViewStrength, empDuration, ARC_CANNON_EMP_FADEOUT_DURATION )
- EmitSoundOnEntityOnlyToPlayer( target, target, ARC_CANNON_TITAN_SCREEN_SFX )
-
- local scale = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_SLOW_SCALE_MIN, ARC_CANNON_SLOW_SCALE_MAX )
- thread EMP_SlowPlayer( target, scale, empDuration )
+ effect = $"impact_arc_cannon_titan"
+ tag = "exp_torso_front"
}
- else if ( zapInfo.chargeFrac >= ARC_CANNON_SCREEN_THRESHOLD )
+ else
{
- Remote.CallFunction_Replay( target, "ServerCallback_PilotEMP", empViewStrength, empDuration, ARC_CANNON_EMP_FADEOUT_DURATION )
- EmitSoundOnEntityOnlyToPlayer( target, target, ARC_CANNON_PILOT_SCREEN_SFX )
+ effect = $"P_emp_body_human"
+ tag = "CHESTFOCUS"
}
- }
- // Do 3rd person effect on the body
- local effect = null
- local tag = null
- target.TakeDamage( damageAmount, zapInfo.player, zapInfo.player, { origin = zapInfo.player.GetOrigin(), force = Vector(0,0,0), scriptType = deathPackage, weapon = zapInfo.weapon, damageSourceId = dmgSourceID } )
+ if ( target.IsPlayer() )
+ {
+ if ( target.LookupAttachment( tag ) != 0 )
+ ClientStylePlayFXOnEntity( effect, target, tag, empDuration )
+ }
- if ( zapInfo.chargeFrac < ARC_CANNON_SCREEN_THRESHOLD )
- empDuration = ARC_CANNON_3RD_PERSON_EFFECT_MIN_DURATION
- else
- empDuration += ARC_CANNON_EMP_FADEOUT_DURATION
+ if ( target.IsPlayer() )
+ EmitSoundOnEntityExceptToPlayer( target, target, "Titan_Blue_Electricity_Cloud" )
+ else
+ EmitSoundOnEntity( target, "Titan_Blue_Electricity_Cloud" )
- if ( target.GetArmorType() == ARMOR_TYPE_HEAVY )
- {
- effect = "impact_arc_cannon_titan"
- tag = "exp_torso_front"
+ thread FadeOutSoundOnEntityAfterDelay( target, "Titan_Blue_Electricity_Cloud", empDuration * 0.6666, empDuration * 0.3333 )
}
else
{
- effect = "P_emp_body_human"
- tag = "CHESTFOCUS"
+ //Don't bounce if the beam is set to do 0 damage.
+ chainNum = zapInfo.maxChains
}
- if ( target.IsPlayer() && effect != null && tag != null )
+ if ( isMissile )
{
- if ( target.LookupAttachment( tag ) != 0 )
- ClientStylePlayFXOnEntity( effect, target, tag, empDuration )
+ if ( IsValid( zapInfo.player ) )
+ target.SetOwner( zapInfo.player )
+ target.MissileExplode()
}
-
- if ( target.IsPlayer() )
- EmitSoundOnEntityExceptToPlayer( target, target, "Titan_Blue_Electricity_Cloud" )
- else
- EmitSoundOnEntity( target, "Titan_Blue_Electricity_Cloud" )
-
- thread FadeOutSoundOnEntityAfterDelay( target, "Titan_Blue_Electricity_Cloud", empDuration * 0.6666, empDuration * 0.3333 )
- }
- else
- {
- //Don't bounce if the beam is set to do 0 damage.
- chainNum = zapInfo.maxChains
}
-
- if ( isMissile )
- {
- if ( IsValid ( zapInfo.player ) )
- target.SetOwner( zapInfo.player )
- target.Explode()
- }
- }
+ #endif // SERVER
}
-function FadeOutSoundOnEntityAfterDelay( entity, soundAlias, delay, fadeTime )
-{
-
- if ( !IsValid( entity ) )
- return
+#if SERVER
- entity.EndSignal( "OnDestroy" )
- wait delay
- FadeOutSoundOnEntity( entity, soundAlias, fadeTime )
+void function PushEntForTime( entity ent, vector velocity, float time )
+{
+ ent.EndSignal( "OnDeath" )
+ float endTime = Time() + time
+ float startTime = Time()
+ for ( ;; )
+ {
+ if ( Time() >= endTime )
+ break
+ float multiplier = Graph( Time(), startTime, endTime, 1.0, 0.0 )
+ vector currentVel = ent.GetVelocity()
+ currentVel += velocity * multiplier
+ ent.SetVelocity( currentVel )
+ WaitFrame()
+ }
}
-
-function GetArcCannonChainTargets( fromOrigin, fromTarget, zapInfo )
+array<entity> function GetArcCannonChainTargets( vector fromOrigin, entity fromTarget, table zapInfo )
{
- Assert( IsServer() )
-
- local results = []
+ // NOTE: fromTarget could be null/invalid if it was a drone
+ array<entity> results = []
if ( !IsValid( zapInfo.player ) )
return results
- local playerTeam = zapInfo.player.GetTeam()
- local allTargets = GetArcCannonTargetsInRange( fromOrigin, playerTeam, zapInfo.weapon )
+ int playerTeam = expect entity( zapInfo.player ).GetTeam()
+ array<entity> allTargets = GetArcCannonTargetsInRange( fromOrigin, playerTeam, expect entity( zapInfo.weapon ) )
allTargets = ArrayClosest( allTargets, fromOrigin )
local viewVector
if ( zapInfo.player.IsPlayer() )
viewVector = zapInfo.player.GetViewVector()
else
- viewVector = zapInfo.player.EyeAngles().AnglesToForward()
+ viewVector = AnglesToForward( zapInfo.player.EyeAngles() )
local eyePosition = zapInfo.player.EyePosition()
- foreach( ent in allTargets )
+ foreach ( ent in allTargets )
{
local forkCount = ARC_CANNON_FORK_COUNT_MAX
if ( zapInfo.weapon.HasMod( "splitter" ) )
@@ -729,21 +768,22 @@ function GetArcCannonChainTargets( fromOrigin, fromTarget, zapInfo )
if ( results.len() >= forkCount )
break
+ if ( ent.IsPhaseShifted() )
+ continue
+
if ( ent.IsPlayer() )
{
- if ( ent.GetPlayerClass() == "operator" )
- continue
-
- if ( ent.GetPlayerClass() == "dronecontroller" )
- continue
-
// Ignore players that are passing damage to their parent. This is to address zapping a friendly rodeo player
local entParent = ent.GetParent()
if ( IsValid( entParent ) && ent.kv.PassDamageToParent.tointeger() )
continue
+
+ // only chains to other titan players for now
+ if ( !ent.IsTitan() )
+ continue
}
- if ( ent.GetClassname() == "script_mover" )
+ if ( ent.GetClassName() == "script_mover" )
continue
if ( IsEntANeutralMegaTurret( ent, playerTeam ) )
@@ -759,7 +799,7 @@ function GetArcCannonChainTargets( fromOrigin, fromTarget, zapInfo )
//Preventing the arc-cannon from firing behind.
local vecToEnt = ( ent.GetWorldSpaceCenter() - eyePosition )
vecToEnt.Norm()
- local dotVal = vecToEnt.Dot( viewVector )
+ local dotVal = DotProduct( vecToEnt, viewVector )
if ( dotVal < 0 )
continue
@@ -774,17 +814,21 @@ function GetArcCannonChainTargets( fromOrigin, fromTarget, zapInfo )
ignoreEnts.append( zappedTarget )
}
- local traceResult = TraceLineHighDetail( fromOrigin, ent.GetWorldSpaceCenter(), ignoreEnts, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE )
+ TraceResults traceResult = TraceLineHighDetail( fromOrigin, ent.GetWorldSpaceCenter(), ignoreEnts, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE )
// Trace failed, lets try an eye to eye trace
- if ( traceResult.fraction < 1 && IsValid( fromTarget ) )
- traceResult = TraceLineHighDetail( fromTarget.EyePosition(), ent.EyePosition(), ignoreEnts, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE )
+ if ( traceResult.fraction < 1 )
+ {
+ // 'fromTarget' may be invalid
+ if ( IsValid( fromTarget ) )
+ traceResult = TraceLineHighDetail( fromTarget.EyePosition(), ent.EyePosition(), ignoreEnts, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE )
+ }
if ( traceResult.fraction < 1 )
continue
// Enemy is in visible, and within range.
- if ( !IsValueInArray( results, ent ) )
+ if ( !results.contains( ent ) )
results.append( ent )
}
@@ -792,72 +836,85 @@ function GetArcCannonChainTargets( fromOrigin, fromTarget, zapInfo )
return results
}
-Globalize( GetArcCannonChainTargets )
-
+#endif // SERVER
-function IsEntANeutralMegaTurret( ent, playerTeam )
+bool function IsEntANeutralMegaTurret( ent, int playerTeam )
{
- if ( ent.GetClassname() != "npc_turret_mega" )
+ expect entity( ent )
+
+ if ( ent.GetClassName() != "npc_turret_mega" )
return false
- local entTeam = ent.GetTeam()
+ int entTeam = ent.GetTeam()
if ( entTeam == playerTeam )
return false
- if ( entTeam != GetOtherTeam( playerTeam ) )
+ if ( !IsEnemyTeam( playerTeam, entTeam ) )
return true
return false
}
-Globalize( IsEntANeutralMegaTurret )
-function ArcCannon_HideIdleEffect( weapon, delay )
+function ArcCannon_HideIdleEffect( entity weapon, delay )
{
- //printt( "HideIdleEffect" )
+ bool weaponOwnerIsPilot = IsPilot( weapon.GetWeaponOwner() )
weapon.EndSignal( ARC_CANNON_SIGNAL_DEACTIVATED )
- weapon.StopWeaponEffect( "wpn_arc_cannon_electricity_fp", "wpn_arc_cannon_electricity" )
+ if ( weaponOwnerIsPilot == false )
+ {
+ weapon.StopWeaponEffect( $"wpn_arc_cannon_electricity_fp", $"wpn_arc_cannon_electricity" )
+ weapon.StopWeaponSound( "arc_cannon_charged_loop" )
+ }
wait delay
- if( !IsValid( weapon ) )
+ if ( !IsValid( weapon ) )
return
- local weaponOwner = weapon.GetWeaponOwner()
+ entity weaponOwner = weapon.GetWeaponOwner()
//The weapon can be valid, but the player isn't a Titan during melee execute.
// JFS: threads with waits should just end on "OnDestroy"
- if ( !IsValid(weaponOwner) )
+ if ( !IsValid( weaponOwner ) )
return
- if ( !weapon.GetWeaponOwner().IsTitan() || weapon != weaponOwner.GetActiveWeapon() )
+ if ( weapon != weaponOwner.GetActiveWeapon() )
return
- weapon.PlayWeaponEffectNoCull( "wpn_arc_cannon_electricity_fp", "wpn_arc_cannon_electricity", "muzzle_flash" )
- weapon.EmitWeaponSound( "arc_cannon_charged_loop" )
+ if ( weaponOwnerIsPilot == false )
+ {
+ weapon.PlayWeaponEffectNoCull( $"wpn_arc_cannon_electricity_fp", $"wpn_arc_cannon_electricity", "muzzle_flash" )
+ weapon.EmitWeaponSound( "arc_cannon_charged_loop" )
+ }
+ else
+ {
+ weapon.EmitWeaponSound_1p3p( "Arc_Rifle_charged_Loop_1P", "Arc_Rifle_charged_Loop_3P" )
+ }
}
-function AddToArcCannonTargets( ent )
+#if SERVER
+void function AddToArcCannonTargets( entity ent )
{
AddToScriptManagedEntArray( level._arcCannonTargetsArrayID, ent );
}
-function GetArcCannonTargets( origin, team )
+function RemoveArcCannonTarget( ent )
{
- local targets = GetScriptManagedEntArrayWithinCenter( level._arcCannonTargetsArrayID, team, origin, ARC_CANNON_TITAN_RANGE_CHAIN )
+ RemoveFromScriptManagedEntArray( level._arcCannonTargetsArrayID, ent )
+}
- if ( ARC_CANNON_TARGETS_MISSILES )
- {
- local enemyTeam = GetEnemyTeam( team )
- targets.extend( GetProjectileArrayEx( "rpg_missile", enemyTeam, origin, ARC_CANNON_TITAN_RANGE_CHAIN ) )
- }
+array<entity> function GetArcCannonTargets( vector origin, int team, entity weapon )
+{
+ array<entity> targets = GetScriptManagedEntArrayWithinCenter( level._arcCannonTargetsArrayID, team, origin, ARC_CANNON_TITAN_RANGE_CHAIN )
+
+ if ( ARC_CANNON_TARGETS_MISSILES && weapon.GetWeaponChargeFraction() == 1.0 )
+ targets.extend( GetProjectileArrayEx( "rpg_missile", TEAM_ANY, team, origin, ARC_CANNON_TITAN_RANGE_CHAIN ) )
return targets
}
-Globalize( GetArcCannonTargets )
-function GetArcCannonTargetsInRange( origin, team, weapon )
+array<entity> function GetArcCannonTargetsInRange( vector origin, int team, entity weapon )
{
- local allTargets = GetArcCannonTargets( origin, team )
- local targetsInRange = []
+ array<entity> allTargets = GetArcCannonTargets( origin, team, weapon )
+ array<entity> targetsInRange
- local titanDistSq
- local distSq
+ float titanDistSq
+ float distSq
if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) )
{
titanDistSq = ARC_CANNON_TITAN_RANGE_CHAIN_BURN * ARC_CANNON_TITAN_RANGE_CHAIN_BURN
@@ -871,45 +928,15 @@ function GetArcCannonTargetsInRange( origin, team, weapon )
foreach( target in allTargets )
{
- local d = DistanceSqr( target.GetOrigin(), origin )
- local validDist = target.IsTitan() ? titanDistSq : distSq
+ float d = DistanceSqr( target.GetOrigin(), origin )
+ float validDist = target.IsTitan() ? titanDistSq : distSq
if ( d <= validDist )
targetsInRange.append( target )
}
return targetsInRange
}
-
-function SortArcCannonTargets( weapon, targets )
-{
- Assert( targets.len() > 0 )
- local originalTargetCount = targets.len()
- //printt( " sorting", originalTargetCount, "targets" )
-
- local sortedTargets = []
- local lastEnt = weapon.GetWeaponOwner()
- local closestIndex = null
- local closestEnt = null
-
- while( targets.len() > 0 )
- {
- closestEnt = null
- closestIndex = null
-
- closestIndex = GetClosestIndex( targets, lastEnt.GetOrigin() )
- Assert( closestIndex != null )
- closestEnt = targets[ closestIndex ]
- Assert( closestEnt != null )
-
- sortedTargets.append( closestEnt )
- targets.remove( closestIndex )
-
- lastEnt = closestEnt
- }
-
- Assert( sortedTargets.len() == originalTargetCount )
- return sortedTargets
-}
+#endif // SERVER
function CreateArcCannonBeam( weapon, target, startPos, endPos, player, lifeDuration = ARC_CANNON_BEAM_LIFETIME, radius = 256, boltWidth = 4, noiseAmplitude = 5, hasTarget = true, firstBeam = false )
{
@@ -922,37 +949,38 @@ function CreateArcCannonBeam( weapon, target, startPos, endPos, player, lifeDura
if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) )
lifeDuration = ARC_CANNON_BEAM_LIFETIME_BURN
// If it's the first beam and on client we do a special beam so it's lined up with the muzzle origin
- if ( IsClient() && firstBeam )
- thread CreateClientArcBeam( weapon, endPos, lifeDuration, target )
-
- if ( IsClient() )
- return
-
- // Control point sets the end position of the effect
- local cpEnd = CreateEntity( "info_placement_helper" )
- cpEnd.SetName( UniqueString( "arc_cannon_beam_cpEnd" ) )
- cpEnd.SetOrigin( endPos )
- DispatchSpawn( cpEnd, false )
-
- local zapBeam = CreateEntity( "info_particle_system" )
- zapBeam.kv.cpoint1 = cpEnd.GetName()
-
- zapBeam.kv.effect_name = GetBeamEffect( weapon )
-
- zapBeam.kv.start_active = 0
- zapBeam.SetOwner( player )
- zapBeam.SetOrigin( startPos )
- if ( firstBeam )
- {
- zapBeam.kv.VisibilityFlags = 6 // everyone but owner
- zapBeam.SetParent( player.GetActiveWeapon(), "muzzle_flash", false, 0.0 )
- }
- DispatchSpawn( zapBeam )
+ #if CLIENT
+ if ( firstBeam )
+ thread CreateClientArcBeam( weapon, endPos, lifeDuration, target )
+ #endif
+
+ #if SERVER
+ // Control point sets the end position of the effect
+ entity cpEnd = CreateEntity( "info_placement_helper" )
+ SetTargetName( cpEnd, UniqueString( "arc_cannon_beam_cpEnd" ) )
+ cpEnd.SetOrigin( endPos )
+ DispatchSpawn( cpEnd )
+
+ entity zapBeam = CreateEntity( "info_particle_system" )
+ zapBeam.kv.cpoint1 = cpEnd.GetTargetName()
+
+ zapBeam.SetValueForEffectNameKey( GetBeamEffect( weapon ) )
+
+ zapBeam.kv.start_active = 0
+ zapBeam.SetOwner( player )
+ zapBeam.SetOrigin( startPos )
+ if ( firstBeam )
+ {
+ zapBeam.kv.VisibilityFlags = (ENTITY_VISIBLE_TO_FRIENDLY | ENTITY_VISIBLE_TO_ENEMY) // everyone but owner
+ zapBeam.SetParent( player.GetActiveWeapon(), "muzzle_flash", false, 0.0 )
+ }
+ DispatchSpawn( zapBeam )
- zapBeam.Fire( "Start" )
- zapBeam.Fire( "StopPlayEndCap", "", lifeDuration )
- zapBeam.Kill( lifeDuration )
- cpEnd.Kill( lifeDuration )
+ zapBeam.Fire( "Start" )
+ zapBeam.Fire( "StopPlayEndCap", "", lifeDuration )
+ zapBeam.Kill_Deprecated_UseDestroyInstead( lifeDuration )
+ cpEnd.Kill_Deprecated_UseDestroyInstead( lifeDuration )
+ #endif
}
function GetBeamEffect( weapon )
@@ -963,14 +991,19 @@ function GetBeamEffect( weapon )
return ARC_CANNON_BEAM_EFFECT
}
+#if CLIENT
function CreateClientArcBeam( weapon, endPos, lifeDuration, target )
{
Assert( IsClient() )
local beamEffect = GetBeamEffect( weapon )
- weapon.PlayWeaponEffect( beamEffect, null, "muzzle_flash" )
- local handle = weapon.AllocateHandleForViewmodelEffect( beamEffect )
+ // HACK HACK HACK HACK
+ string tag = "muzzle_flash"
+ if ( weapon.GetWeaponInfoFileKeyField( "client_tag_override" ) != null )
+ tag = expect string( weapon.GetWeaponInfoFileKeyField( "client_tag_override" ) )
+
+ local handle = weapon.PlayWeaponEffectReturnViewEffectHandle( beamEffect, $"", tag )
if ( !EffectDoesExist( handle ) )
return
@@ -982,25 +1015,33 @@ function CreateClientArcBeam( weapon, endPos, lifeDuration, target )
wait( lifeDuration )
if ( IsValid( weapon ) )
- weapon.StopWeaponEffect( beamEffect, null )
+ weapon.StopWeaponEffect( beamEffect, $"" )
}
-function ClientDestroyCallback_ArcCannon_Stop( entity )
+void function ClientDestroyCallback_ArcCannon_Stop( entity ent )
{
- ArcCannon_Stop( entity )
+ ArcCannon_Stop( ent )
}
+#endif // CLIENT
function GetArcCannonChargeFraction( weapon )
{
if ( IsValid( weapon ) )
{
local chargeRatio = ARC_CANNON_DAMAGE_CHARGE_RATIO
- if( weapon.HasModDefined( "capacitor" ) && weapon.HasMod( "capacitor" ) )
+ if ( weapon.HasMod( "capacitor" ) )
chargeRatio = ARC_CANNON_CAPACITOR_CHARGE_RATIO
- if( weapon.GetWeaponModSetting( "is_burn_mod" ) )
+ if ( weapon.GetWeaponSettingBool( eWeaponVar.is_burn_mod ) )
chargeRatio = ARC_CANNON_DAMAGE_CHARGE_RATIO_BURN
return chargeRatio
}
return 0
+}
+
+function GetWeaponChargeFrac( weapon )
+{
+ if ( weapon.IsChargeWeapon() )
+ return weapon.GetWeaponChargeFraction()
+ return 1.0
} \ No newline at end of file
diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut
index 09faafa5..78879393 100644
--- a/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut
+++ b/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut
@@ -1,24 +1,50 @@
-ArcCannon_PrecacheFX( self )
+untyped
-function OnWeaponActivate( activateParams )
+global function MpTitanweaponArcCannon_Init
+
+global function OnWeaponActivate_titanweapon_arc_cannon
+global function OnWeaponDeactivate_titanweapon_arc_cannon
+global function OnWeaponReload_titanweapon_arc_cannon
+global function OnWeaponOwnerChanged_titanweapon_arc_cannon
+global function OnWeaponChargeBegin_titanweapon_arc_cannon
+global function OnWeaponChargeEnd_titanweapon_arc_cannon
+global function OnWeaponPrimaryAttack_titanweapon_arc_cannon
+
+const FX_EMP_BODY_HUMAN = $"P_emp_body_human"
+const FX_EMP_BODY_TITAN = $"P_emp_body_titan"
+
+#if SERVER
+global function OnWeaponNpcPrimaryAttack_titanweapon_arc_cannon
+#endif // #if SERVER
+
+void function MpTitanweaponArcCannon_Init()
+{
+ ArcCannon_PrecacheFX()
+
+ #if SERVER
+ AddDamageCallbackSourceID( eDamageSourceId.mp_titanweapon_arc_cannon, ArcRifleOnDamage )
+ #endif
+}
+
+void function OnWeaponActivate_titanweapon_arc_cannon( entity weapon )
{
- local weaponOwner = self.GetWeaponOwner()
- thread DelayedArcCannonStart( self, weaponOwner )
- if( !("weaponOwner" in self.s) )
- self.s.weaponOwner <- weaponOwner
+ entity weaponOwner = weapon.GetWeaponOwner()
+ thread DelayedArcCannonStart( weapon, weaponOwner )
+ if( !("weaponOwner" in weapon.s) )
+ weapon.s.weaponOwner <- weaponOwner
}
-function DelayedArcCannonStart( weapon, weaponOwner )
+function DelayedArcCannonStart( entity weapon, entity weaponOwner )
{
weapon.EndSignal( "WeaponDeactivateEvent" )
- wait 0
+ WaitFrame()
if ( IsValid( weapon ) && IsValid( weaponOwner ) && weapon == weaponOwner.GetActiveWeapon() )
{
if( weaponOwner.IsPlayer() )
{
- local modelEnt = weaponOwner.GetViewModelEntity()
+ entity modelEnt = weaponOwner.GetViewModelEntity()
if( IsValid( modelEnt ) && EntHasModelSet( modelEnt ) )
ArcCannon_Start( weapon )
}
@@ -29,91 +55,172 @@ function DelayedArcCannonStart( weapon, weaponOwner )
}
}
-function OnWeaponDeactivate( deactivateParams )
+void function OnWeaponDeactivate_titanweapon_arc_cannon( entity weapon )
{
- ArcCannon_ChargeEnd( self, self.s.weaponOwner )
- ArcCannon_Stop( self )
+ ArcCannon_ChargeEnd( weapon, expect entity( weapon.s.weaponOwner ) )
+ ArcCannon_Stop( weapon )
}
-function OnWeaponReload( reloadParams )
+void function OnWeaponReload_titanweapon_arc_cannon( entity weapon, int milestoneIndex )
{
- local reloadTime = self.GetWeaponInfoFileKeyField( "reload_time" )
- thread ArcCannon_HideIdleEffect( self, reloadTime ) //constant seems to help it sync up better
+ local reloadTime = weapon.GetWeaponInfoFileKeyField( "reload_time" )
+ thread ArcCannon_HideIdleEffect( weapon, reloadTime ) //constant seems to help it sync up better
}
-function OnWeaponOwnerChanged( changeParams )
+void function OnWeaponOwnerChanged_titanweapon_arc_cannon( entity weapon, WeaponOwnerChangedParams changeParams )
{
- if ( IsClient() )
- {
- local viewPlayer = GetLocalViewPlayer()
+ #if CLIENT
+ entity viewPlayer = GetLocalViewPlayer()
if ( changeParams.oldOwner != null && changeParams.oldOwner == viewPlayer )
{
- ArcCannon_ChargeEnd( self, changeParams.oldOwner )
- ArcCannon_Stop( self, changeParams.oldOwner )
+ ArcCannon_ChargeEnd( weapon, changeParams.oldOwner )
+ ArcCannon_Stop( weapon)
}
+
if ( changeParams.newOwner != null && changeParams.newOwner == viewPlayer )
- thread ArcCannon_HideIdleEffect( self, 0.25 )
- }
- else
- {
+ thread ArcCannon_HideIdleEffect( weapon, 0.25 )
+ #else
if ( changeParams.oldOwner != null )
{
- ArcCannon_ChargeEnd( self, changeParams.oldOwner )
- ArcCannon_Stop( self, changeParams.oldOwner )
+ ArcCannon_ChargeEnd( weapon, changeParams.oldOwner )
+ ArcCannon_Stop( weapon )
}
+
if ( changeParams.newOwner != null )
- thread ArcCannon_HideIdleEffect( self, 0.25 )
- }
+ thread ArcCannon_HideIdleEffect( weapon, 0.25 )
+ #endif
}
-function OnWeaponChargeBegin( chargeParams )
+bool function OnWeaponChargeBegin_titanweapon_arc_cannon( entity weapon )
{
- ArcCannon_ChargeBegin( self )
+ local stub = "this is here to suppress the untyped message. This can go away when the .s. usage is removed from this file."
+ #if SERVER
+ //if ( weapon.HasMod( "fastpacitor_push_apart" ) )
+ // weapon.GetWeaponOwner().StunMovementBegin( weapon.GetWeaponSettingFloat( eWeaponVar.charge_time ) )
+ #endif
+
+ ArcCannon_ChargeBegin( weapon )
+
+ return true
}
-function OnWeaponChargeEnd( chargeParams )
+void function OnWeaponChargeEnd_titanweapon_arc_cannon( entity weapon )
{
- ArcCannon_ChargeEnd( self )
+ ArcCannon_ChargeEnd( weapon, weapon )
}
-function OnWeaponPrimaryAttack( attackParams )
+var function OnWeaponPrimaryAttack_titanweapon_arc_cannon( entity weapon, WeaponPrimaryAttackParams attackParams )
{
- if ( self.HasMod( "capacitor" ) && self.GetWeaponChargeFraction() < GetArcCannonChargeFraction( self ) )
+ if ( weapon.HasMod( "capacitor" ) && weapon.GetWeaponChargeFraction() < GetArcCannonChargeFraction( weapon ) )
return 0
if ( !attackParams.firstTimePredicted )
return
- local fireRate = self.GetWeaponInfoFileKeyField( "fire_rate" )
- thread ArcCannon_HideIdleEffect( self, (1 / fireRate) )
- return FireArcCannon( self, attackParams )
-}
+ local fireRate = weapon.GetWeaponInfoFileKeyField( "fire_rate" )
+ thread ArcCannon_HideIdleEffect( weapon, (1 / fireRate) )
-function OnWeaponNpcPrimaryAttack( attackParams )
-{
- local fireRate = self.GetWeaponInfoFileKeyField( "fire_rate" )
- thread ArcCannon_HideIdleEffect( self, fireRate )
- return FireArcCannon( self, attackParams )
+ return FireArcCannon( weapon, attackParams )
}
-function OnWeaponStartZoomIn()
+#if SERVER
+var function OnWeaponNpcPrimaryAttack_titanweapon_arc_cannon( entity weapon, WeaponPrimaryAttackParams attackParams )
{
- HandleWeaponSoundZoomIn( self, "Weapon_Titan_ArcCannon.ADS_In" )
-}
+ local fireRate = weapon.GetWeaponInfoFileKeyField( "fire_rate" )
+ thread ArcCannon_HideIdleEffect( weapon, fireRate )
-function OnWeaponStartZoomOut()
-{
- HandleWeaponSoundZoomOut( self, "Weapon_Titan_ArcCannon.ADS_Out" )
+ return FireArcCannon( weapon, attackParams )
}
-/*
-function OnWeaponPrimaryAttackVMActivityToUse()
+void function ArcRifleOnDamage( entity ent, var damageInfo )
{
- local baseCharge = self.GetWeaponChargeFraction()
- local charge = clamp ( baseCharge * ( 1 / 0.7 ), 0.0, 1.0 )
+ vector pos = DamageInfo_GetDamagePosition( damageInfo )
+ entity attacker = DamageInfo_GetAttacker( damageInfo )
- if ( charge > 0.25 )
- return 1
+ EmitSoundOnEntity( ent, ARC_CANNON_TITAN_SCREEN_SFX )
+
+ if ( ent.IsPlayer() || ent.IsNPC() )
+ {
+ entity entToSlow = ent
+ entity soul = ent.GetTitanSoul()
+
+ if ( soul != null )
+ entToSlow = soul
+
+ StatusEffect_AddTimed( entToSlow, eStatusEffect.move_slow, 0.5, 2.0, 1.0 )
+ StatusEffect_AddTimed( entToSlow, eStatusEffect.dodge_speed_slow, 0.5, 2.0, 1.0 )
+ }
+
+ string tag = ""
+ asset effect
+
+ if ( ent.IsTitan() )
+ {
+ tag = "exp_torso_front"
+ effect = FX_EMP_BODY_TITAN
+ }
+ else if ( ChestFocusTarget( ent ) )
+ {
+ tag = "CHESTFOCUS"
+ effect = FX_EMP_BODY_HUMAN
+ }
+ else if ( IsAirDrone( ent ) )
+ {
+ tag = "HEADSHOT"
+ effect = FX_EMP_BODY_HUMAN
+ }
+ else if ( IsGunship( ent ) )
+ {
+ tag = "ORIGIN"
+ effect = FX_EMP_BODY_TITAN
+ }
+
+ if ( tag != "" )
+ {
+ float duration = 2.0
+ //thread EMP_FX( effect, ent, tag, duration )
+ }
+
+ if ( ent.IsTitan() )
+ {
+ if ( ent.IsPlayer() )
+ {
+ EmitSoundOnEntityOnlyToPlayer( ent, ent, "titan_energy_bulletimpact_3p_vs_1p" )
+ EmitSoundOnEntityExceptToPlayer( ent, ent, "titan_energy_bulletimpact_3p_vs_3p" )
+ }
+ else
+ {
+ EmitSoundOnEntity( ent, "titan_energy_bulletimpact_3p_vs_3p" )
+ }
+ }
else
- return 0
-}*/
+ {
+ if ( ent.IsPlayer() )
+ {
+ EmitSoundOnEntityOnlyToPlayer( ent, ent, "flesh_lavafog_deathzap_3p" )
+ EmitSoundOnEntityExceptToPlayer( ent, ent, "flesh_lavafog_deathzap_1p" )
+ }
+ else
+ {
+ EmitSoundOnEntity( ent, "flesh_lavafog_deathzap_1p" )
+ }
+ }
+
+}
+
+bool function ChestFocusTarget( entity ent )
+{
+ if ( IsSpectre( ent ) )
+ return true
+ if ( IsStalker( ent ) )
+ return true
+ if ( IsSuperSpectre( ent ) )
+ return true
+ if ( IsGrunt( ent ) )
+ return true
+ if ( IsPilot( ent ) )
+ return true
+
+ return false
+}
+#endif // #if SERVER