diff options
Diffstat (limited to 'Northstar.CustomServers')
8 files changed, 610 insertions, 550 deletions
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut index 3151a0f2..3eb6bda6 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut @@ -1,435 +1,441 @@ -untyped - -global function BurnMeter_Init -global function ForceSetGlobalBurncardOverride -global function GetSelectedBurncardRefFromWeaponOrPlayer -global function RunBurnCardUseFunc -global function UseBurnCardWeapon -global function UseBurnCardWeaponInCriticalSection -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 - // do we have to cache these on client? release builds sure don't - PrecacheModel( Dev_GetAISettingAssetByKeyField_Global( "npc_turret_sentry_burn_card_ap", "DefaultModelName" ) ) - PrecacheModel( Dev_GetAISettingAssetByKeyField_Global( "npc_turret_sentry_burn_card_at", "DefaultModelName" ) ) - - // setup burncard use funcs - BurnReward_GetByRef( "burnmeter_amped_weapons" ).rewardAvailableCallback = PlayerUsesAmpedWeaponsBurncard - 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 = PlayerUsesMaphackBurncard - BurnReward_GetByRef( "burnmeter_phase_rewind" ).rewardAvailableCallback = PlayerUsesPhaseRewindBurncard - - // 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 ) - AddCallback_OnTitanBecomesPilot( RemoveAmpedWeaponsForTitanPilot ) - - // necessary signals - RegisterSignal( "StopAmpedWeapons" ) -} - -void function ForceSetGlobalBurncardOverride( string ref ) -{ - 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 ( IsValid( weapon ) ) - { - // 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" - } - } - } - - 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() -{ - // gotta do this, since sh_burnmeter uses this netint - foreach ( entity player in GetPlayerArray() ) - InitPlayerBurncards( player ) -} - -void function InitBurncardsForLateJoiner( entity player ) -{ - // gotta do this, since sh_burnmeter uses this netint - if ( GetGameState() > eGameState.Prematch ) - InitPlayerBurncards( player ) -} - -void function StartPhaseRewindLifetime( entity player ) -{ - thread PhaseRewindLifetime( player ) -} - -void function PhaseRewindLifetime( entity player ) -{ - player.EndSignal( "OnDestroy" ) - player.EndSignal( "OnDeath" ) - - 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 - } -} - -void function RunBurnCardUseFunc( entity player, string itemRef ) -{ - void functionref( entity ) ornull func = BurnReward_GetByRef( itemRef ).rewardAvailableCallback - if ( func != null ) - ( expect void functionref( entity ) ( func ) )( player ) -} - -void function UseBurnCardWeapon( entity weapon, entity player ) -{ - string ref = GetSelectedBurncardRefFromWeaponOrPlayer( weapon, player ) - - Remote_CallFunction_Replay( player, "ServerCallback_RewardUsed", BurnReward_GetByRef( ref ).id ) - RunBurnCardUseFunc( player, ref ) - - // 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 - if ( PlayerEarnMeter_IsRewardAvailable( player ) ) - PlayerEarnMeter_SetRewardUsed( player ) - - 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, but not here - UseBurnCardWeapon( weapon, ownerPlayer ) -} - -void function BurnMeter_GiveRewardDirect( entity player, string itemRef ) -{ - -} - -int function GetBurnCardWeaponSkin( entity weapon ) -{ - return GetBoostSkin( GetSelectedBurncardRefFromWeaponOrPlayer( weapon, weapon.GetOwner() ) ) -} - -// stub -void function InitBurnMeterPersistentData( entity player ) -{} - - -// burncard use funcs - -void function PlayerUsesAmpedWeaponsBurncard( entity player ) -{ - thread PlayerUsesAmpedWeaponsBurncardThreaded( player ) -} - -void function PlayerUsesAmpedWeaponsBurncardThreaded( entity player ) -{ - array<entity> weapons = player.GetMainWeapons() - //weapons.extend( player.GetOffhandWeapons() ) // idk? unsure of vanilla behaviour here - foreach ( entity weapon in weapons ) - { - weapon.RemoveMod( "silencer" ) // both this and the burnmod will override firing fx, if a second one overrides this we crash - foreach ( string mod in GetWeaponBurnMods( weapon.GetWeaponClassName() ) ) - { - // catch incompatibilities just in case - try - { - weapon.AddMod( mod ) - } - catch( ex ) - { - weapons.removebyvalue( weapon ) - } - } - - // needed to display amped weapon time left - weapon.SetScriptFlags0( weapon.GetScriptFlags0() | WEAPONFLAG_AMPED ) - weapon.SetScriptTime0( Time() + AMPED_WEAPONS_LENGTH ) - } - - wait AMPED_WEAPONS_LENGTH - - // note: weapons may have been destroyed or picked up by other people by this point, so need to verify this - foreach ( entity weapon in weapons ) - { - if ( !IsValid( weapon ) ) - continue - - foreach ( string mod in GetWeaponBurnMods( weapon.GetWeaponClassName() ) ) - weapon.RemoveMod( mod ) - - weapon.SetScriptFlags0( weapon.GetScriptFlags0() & ~WEAPONFLAG_AMPED ) - } -} - -void function RemoveAmpedWeaponsForTitanPilot( entity player, entity titan ) -{ - foreach ( entity weapon in player.GetMainWeapons() ) - foreach ( string mod in GetWeaponBurnMods( weapon.GetWeaponClassName() ) ) - weapon.RemoveMod( mod ) -} - -void function PlayerUsesSmartPistolBurncard( entity player ) -{ - // take secondary weapon - array<entity> sidearms = player.GetMainWeapons() - if ( sidearms.len() > 1 ) - player.TakeWeaponNow( sidearms[ 1 ].GetWeaponClassName() ) // take secondary weapon - - player.GiveWeapon( "mp_weapon_smart_pistol" ) - player.SetActiveWeaponByName( "mp_weapon_smart_pistol" ) - - // do we need to track the player losing smart pistol, then give their old weapon back? idk not implementing for now, check later -} - -void function PlayerUsesBatteryBurncard( entity player ) -{ - Rodeo_GiveBatteryToPlayer( player ) -} - -void function PlayerUsesRadarJammerBurncard( entity player ) -{ - foreach ( entity otherPlayer in GetPlayerArray() ) - { - MessageToPlayer( otherPlayer, eEventNotifications.BurnMeter_RadarJammerUsed, player ) - - if ( otherPlayer.GetTeam() != player.GetTeam() ) - StatusEffect_AddTimed( otherPlayer, eStatusEffect.minimap_jammed, 1.0, RADAR_JAM_TIME, RADAR_JAM_TIME ) - } -} - -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 ) -} - -void function PlayerUsesNukeBurncardThreaded( entity player ) -{ - // if this is given manually ( i.e. not the equipped burnreward in inventory ), this will run at bad times - // so do this check here, yes, this will cause people to lose their cards and get nothing, but better than free titan regens - if ( !BurnMeterPlayer_CanUseReward( player, BurnReward_GetByRef( "burnmeter_nuke_titan" ) ) ) - return - - float ownedFrac = PlayerEarnMeter_GetOwnedFrac( player ) - - // use player's titan loadout, but with warpfall so faster and no dome - TitanLoadoutDef titanLoadout = GetTitanLoadoutForPlayer( player ) - titanLoadout.passive3 = "pas_warpfall" - - thread CreateTitanForPlayerAndHotdrop( player, GetTitanReplacementPoint( player, false ) ) - - entity titan = player.GetPetTitan() - SetTeam( titan, TEAM_UNASSIGNED ) // make it so you can kill yourself lol - DoomTitan( titan ) - NPC_SetNuclearPayload( titan ) - // this should get run after the vanilla set_usable's event, so titan is never embarkable - // embarking a titan in this state WILL kill the server so uhh, pretty bad - AddAnimEvent( titan, "set_usable", void function( entity titan ) { titan.UnsetUsable() } ) - - titan.WaitSignal( "TitanHotDropComplete" ) - AutoTitan_SelfDestruct( titan ) - - while ( PlayerEarnMeter_GetMode( player ) == eEarnMeterMode.PET ) - WaitFrame() - - // restore original earnmeter values, no way to set earned that's exposed unfortunately - PlayerEarnMeter_SetOwnedFrac( player, ownedFrac ) -} - -void function PlayerUsesRodeoGrenadeBurncard( entity player ) -{ - 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 ) +untyped
+
+global function BurnMeter_Init
+global function ForceSetGlobalBurncardOverride
+global function GetSelectedBurncardRefFromWeaponOrPlayer
+global function RunBurnCardUseFunc
+global function UseBurnCardWeapon
+global function UseBurnCardWeaponInCriticalSection
+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
+ // do we have to cache these on client? release builds sure don't
+ PrecacheModel( Dev_GetAISettingAssetByKeyField_Global( "npc_turret_sentry_burn_card_ap", "DefaultModelName" ) )
+ PrecacheModel( Dev_GetAISettingAssetByKeyField_Global( "npc_turret_sentry_burn_card_at", "DefaultModelName" ) )
+
+ // setup burncard use funcs
+ BurnReward_GetByRef( "burnmeter_amped_weapons" ).rewardAvailableCallback = PlayerUsesAmpedWeaponsBurncard
+ 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 = PlayerUsesMaphackBurncard
+ BurnReward_GetByRef( "burnmeter_phase_rewind" ).rewardAvailableCallback = PlayerUsesPhaseRewindBurncard
+
+ // 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 )
+ AddCallback_OnTitanBecomesPilot( RemoveAmpedWeaponsForTitanPilot )
+
+ // necessary signals
+ RegisterSignal( "StopAmpedWeapons" )
+}
+
+void function ForceSetGlobalBurncardOverride( string ref )
+{
+ 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 ( IsValid( weapon ) )
+ {
+ // 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"
+ }
+ }
+ }
+
+ 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()
+{
+ // gotta do this, since sh_burnmeter uses this netint
+ foreach ( entity player in GetPlayerArray() )
+ InitPlayerBurncards( player )
+}
+
+void function InitBurncardsForLateJoiner( entity player )
+{
+ // gotta do this, since sh_burnmeter uses this netint
+ if ( GetGameState() > eGameState.Prematch )
+ InitPlayerBurncards( player )
+}
+
+void function StartPhaseRewindLifetime( entity player )
+{
+ thread PhaseRewindLifetime( player )
+}
+
+void function PhaseRewindLifetime( entity player )
+{
+ player.EndSignal( "OnDestroy" )
+ player.EndSignal( "OnDeath" )
+
+ 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
+ }
+}
+
+void function RunBurnCardUseFunc( entity player, string itemRef )
+{
+ void functionref( entity ) ornull func = BurnReward_GetByRef( itemRef ).rewardAvailableCallback
+ if ( func != null )
+ ( expect void functionref( entity ) ( func ) )( player )
+}
+
+void function UseBurnCardWeapon( entity weapon, entity player )
+{
+ string ref = GetSelectedBurncardRefFromWeaponOrPlayer( weapon, player )
+
+ Remote_CallFunction_Replay( player, "ServerCallback_RewardUsed", BurnReward_GetByRef( ref ).id )
+ RunBurnCardUseFunc( player, ref )
+
+ // 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
+ if ( PlayerEarnMeter_IsRewardAvailable( player ) )
+ PlayerEarnMeter_SetRewardUsed( player )
+
+ 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, but not here
+ UseBurnCardWeapon( weapon, ownerPlayer )
+}
+
+void function BurnMeter_GiveRewardDirect( entity player, string itemRef )
+{
+
+}
+
+int function GetBurnCardWeaponSkin( entity weapon )
+{
+ return GetBoostSkin( GetSelectedBurncardRefFromWeaponOrPlayer( weapon, weapon.GetOwner() ) )
+}
+
+// stub
+void function InitBurnMeterPersistentData( entity player )
+{}
+
+
+// burncard use funcs
+
+void function PlayerUsesAmpedWeaponsBurncard( entity player )
+{
+ thread PlayerUsesAmpedWeaponsBurncardThreaded( player )
+}
+
+void function PlayerUsesAmpedWeaponsBurncardThreaded( entity player )
+{
+ array<entity> weapons = player.GetMainWeapons()
+ //weapons.extend( player.GetOffhandWeapons() ) // idk? unsure of vanilla behaviour here
+ foreach ( entity weapon in weapons )
+ {
+ weapon.RemoveMod( "silencer" ) // both this and the burnmod will override firing fx, if a second one overrides this we crash
+ foreach ( string mod in GetWeaponBurnMods( weapon.GetWeaponClassName() ) )
+ {
+ // catch incompatibilities just in case
+ try
+ {
+ weapon.AddMod( mod )
+ }
+ catch( ex )
+ {
+ weapons.removebyvalue( weapon )
+ }
+ }
+
+ // needed to display amped weapon time left
+ weapon.SetScriptFlags0( weapon.GetScriptFlags0() | WEAPONFLAG_AMPED )
+ weapon.SetScriptTime0( Time() + AMPED_WEAPONS_LENGTH )
+ }
+
+ wait AMPED_WEAPONS_LENGTH
+
+ // note: weapons may have been destroyed or picked up by other people by this point, so need to verify this
+ foreach ( entity weapon in weapons )
+ {
+ if ( !IsValid( weapon ) )
+ continue
+
+ foreach ( string mod in GetWeaponBurnMods( weapon.GetWeaponClassName() ) )
+ weapon.RemoveMod( mod )
+
+ weapon.SetScriptFlags0( weapon.GetScriptFlags0() & ~WEAPONFLAG_AMPED )
+ }
+}
+
+void function RemoveAmpedWeaponsForTitanPilot( entity player, entity titan )
+{
+ foreach ( entity weapon in player.GetMainWeapons() )
+ foreach ( string mod in GetWeaponBurnMods( weapon.GetWeaponClassName() ) )
+ weapon.RemoveMod( mod )
+}
+
+void function PlayerUsesSmartPistolBurncard( entity player )
+{
+ // take secondary weapon
+ array<entity> sidearms = player.GetMainWeapons()
+ if ( sidearms.len() > 1 )
+ player.TakeWeaponNow( sidearms[ 1 ].GetWeaponClassName() ) // take secondary weapon
+
+ player.GiveWeapon( "mp_weapon_smart_pistol" )
+ player.SetActiveWeaponByName( "mp_weapon_smart_pistol" )
+
+ // do we need to track the player losing smart pistol, then give their old weapon back? idk not implementing for now, check later
+}
+
+void function PlayerUsesBatteryBurncard( entity player )
+{
+ Rodeo_GiveBatteryToPlayer( player )
+}
+
+void function PlayerUsesRadarJammerBurncard( entity player )
+{
+ foreach ( entity otherPlayer in GetPlayerArray() )
+ {
+ MessageToPlayer( otherPlayer, eEventNotifications.BurnMeter_RadarJammerUsed, player )
+
+ if ( otherPlayer.GetTeam() != player.GetTeam() )
+ StatusEffect_AddTimed( otherPlayer, eStatusEffect.minimap_jammed, 1.0, RADAR_JAM_TIME, RADAR_JAM_TIME )
+ }
+}
+
+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" )
+ array<entity> aliveplayers = GetPlayerArray()
+ 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() && aliveplayers.find(otherPlayer) != -1 && aliveplayers.find(player) != -1 )
+ {
+ StatusEffect_AddTimed( otherPlayer, eStatusEffect.maphack_detected, 1.0, MAPHACK_PULSE_DELAY / 2, 0.0 )
+ SonarStart( otherPlayer, player.GetOrigin(), player.GetTeam(), player )
+ IncrementSonarPerTeam( player.GetTeam() )
+ }
+ }
+ wait MAPHACK_PULSE_DELAY
+ foreach ( entity otherPlayer in GetPlayerArray() ) {
+ if ( otherPlayer.GetTeam() != player.GetTeam() && aliveplayers.find(otherPlayer) != -1 && aliveplayers.find(player) != -1 ) {
+ SonarEnd (otherPlayer, player.GetTeam() )
+ DecrementSonarPerTeam( player.GetTeam() )
+ }
+ }
+ }
+}
+
+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 )
+}
+
+void function PlayerUsesNukeBurncardThreaded( entity player )
+{
+ // if this is given manually ( i.e. not the equipped burnreward in inventory ), this will run at bad times
+ // so do this check here, yes, this will cause people to lose their cards and get nothing, but better than free titan regens
+ if ( !BurnMeterPlayer_CanUseReward( player, BurnReward_GetByRef( "burnmeter_nuke_titan" ) ) )
+ return
+
+ float ownedFrac = PlayerEarnMeter_GetOwnedFrac( player )
+
+ // use player's titan loadout, but with warpfall so faster and no dome
+ TitanLoadoutDef titanLoadout = GetTitanLoadoutForPlayer( player )
+ titanLoadout.passive3 = "pas_warpfall"
+
+ thread CreateTitanForPlayerAndHotdrop( player, GetTitanReplacementPoint( player, false ) )
+
+ entity titan = player.GetPetTitan()
+ SetTeam( titan, TEAM_UNASSIGNED ) // make it so you can kill yourself lol
+ DoomTitan( titan )
+ NPC_SetNuclearPayload( titan )
+ // this should get run after the vanilla set_usable's event, so titan is never embarkable
+ // embarking a titan in this state WILL kill the server so uhh, pretty bad
+ AddAnimEvent( titan, "set_usable", void function( entity titan ) { titan.UnsetUsable() } )
+
+ titan.WaitSignal( "TitanHotDropComplete" )
+ AutoTitan_SelfDestruct( titan )
+
+ while ( PlayerEarnMeter_GetMode( player ) == eEarnMeterMode.PET )
+ WaitFrame()
+
+ // restore original earnmeter values, no way to set earned that's exposed unfortunately
+ PlayerEarnMeter_SetOwnedFrac( player, ownedFrac )
+}
+
+void function PlayerUsesRodeoGrenadeBurncard( entity player )
+{
+ 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 diff --git a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut index a4f23b85..b861ed9f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut @@ -103,11 +103,20 @@ void function EvacEpilogue() if ( canRunEvac ) { - SetRespawnsEnabled( false ) + thread SetRespawnAndWait( false ) thread Evac( GetOtherTeam( winner ), EVAC_INITIAL_WAIT, EVAC_ARRIVAL_TIME, EVAC_WAIT_TIME, EvacEpiloguePlayerCanBoard, EvacEpilogueShouldLeaveEarly, EvacEpilogueCompleted ) } else - thread EvacEpilogueCompleted( null ) // this is hacky but like, this also shouldn't really be hit in normal gameplay + { + thread SetRespawnAndWait( false ) //prevent respawns during the fade to black, should only be an issue if the match is a draw + thread EvacEpilogueCompleted( null ) //this is hacky but like, this also shouldn't really be hit in normal gameplay + } +} + +void function SetRespawnAndWait(bool mode) +{ + wait GAME_EPILOGUE_PLAYER_RESPAWN_LEEWAY + SetRespawnsEnabled( mode ) } bool function EvacEpiloguePlayerCanBoard( entity dropship, entity player ) @@ -386,4 +395,4 @@ void function EvacDropshipKilled( entity dropship, var damageInfo ) player.Die( DamageInfo_GetAttacker( damageInfo ), DamageInfo_GetWeapon( damageInfo ), { damageSourceId = eDamageSourceId.evac_dropship_explosion, scriptType = DF_GIB } ) } } -}
\ No newline at end of file +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut index 4e62e8c5..7eec7c89 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut @@ -1,15 +1,27 @@ -global function GamemodePs_Init - -void function GamemodePs_Init() -{ - Riff_ForceTitanAvailability( eTitanAvailability.Never ) - - AddCallback_OnPlayerKilled( GiveScoreForPlayerKill ) - ScoreEvent_SetupEarnMeterValuesForMixedModes() -} - -void function GiveScoreForPlayerKill( entity victim, entity attacker, var damageInfo ) -{ - if ( victim != attacker && victim.IsPlayer() && attacker.IsPlayer() ) - AddTeamScore( attacker.GetTeam(), 1 ) +global function GamemodePs_Init
+
+void function GamemodePs_Init()
+{
+ Riff_ForceTitanAvailability( eTitanAvailability.Never )
+
+ AddCallback_OnPlayerKilled( GiveScoreForPlayerKill )
+ ScoreEvent_SetupEarnMeterValuesForMixedModes()
+ SetTimeoutWinnerDecisionFunc( CheckScoreForDraw )
+
+}
+
+void function GiveScoreForPlayerKill( entity victim, entity attacker, var damageInfo )
+{
+ if ( victim != attacker && victim.IsPlayer() && attacker.IsPlayer() || GetGameState() != eGameState.Playing )
+ AddTeamScore( attacker.GetTeam(), 1 )
+}
+
+int function CheckScoreForDraw()
+{
+ if (GameRules_GetTeamScore(TEAM_IMC) > GameRules_GetTeamScore(TEAM_MILITIA))
+ return TEAM_IMC
+ else if (GameRules_GetTeamScore(TEAM_MILITIA) > GameRules_GetTeamScore(TEAM_IMC))
+ return TEAM_MILITIA
+
+ return TEAM_UNASSIGNED
}
\ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut index cef0af6b..3bc11c3a 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut @@ -25,6 +25,7 @@ void function GamemodeSpeedball_Init() AddCallback_OnTouchHealthKit( "item_flag", OnFlagCollected ) AddCallback_OnPlayerKilled( OnPlayerKilled ) SetTimeoutWinnerDecisionFunc( TimeoutCheckFlagHolder ) + AddCallback_OnRoundEndCleanup ( ResetFlag ) ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() ) ClassicMP_ForceDisableEpilogue( true ) @@ -103,7 +104,9 @@ void function DropFlag() file.flag.ClearParent() file.flag.SetAngles( < 0, 0, 0 > ) SetGlobalNetEnt( "flagCarrier", file.flag ) - EmitSoundOnEntityOnlyToPlayer( file.flagCarrier, file.flagCarrier, "UI_CTF_1P_FlagDrop" ) + + if ( IsValid( file.flagCarrier ) ) + EmitSoundOnEntityOnlyToPlayer( file.flagCarrier, file.flagCarrier, "UI_CTF_1P_FlagDrop" ) foreach ( entity player in GetPlayerArray() ) MessageToPlayer( player, eEventNotifications.SPEEDBALL_FlagDropped, file.flagCarrier ) @@ -127,4 +130,4 @@ int function TimeoutCheckFlagHolder() return TEAM_UNASSIGNED return file.flagCarrier.GetTeam() -}
\ No newline at end of file +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut index 5dd8a403..ba180790 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut @@ -1,20 +1,31 @@ -global function GamemodeTdm_Init -global function RateSpawnpoints_Directional - -void function GamemodeTdm_Init() -{ - AddCallback_OnPlayerKilled( GiveScoreForPlayerKill ) - ScoreEvent_SetupEarnMeterValuesForMixedModes() -} - -void function GiveScoreForPlayerKill( entity victim, entity attacker, var damageInfo ) -{ - if ( victim != attacker && victim.IsPlayer() && attacker.IsPlayer() ) - AddTeamScore( attacker.GetTeam(), 1 ) -} - -void function RateSpawnpoints_Directional( int checkclass, array<entity> spawnpoints, int team, entity player ) -{ - // temp - RateSpawnpoints_Generic( checkclass, spawnpoints, team, player ) +global function GamemodeTdm_Init
+global function RateSpawnpoints_Directional
+
+void function GamemodeTdm_Init()
+{
+ AddCallback_OnPlayerKilled( GiveScoreForPlayerKill )
+ ScoreEvent_SetupEarnMeterValuesForMixedModes()
+ SetTimeoutWinnerDecisionFunc( CheckScoreForDraw )
+}
+
+void function GiveScoreForPlayerKill( entity victim, entity attacker, var damageInfo )
+{
+ if ( victim != attacker && victim.IsPlayer() && attacker.IsPlayer() || GetGameState() != eGameState.Playing )
+ AddTeamScore( attacker.GetTeam(), 1 )
+}
+
+void function RateSpawnpoints_Directional( int checkclass, array<entity> spawnpoints, int team, entity player )
+{
+ // temp
+ RateSpawnpoints_Generic( checkclass, spawnpoints, team, player )
+}
+
+int function CheckScoreForDraw()
+{
+ if (GameRules_GetTeamScore(TEAM_IMC) > GameRules_GetTeamScore(TEAM_MILITIA))
+ return TEAM_IMC
+ else if (GameRules_GetTeamScore(TEAM_MILITIA) > GameRules_GetTeamScore(TEAM_IMC))
+ return TEAM_MILITIA
+
+ return TEAM_UNASSIGNED
}
\ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut index 9e5d95ba..c72fcb0d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut @@ -1,76 +1,87 @@ -global function GamemodeTTDM_Init - -const float TTDMIntroLength = 15.0 - -void function GamemodeTTDM_Init() -{ - Riff_ForceSetSpawnAsTitan( eSpawnAsTitan.Always ) - Riff_ForceTitanExitEnabled( eTitanExitEnabled.Never ) - TrackTitanDamageInPlayerGameStat( PGS_ASSAULT_SCORE ) - ScoreEvent_SetupEarnMeterValuesForMixedModes() - SetLoadoutGracePeriodEnabled( false ) - - ClassicMP_SetCustomIntro( TTDMIntroSetup, TTDMIntroLength ) - ClassicMP_ForceDisableEpilogue( true ) - - AddCallback_OnPlayerKilled( AddTeamScoreForPlayerKilled ) // dont have to track autotitan kills since you cant leave your titan in this mode - - // probably needs scoreevent earnmeter values -} - -void function TTDMIntroSetup() -{ - // this should show intermission cam for 15 sec in prematch, before spawning players as titans - AddCallback_GameStateEnter( eGameState.Prematch, TTDMIntroStart ) - AddCallback_OnClientConnected( TTDMIntroShowIntermissionCam ) -} - -void function TTDMIntroStart() -{ - thread TTDMIntroStartThreaded() -} - -void function TTDMIntroStartThreaded() -{ - ClassicMP_OnIntroStarted() - - foreach ( entity player in GetPlayerArray() ) - TTDMIntroShowIntermissionCam( player ) - - wait TTDMIntroLength - - ClassicMP_OnIntroFinished() -} - -void function TTDMIntroShowIntermissionCam( entity player ) -{ - if ( GetGameState() != eGameState.Prematch ) - return - - thread PlayerWatchesTTDMIntroIntermissionCam( player ) -} - -void function PlayerWatchesTTDMIntroIntermissionCam( entity player ) -{ - ScreenFadeFromBlack( player ) - - entity intermissionCam = GetEntArrayByClass_Expensive( "info_intermission" )[ 0 ] - - // the angle set here seems sorta inconsistent as to whether it actually works or just stays at 0 for some reason - player.SetObserverModeStaticPosition( intermissionCam.GetOrigin() ) - player.SetObserverModeStaticAngles( intermissionCam.GetAngles() ) - player.StartObserverMode( OBS_MODE_STATIC_LOCKED ) - - wait TTDMIntroLength - - RespawnAsTitan( player, false ) - TryGameModeAnnouncement( player ) -} - -void function AddTeamScoreForPlayerKilled( entity victim, entity attacker, var damageInfo ) -{ - if ( victim == attacker || !victim.IsPlayer() || !attacker.IsPlayer() ) - return - - AddTeamScore( GetOtherTeam( victim.GetTeam() ), 1 ) +global function GamemodeTTDM_Init
+
+const float TTDMIntroLength = 15.0
+
+void function GamemodeTTDM_Init()
+{
+ Riff_ForceSetSpawnAsTitan( eSpawnAsTitan.Always )
+ Riff_ForceTitanExitEnabled( eTitanExitEnabled.Never )
+ TrackTitanDamageInPlayerGameStat( PGS_ASSAULT_SCORE )
+ ScoreEvent_SetupEarnMeterValuesForMixedModes()
+ SetLoadoutGracePeriodEnabled( false )
+
+ ClassicMP_SetCustomIntro( TTDMIntroSetup, TTDMIntroLength )
+ ClassicMP_ForceDisableEpilogue( true )
+ SetTimeoutWinnerDecisionFunc( CheckScoreForDraw )
+
+ AddCallback_OnPlayerKilled( AddTeamScoreForPlayerKilled ) // dont have to track autotitan kills since you cant leave your titan in this mode
+
+ // probably needs scoreevent earnmeter values
+}
+
+void function TTDMIntroSetup()
+{
+ // this should show intermission cam for 15 sec in prematch, before spawning players as titans
+ AddCallback_GameStateEnter( eGameState.Prematch, TTDMIntroStart )
+ AddCallback_OnClientConnected( TTDMIntroShowIntermissionCam )
+}
+
+void function TTDMIntroStart()
+{
+ thread TTDMIntroStartThreaded()
+}
+
+void function TTDMIntroStartThreaded()
+{
+ ClassicMP_OnIntroStarted()
+
+ foreach ( entity player in GetPlayerArray() )
+ TTDMIntroShowIntermissionCam( player )
+
+ wait TTDMIntroLength
+
+ ClassicMP_OnIntroFinished()
+}
+
+void function TTDMIntroShowIntermissionCam( entity player )
+{
+ if ( GetGameState() != eGameState.Prematch )
+ return
+
+ thread PlayerWatchesTTDMIntroIntermissionCam( player )
+}
+
+void function PlayerWatchesTTDMIntroIntermissionCam( entity player )
+{
+ ScreenFadeFromBlack( player )
+
+ entity intermissionCam = GetEntArrayByClass_Expensive( "info_intermission" )[ 0 ]
+
+ // the angle set here seems sorta inconsistent as to whether it actually works or just stays at 0 for some reason
+ player.SetObserverModeStaticPosition( intermissionCam.GetOrigin() )
+ player.SetObserverModeStaticAngles( intermissionCam.GetAngles() )
+ player.StartObserverMode( OBS_MODE_STATIC_LOCKED )
+
+ wait TTDMIntroLength
+
+ RespawnAsTitan( player, false )
+ TryGameModeAnnouncement( player )
+}
+
+void function AddTeamScoreForPlayerKilled( entity victim, entity attacker, var damageInfo )
+{
+ if ( victim == attacker || !victim.IsPlayer() || !attacker.IsPlayer() || GetGameState() != eGameState.Playing )
+ return
+
+ AddTeamScore( GetOtherTeam( victim.GetTeam() ), 1 )
+}
+
+int function CheckScoreForDraw()
+{
+ if (GameRules_GetTeamScore(TEAM_IMC) > GameRules_GetTeamScore(TEAM_MILITIA))
+ return TEAM_IMC
+ else if (GameRules_GetTeamScore(TEAM_MILITIA) > GameRules_GetTeamScore(TEAM_IMC))
+ return TEAM_MILITIA
+
+ return TEAM_UNASSIGNED
}
\ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 78dec3d1..8e624c14 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -125,6 +125,8 @@ void function EndIntroWhenFinished() void function SpawnPlayerIntoDropship( entity player ) { + player.EndSignal( "OnDestroy" ) + if ( IsAlive( player ) ) player.Die() // kill them so we don't have any issues respawning them later @@ -148,7 +150,6 @@ void function SpawnPlayerIntoDropship( entity player ) WaitFrame() player.EndSignal( "OnDeath" ) - player.EndSignal( "OnDestroy" ) // find the player's dropship and seat array<IntroDropship> teamDropships @@ -179,6 +180,7 @@ void function SpawnPlayerIntoDropship( entity player ) // respawn player and holster their weapons so they aren't out player.RespawnPlayer( null ) + HolsterAndDisableWeapons(player) player.DisableWeaponViewModel() // hide hud and fade screen out from black @@ -186,7 +188,7 @@ void function SpawnPlayerIntoDropship( entity player ) ScreenFadeFromBlack( player, 0.5, 0.5 ) // faction leaders are done clientside, spawn them here Remote_CallFunction_NonReplay( player, "ServerCallback_SpawnFactionCommanderInDropship", playerDropship.dropship.GetEncodedEHandle(), file.introStartTime ) - + // do firstperson sequence FirstPersonSequenceStruct idleSequence idleSequence.firstPersonAnim = DROPSHIP_IDLE_ANIMS_POV[ playerDropshipIndex ] @@ -228,6 +230,7 @@ void function PlayerJumpsFromDropship( entity player ) // show weapon viewmodel and hud and let them move again player.MovementEnable() player.EnableWeaponViewModel() + DeployAndEnableWeapons(player) RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) } }) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_titan_transfer.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_titan_transfer.nut index 7b126cd0..c84e6aba 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_titan_transfer.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_titan_transfer.nut @@ -178,7 +178,12 @@ void function GiveWeaponsFromStoredArray( entity player, array<StoredWeapon> sto UpdateProScreen( player, weapon ) } - string weaponCategory = GetWeaponInfoFileKeyField_GlobalString( weapon.GetWeaponClassName(), "menu_category" ) + string weaponCategory = "" + if ( IsWeaponKeyFieldDefined(weapon.GetWeaponClassName(), "menu_category") ) + { + weaponCategory = GetWeaponInfoFileKeyField_GlobalString( weapon.GetWeaponClassName(), "menu_category" ) + } + if ( weaponCategory == "at" || weaponCategory == "special" ) // refill AT/grenadier ammo stockpile { int defaultTotal = weapon.GetWeaponSettingInt( eWeaponVar.ammo_default_total ) |