diff options
Diffstat (limited to 'Northstar.CustomServers/mod/scripts/vscripts/burnmeter')
-rw-r--r-- | Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut | 267 |
1 files changed, 192 insertions, 75 deletions
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut index fa6867b8..d4bc38d4 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut @@ -1,6 +1,8 @@ untyped global function BurnMeter_Init +global function ForceSetGlobalBurncardOverride +global function GetSelectedBurncardRefFromWeaponOrPlayer global function RunBurnCardUseFunc global function UseBurnCardWeapon global function UseBurnCardWeaponInCriticalSection @@ -8,10 +10,20 @@ global function BurnMeter_GiveRewardDirect global function GetBurnCardWeaponSkin global function InitBurnMeterPersistentData +const float PHASE_REWIND_LENGTH = 2.0 // taken from wraith portal in apex, assuming it's the same as tf2's const float PHASE_REWIND_PATH_SNAPSHOT_INTERVAL = 0.1 +const int PHASE_REWIND_MAX_SNAPSHOTS = int( PHASE_REWIND_LENGTH / PHASE_REWIND_PATH_SNAPSHOT_INTERVAL ) + const float AMPED_WEAPONS_LENGTH = 30.0 +const int MAPHACK_PULSE_COUNT = 4 +const float MAPHACK_PULSE_DELAY = 2.0 + +struct { + string forcedGlobalBurncardOverride = "" +} file + void function BurnMeter_Init() { // turret precaches @@ -24,35 +36,97 @@ void function BurnMeter_Init() BurnReward_GetByRef( "burnmeter_smart_pistol" ).rewardAvailableCallback = PlayerUsesSmartPistolBurncard BurnReward_GetByRef( "burnmeter_emergency_battery" ).rewardAvailableCallback = PlayerUsesBatteryBurncard BurnReward_GetByRef( "burnmeter_radar_jammer" ).rewardAvailableCallback = PlayerUsesRadarJammerBurncard - //BurnReward_GetByRef( "burnmeter_maphack" ).rewardAvailableCallback = - //BurnReward_GetByRef( "burnmeter_phase_rewind" ).rewardAvailableCallback = + BurnReward_GetByRef( "burnmeter_maphack" ).rewardAvailableCallback = PlayerUsesMaphackBurncard + BurnReward_GetByRef( "burnmeter_phase_rewind" ).rewardAvailableCallback = PlayerUsesPhaseRewindBurncard - // these ones aren't so important - BurnReward_GetByRef( "burnmeter_nuke_titan" ).rewardAvailableCallback = PlayerUsesNukeTitanBurncard // unused in vanilla, fun though + // these ones aren't so important, they're either for fd ( unsupported rn ) or unused //BurnReward_GetByRef( "burnmeter_harvester_shield" ).rewardAvailableCallback = BurnReward_GetByRef( "burnmeter_rodeo_grenade" ).rewardAvailableCallback = PlayerUsesRodeoGrenadeBurncard + BurnReward_GetByRef( "burnmeter_nuke_titan" ).rewardAvailableCallback = PlayerUsesNukeTitanBurncard // unused in vanilla, fun though // setup player callbacks AddCallback_GameStateEnter( eGameState.Playing, InitBurncardsForIntroPlayers ) AddCallback_OnClientConnected( InitBurncardsForLateJoiner ) AddCallback_OnPlayerRespawned( StartPhaseRewindLifetime ) + + // necessary signals + RegisterSignal( "StopAmpedWeapons" ) } -void function InitPlayerBurncards( entity player ) +void function ForceSetGlobalBurncardOverride( string ref ) { - int burnmeterSlot = player.GetPersistentVarAsInt( "burnmeterSlot" ) - player.SetPlayerNetInt( TOP_INVENTORY_ITEM_BURN_CARD_ID, burnmeterSlot ) + file.forcedGlobalBurncardOverride = ref +} + +string function GetSelectedBurncardRefFromWeaponOrPlayer( entity weapon, entity player ) +{ + // determine the burncard we're using + // in actual gameplay, this will always be the player's selected burncard + // however, if we want to manually give burncards and such, we want to make sure they'll still work + // so some extra work goes into this + + string ref = GetSelectedBurnCardRef( player ) + + if ( file.forcedGlobalBurncardOverride.len() > 0 ) + ref = file.forcedGlobalBurncardOverride - if ( BurnReward_GetById( burnmeterSlot ).ref == "burnmeter_phase_rewind" ) + if ( IsValid( weapon ) ) { - player.s.hasPhaseRewind <- true - - if ( IsAlive( player ) ) - thread PhaseRewindLifetime( player ) + // determine via weapon mods, this assumes weapon mod names are the same as burn refs, which works in practice but is a bit weird + // this does crash with the burnmeter_doublexp mod, but who cares, it doesn't get hit normally + if ( weapon.GetWeaponClassName() == "mp_ability_burncardweapon" ) + { + foreach ( string mod in weapon.GetMods() ) + if ( mod.find( "burnmeter_" ) == 0 ) + return mod + } + // determine via weapon name in the case of stuff like holopilot etc + else + { + // unfortunately, we have to hardcode this, we don't have a way of getting refs directly from weapons other than the burncard weapon + // this should be modular at some point, wish we could just iterate over burncards and find ones with the current weapon, but this isn't possible + switch ( weapon.GetWeaponClassName() ) + { + case "mp_ability_holopilot_nova": + return "burnmeter_holopilot_nova" + + case "mp_weapon_arc_trap": + return "burnmeter_arc_trap" + + case "mp_weapon_frag_drone": + return "burnmeter_ticks" + + case "mp_weapon_hard_cover": + return "burnmeter_hard_cover" + + case "mp_ability_turretweapon": + // turret has 2 burncards, antititan and antipilot + if( weapon.HasMod( "burnmeter_at_turret_weapon" ) || weapon.HasMod( "burnmeter_at_turret_weapon_inf" ) ) + return "burnmeter_at_turret_weapon" + else + return "burnmeter_ap_turret_weapon" + + // note: cloak and stim both have burn_card_weapon_mod mods, but they aren't used and don't call burncard code at all, likely for tf1 infinite stim/cloak burncards? + + default: + print( "tried to use unknown burncard weapon " + weapon.GetWeaponClassName() ) + return "burnmeter_amped_weapons" + } + } } - else - player.s.hasPhaseRewind <- false + + return ref +} + +void function InitPlayerBurncards( entity player ) +{ + string ref = GetSelectedBurncardRefFromWeaponOrPlayer( null, player ) + BurnReward reward = BurnReward_GetByRef( ref ) + player.SetPlayerNetInt( TOP_INVENTORY_ITEM_BURN_CARD_ID, reward.id ) + + if ( IsAlive( player ) ) + thread PhaseRewindLifetime( player ) } void function InitBurncardsForIntroPlayers() @@ -71,8 +145,7 @@ void function InitBurncardsForLateJoiner( entity player ) void function StartPhaseRewindLifetime( entity player ) { - if ( "hasPhaseRewind" in player.s && player.s.hasPhaseRewind ) - thread PhaseRewindLifetime( player ) + thread PhaseRewindLifetime( player ) } void function PhaseRewindLifetime( entity player ) @@ -82,12 +155,28 @@ void function PhaseRewindLifetime( entity player ) OnThreadEnd( function() : ( player ) { - + player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions.clear() }) while ( true ) { + PhaseRewindData rewindData + rewindData.origin = player.GetOrigin() + rewindData.angles = player.GetAngles() + rewindData.velocity = player.GetVelocity() + rewindData.wasInContextAction = player.ContextAction_IsActive() + rewindData.wasCrouched = player.IsCrouched() + if ( player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions.len() >= PHASE_REWIND_MAX_SNAPSHOTS ) + { + // shift all snapshots left + for ( int i = 0; i < PHASE_REWIND_MAX_SNAPSHOTS - 1; i++ ) + player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions[ i ] = player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions[ i + 1 ] + + player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions[ PHASE_REWIND_MAX_SNAPSHOTS - 1 ] = rewindData + } + else + player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions.append( rewindData ) wait PHASE_REWIND_PATH_SNAPSHOT_INTERVAL } @@ -100,62 +189,9 @@ void function RunBurnCardUseFunc( entity player, string itemRef ) ( expect void functionref( entity ) ( func ) )( player ) } -string function GetBurncardRefFromWeaponOrPlayer( entity weapon, entity player ) -{ - // determine the burncard we're using - // in actual gameplay, this will always be the player's selected burncard - // however, if we want to manually give burncards and such, we want to make sure they'll still work - // so some extra work goes into this - - string ref = GetSelectedBurnCardRef( player ) - // determine via weapon mods, this assumes weapon mod names are the same as burn refs, which works in practice but is a bit weird - // though, this does crash with the burnmeter_doublexp mod - if ( weapon.GetWeaponClassName() == "mp_ability_burncardweapon" ) - { - foreach ( string mod in weapon.GetMods() ) - if ( mod.find( "burnmeter_" ) == 0 ) - return mod - } - // determine via weapon name in the case of stuff like holopilot etc - else - { - // unfortunately, we have to hardcode this, we don't have a way of getting refs directly from weapons other than the burncard weapon - // this should be modular at some point, wish we could just iterate over burncards and find ones with the current weapon, but this isn't possible - switch ( weapon.GetWeaponClassName() ) - { - case "mp_ability_holopilot_nova": - return "burnmeter_holopilot_nova" - - case "mp_weapon_arc_trap": - return "burnmeter_arc_trap" - - case "mp_weapon_frag_drone": - return "burnmeter_ticks" - - case "mp_weapon_hard_cover": - return "burnmeter_hard_cover" - - case "mp_ability_turretweapon": - // turret has 2 burncards, antititan and antipilot - if( weapon.HasMod( "burnmeter_at_turret_weapon" ) || weapon.HasMod( "burnmeter_at_turret_weapon_inf" ) ) - return "burnmeter_at_turret_weapon" - else - return "burnmeter_ap_turret_weapon" - - // note: cloak and stim both have burn_card_weapon_mod mods, but they aren't used, likely for infinite stim/cloak burncards? - - default: - print( "tried to use unknown burncard weapon " + weapon.GetWeaponClassName() ) - return "burnmeter_amped_weapons" // shouldn't hit this - } - } - - return ref -} - void function UseBurnCardWeapon( entity weapon, entity player ) { - string ref = GetBurncardRefFromWeaponOrPlayer( weapon, player ) + string ref = GetSelectedBurncardRefFromWeaponOrPlayer( weapon, player ) Remote_CallFunction_Replay( player, "ServerCallback_RewardUsed", BurnReward_GetByRef( ref ).id ) RunBurnCardUseFunc( player, ref ) @@ -163,12 +199,12 @@ void function UseBurnCardWeapon( entity weapon, entity player ) // dont remove in RunBurnCardUseFunc because it can be called in non-burn_card_weapon_mod contexts // TODO: currently not sure how burncards can be stacked ( max clipcount for all burncards is 1, so can't just set that ) // if this gets figured out, add a conditional check here to prevent removes if they've got burncards left - player.TakeOffhandWeapon( 4 ) + player.TakeWeapon( BurnReward_GetByRef( ref ).weaponName ) } void function UseBurnCardWeaponInCriticalSection( entity weapon, entity ownerPlayer ) { - // ignoring critical section stuff, assuming it was necessary in tf1 where burncards were part of inventory + // ignoring critical section stuff, assuming it was necessary in tf1 where burncards were part of inventory, but not here UseBurnCardWeapon( weapon, ownerPlayer ) } @@ -179,7 +215,7 @@ void function BurnMeter_GiveRewardDirect( entity player, string itemRef ) int function GetBurnCardWeaponSkin( entity weapon ) { - return GetBoostSkin( GetBurncardRefFromWeaponOrPlayer( weapon, weapon.GetOwner() ) ) + return GetBoostSkin( GetSelectedBurncardRefFromWeaponOrPlayer( weapon, weapon.GetOwner() ) ) } // stub @@ -252,6 +288,77 @@ void function PlayerUsesRadarJammerBurncard( entity player ) } } +void function PlayerUsesMaphackBurncard( entity player ) +{ + thread PlayerUsesMaphackBurncardThreaded( player ) +} + +void function PlayerUsesMaphackBurncardThreaded( entity player ) +{ + player.EndSignal( "OnDestroy" ) + player.EndSignal( "OnDeath" ) + + // todo: potentially look into ScanMinimap in _passives for doing this better? boost is pretty likely based off it pretty heavily + for ( int i = 0; i < MAPHACK_PULSE_COUNT; i++ ) + { + EmitSoundOnEntityOnlyToPlayer( player, player, "Burn_Card_Map_Hack_Radar_Pulse_V1_1P" ) + + foreach ( entity otherPlayer in GetPlayerArray() ) + { + Remote_CallFunction_Replay( otherPlayer, "ServerCallback_SonarPulseFromPosition", player.GetOrigin().x, player.GetOrigin().y, player.GetOrigin().z, SONAR_GRENADE_RADIUS ) + + if ( otherPlayer.GetTeam() != player.GetTeam() ) + { + StatusEffect_AddTimed( player, eStatusEffect.maphack_detected, 1.0, MAPHACK_PULSE_DELAY / 2, 0.0 ) + SonarStart( otherPlayer, player.GetOrigin(), player.GetTeam(), player ) + } + } + + wait MAPHACK_PULSE_DELAY + } +} + +void function PlayerUsesPhaseRewindBurncard( entity player ) +{ + thread PlayerUsesPhaseRewindBurncardThreaded( player ) +} + +void function PlayerUsesPhaseRewindBurncardThreaded( entity player ) +{ + player.EndSignal( "OnDestroy" ) + player.EndSignal( "OnDeath" ) + + entity mover = CreateScriptMover( player.GetOrigin(), player.GetAngles() ) + player.SetParent( mover, "REF" ) + + OnThreadEnd( function() : ( player, mover ) + { + CancelPhaseShift( player ) + player.DeployWeapon() + player.SetPredictionEnabled( true ) + player.ClearParent() + ViewConeFree( player ) + mover.Destroy() + }) + + array<PhaseRewindData> positions = clone player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions + + ViewConeZero( player ) + player.HolsterWeapon() + player.SetPredictionEnabled( false ) + PhaseShift( player, 0.0, positions.len() * PHASE_REWIND_PATH_SNAPSHOT_INTERVAL * 1.5 ) + + for ( int i = positions.len() - 1; i > -1; i-- ) + { + mover.NonPhysicsMoveTo( positions[ i ].origin, PHASE_REWIND_PATH_SNAPSHOT_INTERVAL, 0, 0 ) + mover.NonPhysicsRotateTo( positions[ i ].angles, PHASE_REWIND_PATH_SNAPSHOT_INTERVAL, 0, 0 ) + wait PHASE_REWIND_PATH_SNAPSHOT_INTERVAL + } + + // this isn't vanilla but it's cool lol, should prolly remove it tho + player.SetVelocity( -positions[ positions.len() - 1 ].velocity ) +} + void function PlayerUsesNukeTitanBurncard( entity player ) { thread PlayerUsesNukeBurncardThreaded( player ) @@ -292,5 +399,15 @@ void function PlayerUsesNukeBurncardThreaded( entity player ) void function PlayerUsesRodeoGrenadeBurncard( entity player ) { - player.SetPlayerNetInt( "numSuperRodeoGrenades", 7player.GetPlayerNetInt( "numSuperRodeoGrenades" ) + 1 ) + player.SetPlayerNetInt( "numSuperRodeoGrenades", player.GetPlayerNetInt( "numSuperRodeoGrenades" ) + 1 ) +} + +// unused burncard that's mentioned in a few areas and has a validiation function in sh_burnmeter ( BurnMeter_SummonReaperCanUse ), thought it'd be neat to add it +void function PlayerUsesReaperfallBurncard( entity player ) +{ + Point spawnpoint = GetTitanReplacementPoint( player, false ) + entity reaper = CreateSuperSpectre( player.GetTeam(), spawnpoint.origin, spawnpoint.angles ) + DispatchSpawn( reaper ) + + thread SuperSpectre_WarpFall( reaper ) }
\ No newline at end of file |