diff options
author | RoyalBlue1 <realEmail@veryRealURL.com> | 2023-01-15 15:59:08 +0100 |
---|---|---|
committer | RoyalBlue1 <realEmail@veryRealURL.com> | 2023-01-15 15:59:08 +0100 |
commit | bb8671eefc562fa76e13559915ae1ad493d06802 (patch) | |
tree | 40ac781a3422083ef2358ddf38da43e64462bbd0 /Northstar.CustomServers/mod/scripts/vscripts | |
parent | cad416bc967bc4b902ff5808c0ae3281402d4895 (diff) | |
parent | 9bbe6832460aaabd96fef18d6e4ebb05779bb71d (diff) | |
download | NorthstarMods-bb8671eefc562fa76e13559915ae1ad493d06802.tar.gz NorthstarMods-bb8671eefc562fa76e13559915ae1ad493d06802.zip |
Merge remote-tracking branch 'upsteam/main' into gamemode_fd
Diffstat (limited to 'Northstar.CustomServers/mod/scripts/vscripts')
24 files changed, 1204 insertions, 63 deletions
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_chat.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_chat.gnut index 97ed959c..44836bc9 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_chat.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_chat.gnut @@ -25,26 +25,26 @@ void function Chat_PrivateMessage(entity fromPlayer, entity toPlayer, string tex } // Broadcasts a message from the server to all players. -void function Chat_ServerBroadcast(string text) +void function Chat_ServerBroadcast(string text, bool withServerTag = true) { NSBroadcastMessage( -1, -1, text, - false, + !withServerTag, false, eChatMessageType.CHAT ) } // Sends a message from the server to one player. Will be shown as a whisper if whisper is set. -void function Chat_ServerPrivateMessage(entity toPlayer, string text, bool whisper) +void function Chat_ServerPrivateMessage(entity toPlayer, string text, bool whisper, bool withServerTag = true) { NSBroadcastMessage( -1, toPlayer.GetPlayerIndex(), text, - false, + !withServerTag, false, whisper ? eChatMessageType.WHISPER : eChatMessageType.CHAT ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_custom_codecallbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_custom_codecallbacks.gnut index 4a7f8189..ee21116d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_custom_codecallbacks.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_custom_codecallbacks.gnut @@ -1,7 +1,10 @@ untyped global function AddCallback_OnReceivedSayTextMessage -global function NSSetupChathooksServer + +// this is global due to squirrel bridge v3 making native not be able to find non-global funcs properly +// temp fix (surely it will get replaced), do not use this function please +global function CServerGameDLL_ProcessMessageStartThread global struct ClServer_MessageStruct { string message @@ -53,7 +56,3 @@ void function AddCallback_OnReceivedSayTextMessage( ClServer_MessageStruct funct { NsCustomCallbacks.OnReceivedSayTextMessageCallbacks.append(callbackFunc) } - -void function NSSetupChathooksServer() { - getroottable().rawset("CServerGameDLL_ProcessMessageStartThread", CServerGameDLL_ProcessMessageStartThread) -} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut index 3161237c..24dbb62d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut @@ -187,6 +187,8 @@ bool function ClientCommandCallback_SetPersistentLoadoutValue( entity player, ar if ( args[0] == "pilot" ) SetPlayerLoadoutDirty( player ) + UnlockAchievement( player, achievements.CUSTOMIZE_LOADOUT ) + return true } @@ -230,7 +232,6 @@ bool function ClientCommandCallback_SetBurnCardPersistenceSlot( entity player, a print( player + " SetBurnCardPersistenceSlot " + args[0] ) - // insecure, could be used to set invalid burnmeterslot potentially if ( IsRefValidAndOfType( args[0], eItemTypes.BURN_METER_REWARD ) ) player.SetPersistentVar( "burnmeterSlot", BurnReward_GetByRef( args[0] ).id ) else diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut index c0e69ba5..3546e3b7 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut @@ -2127,8 +2127,13 @@ void function EntityDemigod_TryAdjustDamageInfo( entity ent, var damageInfo ) return int bottomLimit = 5 + // Set it up so that you at least take 1 damage, for hit indicators etc to trigger if ( ent.GetHealth() <= bottomLimit ) - ent.SetHealth( bottomLimit + 1 ) //Set it up so that you at least take 1 damage, for hit indicators etc to trigger + { + // Prevent going over max health to avoid a server crash. + int newHealth = bottomLimit + 1 + ent.SetHealth( ent.GetMaxHealth() < newHealth ? ent.GetMaxHealth() : newHealth ) + } int health = ent.GetHealth() diff --git a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut index a8def7b2..f193643c 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut @@ -265,7 +265,7 @@ void function UseBurnCardWeapon( entity weapon, entity player ) if ( PlayerEarnMeter_IsRewardAvailable( player ) )
PlayerEarnMeter_SetRewardUsed( player )
- PlayerInventory_PopInventoryItem( player )
+ thread PlayerInventory_PopInventoryItem( player )
}
void function UseBurnCardWeaponInCriticalSection( entity weapon, entity ownerPlayer )
@@ -295,10 +295,14 @@ void function InitBurnMeterPersistentData( entity player ) void function PlayerUsesAmpedWeaponsBurncard( entity player )
{
thread PlayerUsesAmpedWeaponsBurncardThreaded( player )
+
}
void function PlayerUsesAmpedWeaponsBurncardThreaded( entity player )
{
+ player.Signal( "StopAmpedWeapons" )
+ player.EndSignal("StopAmpedWeapons")
+
array<entity> weapons = player.GetMainWeapons()
//weapons.extend( player.GetOffhandWeapons() ) // idk? unsure of vanilla behaviour here
foreach ( entity weapon in weapons )
@@ -615,4 +619,4 @@ void function PlayerUsesReaperfallBurncard( entity player ) DispatchSpawn( reaper )
thread SuperSpectre_WarpFall( reaper )
-}
\ No newline at end of file +}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/class/cplayer.nut b/Northstar.CustomServers/mod/scripts/vscripts/class/cplayer.nut index b9f8f7eb..19c6b6df 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/class/cplayer.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/class/cplayer.nut @@ -328,6 +328,26 @@ function CodeCallback_RegisterClass_CPlayer() } } } + + function CPlayer::GetUserInfoString( key, defaultValue = "" ) + { + return GetUserInfoKVString_Internal( this, key, defaultValue ) + } + + function CPlayer::GetUserInfoInt( key, defaultValue = 0 ) + { + return GetUserInfoKVInt_Internal( this, key, defaultValue ) + } + + function CPlayer::GetUserInfoFloat( key, defaultValue = 0 ) + { + return GetUserInfoKVFloat_Internal( this, key, defaultValue ) + } + + function CPlayer::GetUserInfoBool( key, defaultValue = false ) + { + return GetUserInfoKVBool_Internal( this, key, defaultValue ) + } } void function PlayerDropsScriptedItems( entity player ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter.gnut index dda84976..b4e77375 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter.gnut @@ -315,12 +315,12 @@ void function PlayerEarnMeter_Empty( entity player ) PlayerEarnMeter_SetRewardFrac( player, 0.0 ) } - void function EarnMeterDecayThink( entity player ) { player.EndSignal( "OnDeath" ) player.Signal( "EarnMeterDecayThink" ) player.EndSignal( "EarnMeterDecayThink" ) + thread OverDriveClearOnDeath( player ) if ( EarnMeter_DecayHold() < 0 ) return @@ -348,6 +348,12 @@ void function EarnMeterDecayThink( entity player ) } } +void function OverDriveClearOnDeath( entity player ) +{ + player.EndSignal( "OnDestroy" ) + player.WaitSignal( "OnDeath" ) + PlayerEarnMeter_SetEarnedFrac( player, PlayerEarnMeter_GetOwnedFrac( player ) ) +} bool function PlayerEarnMeter_TryMakeGoalAvailable( entity player ) { diff --git a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut index b1d8f6bd..f23c841d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut @@ -69,11 +69,21 @@ struct { entity evacIcon } file +struct EvacShipSetting +{ + asset shipModel + string flyinSound + string hoverSound + string flyoutSound +} + void function Evac_Init() { EvacShared_Init() RegisterSignal( "EvacShipLeaves" ) RegisterSignal( "EvacOver" ) + + PrecacheParticleSystem( FX_EVAC_MARKER ) } void function AddEvacNode( entity evacNode ) @@ -100,7 +110,7 @@ void function EvacEpilogueSetup() void function EvacEpilogue() { - int winner = GetWinningTeam() + int winner = GetWinningTeam() // make sure we don't run evac if it won't be supported for current map/gamestate bool canRunEvac = GetCurrentPlaylistVarInt( "max_teams", 2 ) == 2 && @@ -110,6 +120,10 @@ void function EvacEpilogue() if ( canRunEvac ) { thread SetRespawnAndWait( false ) + + // no players can evac? end match + thread CheckIfAnyPlayerLeft( GetOtherTeam( winner ) ) + thread Evac( GetOtherTeam( winner ), EVAC_INITIAL_WAIT, EVAC_ARRIVAL_TIME, EVAC_WAIT_TIME, EvacEpiloguePlayerCanBoard, EvacEpilogueShouldLeaveEarly, EvacEpilogueCompleted ) } else @@ -139,6 +153,10 @@ void function SetRespawnAndWait( bool mode ) { wait GAME_EPILOGUE_PLAYER_RESPAWN_LEEWAY SetRespawnsEnabled( mode ) + + // clear any respawn availablity, or players are able to save there respawn for whenever they want + foreach( entity player in GetPlayerArray() ) + ClearRespawnAvailable( player ) } bool function EvacEpiloguePlayerCanBoard( entity dropship, entity player ) @@ -174,12 +192,16 @@ void function EvacEpilogueCompleted( entity dropship ) ScreenFadeToBlackForever( player, 2.0 ) wait 2.0 - SetGameState( eGameState.Postmatch ) + if( GetGameState() != eGameState.Postmatch ) + SetGameState( eGameState.Postmatch ) } // global evac func, anything can call this, it's not necessarily an epilogue thing void function Evac( int evacTeam, float initialWait, float arrivalTime, float waitTime, bool functionref( entity, entity ) canBoardCallback, bool functionref( entity ) shouldLeaveEarlyCallback, void functionref( entity ) completionCallback, entity customEvacNode = null ) { + // get evac ship sound and model for specific team + EvacShipSetting evacShip = GetEvacShipSettingByTeam( evacTeam ) + wait initialWait // setup evac nodes if not manually registered @@ -212,6 +234,13 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa DispatchSpawn( file.evacIcon ) file.evacIcon.DisableHibernation() + // start evac beam + int index = GetParticleSystemIndex( FX_EVAC_MARKER ) + + entity effectFriendly = StartParticleEffectInWorld_ReturnEntity( index, evacNode.GetOrigin(), < 0,0,0 > ) + SetTeam( effectFriendly, evacTeam ) + effectFriendly.kv.VisibilityFlags = ENTITY_VISIBLE_TO_FRIENDLY + wait 0.5 // need to wait here, or the target won't appear on clients for some reason // eta until arrive SetTeamActiveObjective( evacTeam, "EG_DropshipExtract", Time() + arrivalTime, file.evacIcon ) @@ -221,14 +250,20 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa wait arrivalTime - 4.33333 entity dropship = CreateDropship( evacTeam, evacNode.GetOrigin(), evacNode.GetAngles() ) - dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) - dropship.SetValueForModelKey( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) + + thread DropShipTempHide( dropship ) // prevent showing model and health bar on spawn + dropship.SetModel( evacShip.shipModel ) + dropship.SetValueForModelKey( evacShip.shipModel ) + dropship.SetMaxHealth( EVAC_SHIP_HEALTH ) dropship.SetHealth( EVAC_SHIP_HEALTH ) dropship.SetShieldHealth( EVAC_SHIP_SHIELDS ) SetTargetName( dropship, "#NPC_EVAC_DROPSHIP" ) DispatchSpawn( dropship ) - dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) + + // reduce nuclear core's damage + AddEntityCallback_OnDamaged( dropship, EvacDropshipDamaged ) + AddEntityCallback_OnKilled( dropship, EvacDropshipKilled ) dropship.s.evacSlots <- [ null, null, null, null, null, null, null, null ] @@ -241,9 +276,12 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa dropship.s.evacTrigger.Destroy() // this should be for both teams - SetTeamActiveObjective( evacTeam, "EG_DropshipExtractDropshipDestroyed" ) - SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_DropshipExtractDropshipDestroyed" ) - + if( !IsValid( dropship ) ) + { + SetTeamActiveObjective( evacTeam, "EG_DropshipExtractDropshipDestroyed" ) + SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_DropshipExtractDropshipDestroyed" ) + } + foreach ( entity player in dropship.s.evacSlots ) { if ( !IsValid( player ) ) @@ -255,10 +293,14 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa // this is called whether dropship is destroyed or evac finishes, callback can handle this itself thread completionCallback( dropship ) }) - + // flyin Spectator_SetCustomSpectatorFunc( EvacSpectatorFunc ) thread PlayAnim( dropship, "cd_dropship_rescue_side_start", evacNode ) + + // fly in sound and effect + EmitSoundOnEntity( dropship, evacShip.flyinSound ) + thread WarpInEffectEvacShip( dropship ) // calculate time until idle start float sequenceDuration = dropship.GetSequenceDuration( "cd_dropship_rescue_side_start" ) @@ -266,11 +308,22 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa wait sequenceDuration * cycleFrac thread PlayAnim( dropship, "cd_dropship_rescue_side_idle", evacNode ) + + // hover sound + EmitSoundOnEntity( dropship, evacShip.hoverSound ) // eta until leave SetTeamActiveObjective( evacTeam, "EG_DropshipExtract2", Time() + waitTime, file.evacIcon ) SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtract2", Time() + waitTime, file.evacIcon ) + // dialogue + PlayFactionDialogueToTeam( "mp_evacGo", evacTeam ) + PlayFactionDialogueToTeam( "mp_evacStop", GetOtherTeam( evacTeam ) ) + + // stop evac beam + if( IsValid( effectFriendly ) ) + EffectStop( effectFriendly ) + // setup evac trigger entity trigger = CreateEntity( "trigger_cylinder" ) trigger.SetRadius( 150 ) @@ -298,6 +351,10 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa WaitFrame() } + + // fly out sound + StopSoundOnEntity( dropship, evacShip.hoverSound ) + EmitSoundOnEntity( dropship, evacShip.flyoutSound ) // holster all weapons foreach ( entity player in dropship.s.evacSlots ) @@ -320,6 +377,12 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa Remote_CallFunction_NonReplay( player, "ServerCallback_PlayScreenFXWarpJump" ) wait WARPINFXTIME + + dropship.kv.VisibilityFlags = 0 // prevent jetpack trails being like "dive" into ground + WaitFrame() // better wait because we are server + if( !IsValid( dropship ) ) + return + thread __WarpOutEffectShared( dropship ) // go to space @@ -345,6 +408,9 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa } SetPlayerActiveObjective( player, "EG_DropshipExtractSuccessfulEscape" ) + + // let evacing team able to see the ship again + dropship.kv.VisibilityFlags = ENTITY_VISIBLE_TO_FRIENDLY // skybox player.SetSkyCamera( GetEnt( SKYBOXSPACE ) ) @@ -428,3 +494,88 @@ void function EvacDropshipKilled( entity dropship, var damageInfo ) } } } + +// if there's no player left in evacing team, we end this match +void function CheckIfAnyPlayerLeft( int evacTeam ) +{ + wait GAME_EPILOGUE_PLAYER_RESPAWN_LEEWAY + float startTime = Time() + + OnThreadEnd( + function() : ( evacTeam ) + { + SetTeamActiveObjective( evacTeam, "EG_DropshipExtractEvacPlayersKilled" ) + SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtractEvacPlayersKilled" ) + thread EvacEpilogueCompleted( null ) + } + ) + while( true ) + { + if( GetPlayerArrayOfTeam_Alive( evacTeam ).len() == 0 ) + break + if( GetGameState() == eGameState.Postmatch ) + return + WaitFrame() + } +} + +void function DropShipTempHide( entity dropship ) +{ + dropship.kv.VisibilityFlags = 0 // or it will still shows the jetpack fxs + HideName( dropship ) + wait 0.46 + if( IsValid( dropship ) ) + { + dropship.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE + ShowName( dropship ) + } +} + +EvacShipSetting function GetEvacShipSettingByTeam( int team ) +{ + EvacShipSetting tempSetting + tempSetting.shipModel = $"models/vehicle/goblin_dropship/goblin_dropship_hero.mdl" + tempSetting.flyinSound = "Goblin_IMC_Evac_Flyin" + tempSetting.hoverSound = "Goblin_IMC_Evac_Hover" + tempSetting.flyoutSound = "Goblin_IMC_Evac_FlyOut" + + if( team == TEAM_MILITIA ) + { + tempSetting.shipModel = $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" + tempSetting.flyinSound = "Crow_MCOR_Evac_Flyin" + tempSetting.hoverSound = "Crow_MCOR_Evac_Hover" + tempSetting.flyoutSound = "Crow_MCOR_Evac_Flyout" + } + return tempSetting +} + +void function EvacDropshipDamaged( entity evacShip, var damageInfo ) +{ + int damageSourceID = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + if( damageSourceID == damagedef_nuclear_core ) + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) * EVAC_SHIP_DAMAGE_MULTIPLIER_AGAINST_NUCLEAR_CORE ) +} + +void function WarpInEffectEvacShip( entity dropship ) +{ + dropship.EndSignal( "OnDestroy" ) + float sfxWait = 0.1 + float totalTime = WARPINFXTIME + float preWaitTime = 0.16 // give it some time so it's actually playing anim, and we can get it's "origin" attatch for playing warp in effect + string sfx = "dropship_warpin" + + wait preWaitTime + + int attach = dropship.LookupAttachment( "origin" ) + vector origin = dropship.GetAttachmentOrigin( attach ) + vector angles = dropship.GetAttachmentAngles( attach ) + + entity fx = PlayFX( FX_GUNSHIP_CRASH_EXPLOSION_ENTRANCE, origin, angles ) + fx.FXEnableRenderAlways() + fx.DisableHibernation() + + wait sfxWait + EmitSoundAtPosition( TEAM_UNASSIGNED, origin, sfx ) + + wait totalTime - sfxWait +}
\ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 99f34164..9b05c3d4 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -26,6 +26,8 @@ void function CaptureTheFlag_Init() { PrecacheModel( CTF_FLAG_MODEL ) PrecacheModel( CTF_FLAG_BASE_MODEL ) + PrecacheParticleSystem( FLAG_FX_FRIENDLY ) + PrecacheParticleSystem( FLAG_FX_ENEMY ) CaptureTheFlagShared_Init() SetSwitchSidesBased( true ) @@ -164,6 +166,9 @@ void function CreateFlags() flag.SetValueForModelKey( CTF_FLAG_MODEL ) SetTeam( flag, flagTeam ) flag.MarkAsNonMovingAttachment() + flag.Minimap_AlwaysShow( TEAM_IMC, null ) // show flag icon on minimap + flag.Minimap_AlwaysShow( TEAM_MILITIA, null ) + flag.Minimap_SetAlignUpright( true ) DispatchSpawn( flag ) flag.SetModel( CTF_FLAG_MODEL ) flag.SetOrigin( spawn.GetOrigin() + < 0, 0, base.GetBoundingMaxs().z * 2 > ) // ensure flag doesn't spawn clipped into geometry @@ -291,7 +296,7 @@ void function GiveFlag( entity player, entity flag ) PlayFactionDialogueToTeamExceptPlayer( "ctf_flagPickupFriendly", player.GetTeam(), player ) MessageToTeam( flag.GetTeam(), eEventNotifications.PlayerHasFriendlyFlag, player, player ) - EmitSoundOnEntityToTeam( flag, "UI_CTF_EnemyGrabFlag", flag.GetTeam() ) + EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_EnemyGrabFlag", flag.GetTeam() ) SetFlagStateForTeam( flag.GetTeam(), eFlagState.Away ) // used for held } @@ -339,14 +344,13 @@ void function DropFlag( entity player, bool realDrop = true ) file.imcCaptureAssistList.append( player ) else file.militiaCaptureAssistList.append( player ) - + // do notifications MessageToPlayer( player, eEventNotifications.YouDroppedTheEnemyFlag ) EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_FlagDrop" ) - + MessageToTeam( player.GetTeam(), eEventNotifications.PlayerDroppedEnemyFlag, player, player ) // todo need a sound here maybe - MessageToTeam( GetOtherTeam( player.GetTeam() ), eEventNotifications.PlayerDroppedFriendlyFlag, player, player ) // todo need a sound here maybe } @@ -421,7 +425,7 @@ void function CaptureFlag( entity player, entity flag ) AddPlayerScore( assistPlayer, "FlagCaptureAssist", player ) assistList.clear() - + // notifs MessageToPlayer( player, eEventNotifications.YouCapturedTheEnemyFlag ) EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_PlayerScore" ) @@ -430,7 +434,7 @@ void function CaptureFlag( entity player, entity flag ) EmitSoundOnEntityToTeamExceptPlayer( flag, "UI_CTF_3P_TeamScore", player.GetTeam(), player ) MessageToTeam( GetOtherTeam( team ), eEventNotifications.PlayerCapturedFriendlyFlag, player, player ) - EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_EnemyScore", flag.GetTeam() ) + EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_EnemyScores", flag.GetTeam() ) if ( GameRules_GetTeamScore( team ) == GameMode_GetRoundScoreLimit( GAMETYPE ) - 1 ) { @@ -446,6 +450,9 @@ void function OnPlayerEntersFlagReturnTrigger( entity trigger, entity player ) flag = file.imcFlag else flag = file.militiaFlag + + if( !IsValid( flag ) || !IsValid( player ) ) + return if ( !player.IsPlayer() || player.IsTitan() || player.GetTeam() != flag.GetTeam() || IsFlagHome( flag ) || flag.GetParent() != null ) return @@ -481,6 +488,7 @@ void function TryReturnFlag( entity player, entity flag ) }) player.EndSignal( "FlagReturnEnded" ) + flag.EndSignal( "FlagReturnEnded" ) // avoid multiple players to return one flag at once player.EndSignal( "OnDeath" ) wait CTF_GetFlagReturnTime() @@ -488,7 +496,8 @@ void function TryReturnFlag( entity player, entity flag ) // flag return succeeded // return flag ResetFlag( flag ) - + flag.Signal( "FlagReturnEnded" ) + // do notifications for return MessageToPlayer( player, eEventNotifications.YouReturnedFriendlyFlag ) AddPlayerScore( player, "FlagReturn", player ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut b/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut index 496ebf84..7c08c036 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut @@ -32,7 +32,7 @@ void function Sv_ItemInventory_OnPlayerGetsNewPilotLoadout( entity player, Pilot if (playerInventoryStack.len() > 0) { InventoryItem topInventoryItem = playerInventoryStack[playerInventoryStack.len() - 1] - PlayerInventory_GiveInventoryItem(player, topInventoryItem) + thread PlayerInventory_GiveInventoryItem(player, topInventoryItem) } return @@ -68,13 +68,25 @@ int function PlayerInventory_CountBurnRef( entity player, string burnRef ) void function PlayerInventory_TakeInventoryItem( entity player ) { + player.EndSignal( "OnDestroy" ) entity preexistingWeapon = player.GetOffhandWeapon( OFFHAND_INVENTORY ) - if ( IsValid( preexistingWeapon ) ) - player.TakeWeaponNow( preexistingWeapon.GetWeaponClassName() ) + + if( !IsValid( preexistingWeapon ) ) + return + preexistingWeapon.EndSignal( "OnDestroy" ) + if( preexistingWeapon.GetWeaponClassName() == "mp_ability_burncardweapon" ) + { + var fireTime = preexistingWeapon.GetWeaponInfoFileKeyField( "fire_anim_rate" ) + if( fireTime ) + wait fireTime + } + player.TakeWeaponNow( preexistingWeapon.GetWeaponClassName() ) } void function PlayerInventory_GiveInventoryItem( entity player, InventoryItem inventoryItem ) { + player.EndSignal( "OnDestroy" ) + array<string> mods = [] if ( inventoryItem.itemType == eInventoryItemType.burnmeter ) { @@ -84,7 +96,10 @@ void function PlayerInventory_GiveInventoryItem( entity player, InventoryItem in } // ensure inventory slot isn't full to avoid crash - PlayerInventory_TakeInventoryItem( player ) + waitthread PlayerInventory_TakeInventoryItem( player ) + entity preexistingWeapon = player.GetOffhandWeapon( OFFHAND_INVENTORY ) // defensive fix + if( IsValid( preexistingWeapon ) ) + player.TakeWeaponNow( preexistingWeapon.GetWeaponClassName() ) player.GiveOffhandWeapon( inventoryItem.weaponRef, OFFHAND_INVENTORY, mods ) if ( inventoryItem.itemType == eInventoryItemType.burnmeter ) { @@ -98,7 +113,7 @@ void function PlayerInventory_PushInventoryItem( entity player, InventoryItem in file.playerInventoryStacks[ player ].append(inventoryItem) player.SetPlayerNetInt( "itemInventoryCount", file.playerInventoryStacks[ player ].len() ) - PlayerInventory_GiveInventoryItem(player, inventoryItem) + thread PlayerInventory_GiveInventoryItem(player, inventoryItem) } void function PlayerInventory_PushInventoryItemByBurnRef( entity player, string burnRef ) @@ -121,9 +136,9 @@ void function PlayerInventory_PopInventoryItem( entity player ) if (playerInventoryStack.len() > 0) { InventoryItem nextInventoryItem = playerInventoryStack[playerInventoryStack.len() - 1] - PlayerInventory_GiveInventoryItem(player, nextInventoryItem) + thread PlayerInventory_GiveInventoryItem( player, nextInventoryItem ) } else { - PlayerInventory_TakeInventoryItem( player ) + waitthread PlayerInventory_TakeInventoryItem( player ) } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype.gnut index a4c6e187..362407b3 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype.gnut @@ -1412,15 +1412,28 @@ void function CodeCallback_WeaponFireInCloak( entity player ) //player.SetCloakFlicker( 1.0, 2.0 ) DisableCloak( player, 0.5 ) - entity weapon = player.GetOffhandWeapon( OFFHAND_LEFT ) - //printt( "weapon", weapon.GetWeaponClassName() ) - // JFS; need code feature to properly reset next attack time/cooldown stuff - if ( IsValid( weapon ) && weapon.GetWeaponClassName() == "mp_ability_cloak" ) + entity cloakWeapon + int offhandSlot + for ( int i = 0; i <= OFFHAND_MELEE; i++ ) // OFFHAND_MELEE is the largest { - player.TakeOffhandWeapon( OFFHAND_LEFT ) - player.GiveOffhandWeapon( "mp_ability_cloak", OFFHAND_LEFT ) - weapon = player.GetOffhandWeapon( OFFHAND_LEFT ) - weapon.SetWeaponPrimaryClipCountAbsolute( 0 ) + entity nowWeapon = player.GetOffhandWeapon( i ) + if( IsValid( nowWeapon )) + { + if( nowWeapon.GetWeaponClassName() == "mp_ability_cloak" ) + { + cloakWeapon = nowWeapon + offhandSlot = i + } + } + } + if( IsValid( cloakWeapon ) ) + { + array<string> mods = cloakWeapon.GetMods() + // can't reset cooldown properly in script, let's give player a empty one + player.TakeWeapon( "mp_ability_cloak" ) // not using TakeWeaponNow() to fit vanilla behavior + player.GiveOffhandWeapon( "mp_ability_cloak", offhandSlot, mods ) + cloakWeapon = player.GetOffhandWeapon( offhandSlot ) + cloakWeapon.SetWeaponPrimaryClipCountAbsolute( 0 ) } } else diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut index ca8dc5f1..ec426754 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -19,6 +19,8 @@ global function ShouldEntTakeDamage_SPMP global function GetTitanBuildTime global function TitanPlayerHotDropsIntoLevel +global function SetRecalculateRespawnAsTitanStartPointCallback + struct { bool killcamsEnabled = true bool playerDeathsHidden = false @@ -26,6 +28,8 @@ struct { entity intermissionCamera array<entity> specCams + + entity functionref( entity player, entity basePoint ) recalculateRespawnAsTitanStartPointCallback } file void function BaseGametype_Init_MPSP() @@ -443,6 +447,9 @@ void function RespawnAsTitan( entity player, bool manualPosition = false ) player.isSpawning = true entity spawnpoint = FindSpawnPoint( player, true, ( ShouldStartSpawn( player ) || Flag( "ForceStartSpawn" ) ) && !IsFFAGame() ) + if ( file.recalculateRespawnAsTitanStartPointCallback != null ) + spawnpoint = file.recalculateRespawnAsTitanStartPointCallback( player, spawnpoint ) + TitanLoadoutDef titanLoadout = GetTitanLoadoutForPlayer( player ) asset model = GetPlayerSettingsAssetForClassName( titanLoadout.setFile, "bodymodel" ) @@ -500,7 +507,7 @@ void function RespawnAsTitan( entity player, bool manualPosition = false ) titan.Destroy() // pilotbecomestitan leaves an npc titan that we need to delete else RespawnAsPilot( player ) // this is 100% an edgecase, just avoid softlocking if we ever hit it in playable gamestates - + camera.Fire( "Disable", "!activator", 0, player ) camera.Destroy() }) @@ -509,6 +516,7 @@ void function RespawnAsTitan( entity player, bool manualPosition = false ) player.RespawnPlayer( null ) // spawn player as pilot so they get their pilot loadout on embark player.SetOrigin( titan.GetOrigin() ) + ClearTitanAvailable( player ) // titanfall succeed, clear titan availability // don't make player titan when entity batteryContainer is not valid. // This will prevent a servercrash that sometimes occur when evac is disabled and somebody is calling a titan in the defeat screen. @@ -577,6 +585,11 @@ void function CheckForAutoTitanDeath( entity victim, entity attacker, var damage } } +void function SetRecalculateRespawnAsTitanStartPointCallback( entity functionref( entity player, entity basePoint ) callbackFunc ) +{ + file.recalculateRespawnAsTitanStartPointCallback = callbackFunc +} + // stuff to change later bool function ShouldEntTakeDamage_SPMP( entity ent, var damageInfo ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_battery_port.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_battery_port.gnut index 37b89169..ea88c1bc 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_battery_port.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_battery_port.gnut @@ -1 +1,219 @@ -//fuck
\ No newline at end of file +untyped +global function InitTurretBatteryPort // only for fw turrets! + +void function InitTurretBatteryPort( entity batteryPort ) +{ + + batteryPort.s.beingUsed <- false // bool + batteryPort.s.hackAvaliable <- true // bool, for controlling hacking avaliablity + + // SetUsableByGroup() updates is done in TurretStateWatcher() + batteryPort.SetUsableByGroup( "pilot" ) // show hind to any pilots + batteryPort.SetUsePrompts( "#RODEO_APPLY_BATTERY_HINT", "#RODEO_APPLY_BATTERY_HINT" ) // don't know what to use + AddCallback_OnUseEntity( batteryPort, OnUseTurretBatteryPort ) +} + +function OnUseTurretBatteryPort( entBeingUse, user ) +{ + expect entity( entBeingUse ) + expect entity( user ) + + //print( "try to use batteryPort" ) + thread TryUseTurretBatteryPort( user, entBeingUse ) +} + +void function TryUseTurretBatteryPort( entity player, entity batteryPort ) +{ + if( batteryPort.s.beingUsed ) // already being using + return + + player.EndSignal( "OnDeath" ) + player.EndSignal( "OnDestroy" ) + player.EndSignal( "ScriptAnimStop" ) // so you can jump off animation + AddButtonPressedPlayerInputCallback( player, IN_JUMP, ForceStopUseBatteryPort ) + + OnThreadEnd( + function():( player ) + { + RemoveButtonPressedPlayerInputCallback( player, IN_JUMP, ForceStopUseBatteryPort ) + } + ) + + + var BatteryPortUsable = batteryPort.s.isUsable + + if( expect bool( BatteryPortUsable( batteryPort, player ) ) ) + { + // friendly try to apply one, or enemy try to hack this turret + waitthread PlayerApplesBatteryPackToPort( player, batteryPort ) + } +} + +void function ForceStopUseBatteryPort( entity player ) +{ + player.Signal( "ScriptAnimStop" ) +} + +void function PlayerApplesBatteryPackToPort( entity player, entity batteryPort ) +{ + table result = {} + result.success <- false + batteryPort.s.beingUsed = true + + BatteryPortSequenceStruct dataStruct = DisableCloakBeforeBatteryPortSequence( player ) + + // these are from _rodeo_titan.gnut + entity battery = GetBatteryOnBack( player ) + battery.Hide() //Hide it because the animation has a battery model already + Battery_StopFX( battery ) + + entity tempBattery3p + tempBattery3p = CreatePropDynamic( RODEO_BATTERY_MODEL_FOR_RODEO_ANIMS ) + tempBattery3p.SetParent( player, "R_HAND", false, 0.0 ) + tempBattery3p.RemoveFromSpatialPartition() + + entity tempBattery1p + tempBattery1p = CreatePropDynamic( RODEO_BATTERY_MODEL_FOR_RODEO_ANIMS ) + tempBattery1p.SetParent( player.GetFirstPersonProxy(), "R_HAND", false, 0.0 ) + tempBattery1p.RemoveFromSpatialPartition() + + player.p.rodeoAnimTempProps.append( tempBattery3p ) + player.p.rodeoAnimTempProps.append( tempBattery1p ) + + OnThreadEnd( + function() : ( battery, batteryPort, player, result, dataStruct ) + { + if ( IsValid( battery ) ) // animation interrupted, otherwise the battery will be destroyed + { + battery.Show() + Battery_StartFX( battery ) + } + + if ( IsValid( batteryPort ) ) + { + batteryPort.s.beingUsed = false + batteryPort.Anim_Stop() + } + + if ( IsValid( player ) ) + { + // restore control + DeployAndEnableWeapons( player ) + //ViewConeFree( player ) // no need to lock viewcone + + // clean up + ClearBatteryAnimTempProps( player ) + PutEntityInSafeSpot( player, player, null, player.GetOrigin() + <0, 0, 32>, player.GetOrigin() ) + + CleanUpBatterySequenceForPlayer( player ) + RestoreCloakAfterBatteryPortSequence( player, dataStruct ) + } + } + ) + + FirstPersonSequenceStruct sequence + sequence.attachment = "REF" // only ref the batteryPort has + + sequence.thirdPersonAnim = "pt_mp_battery_port_insert" //"pt_rodeo_ride_r_return_battery" + sequence.firstPersonAnim = "ptpov_mp_battery_port_insert" //"ptpov_rodeo_ride_r_return_battery" + + // player stats + HolsterAndDisableWeapons( player ) + //ViewConeZero( player ) // no need to lock viewcone + + batteryPort.Anim_Play( "bp_mp_battery_port_insert" ) + + thread WaitForActivateBattery( player, battery, batteryPort ) + waitthread FirstPersonSequence( sequence, player, batteryPort ) +} + +void function WaitForActivateBattery( entity player, entity battery, entity batteryPort ) +{ + player.EndSignal( "OnDeath" ) + player.EndSignal( "OnDestroy" ) + player.EndSignal( "ScriptAnimStop" ) // so you can jump off animation + battery.EndSignal( "OnDestroy" ) + + player.WaitSignal( "BatteryActivate" ) // this is registered in _gamemode_fw.nut! + ApplyBatteryToBatteryPort( player, batteryPort ) +} + +void function ApplyBatteryToBatteryPort( entity player, entity batteryPort ) +{ + if ( player.GetPlayerNetInt( "batteryCount" ) <= 0 ) // player actually not carrying a battery + return + + entity battery = Rodeo_TakeBatteryAwayFromPilot( player ) + if ( !IsValid( battery ) ) + return + + // player can apply battery + + // disable hacking + batteryPort.s.hackAvaliable = false // can't be hacked again until completely killed + + + var useBatteryPort = batteryPort.s.useBattery + useBatteryPort( batteryPort, player ) + + // all things done, destroy this batt + battery.Destroy() +} + +// for disabling cloak +struct BatteryPortSequenceStruct +{ + bool wasCloaked = false + float cloakEndTime = 0.0 +} + +BatteryPortSequenceStruct function DisableCloakBeforeBatteryPortSequence( entity player ) +{ + BatteryPortSequenceStruct dataStruct + if ( !IsCloaked( player ) ) + return dataStruct // empty struct! + + dataStruct.wasCloaked = true + dataStruct.cloakEndTime = player.GetCloakEndTime() + DisableCloak( player, 0.0 ) + + return dataStruct +} + +bool function RestoreCloakAfterBatteryPortSequence( entity player, BatteryPortSequenceStruct dataStruct ) +{ + if ( !IsAlive( player ) ) + return false + + if ( !dataStruct.wasCloaked ) + return false + + if ( dataStruct.cloakEndTime <= 0.0 ) + return false + + float remainingCloakDuration = max( 0.0, dataStruct.cloakEndTime - Time() ) + if ( remainingCloakDuration <= CLOAK_FADE_IN ) //Has to be greater than 1.0 fade in duration, otherwise will cloak forever + return false + + EnableCloak( player, remainingCloakDuration, CLOAK_FADE_IN ) + return true +} + +void function CleanUpBatterySequenceForPlayer( entity player ) +{ + ClearPlayerAnimViewEntity( player ) + player.AnimViewEntity_SetLerpOutTime( 0.4 ) // blend out the clear anim view entity + player.ClearParent() + player.Anim_Stop() +} + +void function ClearBatteryAnimTempProps( entity player ) +{ + foreach( tempProp in player.p.rodeoAnimTempProps ) + { + if ( IsValid( tempProp ) ) + tempProp.Destroy() + } + + player.p.rodeoAnimTempProps.clear() +}
\ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index 6cde4655..46b39ebc 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -220,6 +220,8 @@ void function GameStateEnter_Playing_Threaded() { WaitFrame() // ensure timelimits are all properly set + thread DialoguePlayNormal() // runs dialogue play function + while ( GetGameState() == eGameState.Playing ) { // could cache these, but what if we update it midgame? @@ -268,6 +270,8 @@ void function GameStateEnter_WinnerDetermined_Threaded() // do win announcement int winningTeam = GetWinningTeamWithFFASupport() + DialoguePlayWinnerDetermined() // play a faction dialogue when winner is determined + foreach ( entity player in GetPlayerArray() ) { int announcementSubstr @@ -509,6 +513,20 @@ void function GameStateEnter_SuddenDeath() { // disable respawns, suddendeath calling is done on a kill callback SetRespawnsEnabled( false ) + + // defensive fixes, so game won't stuck in SuddenDeath forever + bool mltElimited = false + bool imcElimited = false + if( GetPlayerArrayOfTeam_Alive( TEAM_MILITIA ).len() < 1 ) + mltElimited = true + if( GetPlayerArrayOfTeam_Alive( TEAM_IMC ).len() < 1 ) + imcElimited = true + if( mltElimited && imcElimited ) + SetWinner( TEAM_UNASSIGNED ) + else if( mltElimited ) + SetWinner( TEAM_IMC ) + else if( imcElimited ) + SetWinner( TEAM_MILITIA ) } @@ -874,3 +892,90 @@ float function GetTimeLimit_ForGameMode() // default to 10 mins, because that seems reasonable return GetCurrentPlaylistVarFloat( playlistString, 10 ) } + +// faction dialogue + +void function DialoguePlayNormal() +{ + int totalScore = GameMode_GetScoreLimit( GameRules_GetGameMode() ) + int winningTeam + int losingTeam + float diagIntervel = 71 // play a faction dailogue every 70 + 1s to prevent play together with winner dialogue + + while( GetGameState() == eGameState.Playing ) + { + wait diagIntervel + if( GameRules_GetTeamScore( TEAM_MILITIA ) < GameRules_GetTeamScore( TEAM_IMC ) ) + { + winningTeam = TEAM_IMC + losingTeam = TEAM_MILITIA + } + if( GameRules_GetTeamScore( TEAM_MILITIA ) > GameRules_GetTeamScore( TEAM_IMC ) ) + { + winningTeam = TEAM_MILITIA + losingTeam = TEAM_IMC + } + if( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) >= totalScore * 0.4 ) + { + PlayFactionDialogueToTeam( "scoring_winningLarge", winningTeam ) + PlayFactionDialogueToTeam( "scoring_losingLarge", losingTeam ) + } + else if( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) <= totalScore * 0.2 ) + { + PlayFactionDialogueToTeam( "scoring_winningClose", winningTeam ) + PlayFactionDialogueToTeam( "scoring_losingClose", losingTeam ) + } + else if( GameRules_GetTeamScore( winningTeam ) == GameRules_GetTeamScore( losingTeam ) ) + { + continue + } + else + { + PlayFactionDialogueToTeam( "scoring_winning", winningTeam ) + PlayFactionDialogueToTeam( "scoring_losing", losingTeam ) + } + } +} + +void function DialoguePlayWinnerDetermined() +{ + int totalScore = GameMode_GetScoreLimit( GameRules_GetGameMode() ) + int winningTeam + int losingTeam + + if( GameRules_GetTeamScore( TEAM_MILITIA ) < GameRules_GetTeamScore( TEAM_IMC ) ) + { + winningTeam = TEAM_IMC + losingTeam = TEAM_MILITIA + } + if( GameRules_GetTeamScore( TEAM_MILITIA ) > GameRules_GetTeamScore( TEAM_IMC ) ) + { + winningTeam = TEAM_MILITIA + losingTeam = TEAM_IMC + } + if( IsRoundBased() ) // check for round based modes + { + if( GameRules_GetTeamScore( winningTeam ) != GameMode_GetRoundScoreLimit( GAMETYPE ) ) // no winner dialogue till game really ends + return + } + if( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) >= totalScore * 0.4 ) + { + PlayFactionDialogueToTeam( "scoring_wonMercy", winningTeam ) + PlayFactionDialogueToTeam( "scoring_lostMercy", losingTeam ) + } + else if( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) <= totalScore * 0.2 ) + { + PlayFactionDialogueToTeam( "scoring_wonClose", winningTeam ) + PlayFactionDialogueToTeam( "scoring_lostClose", losingTeam ) + } + else if( GameRules_GetTeamScore( winningTeam ) == GameRules_GetTeamScore( losingTeam ) ) + { + PlayFactionDialogueToTeam( "scoring_tied", winningTeam ) + PlayFactionDialogueToTeam( "scoring_tied", losingTeam ) + } + else + { + PlayFactionDialogueToTeam( "scoring_won", winningTeam ) + PlayFactionDialogueToTeam( "scoring_lost", losingTeam ) + } +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_model_viewer.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_model_viewer.nut new file mode 100644 index 00000000..c33f4ef0 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_model_viewer.nut @@ -0,0 +1,180 @@ +untyped
+
+
+global function ModelViewer_Init
+
+global function ToggleModelViewer
+
+global modelViewerModels = []
+
+#if DEV
+struct
+{
+ bool initialized
+ bool active
+ entity gameUIFreezeControls
+ array<string> playerWeapons
+ array<string> playerOffhands
+ bool dpadUpPressed = true
+ bool dpadDownPressed = true
+ var lastTitanAvailability
+} file
+#endif // DEV
+
+function ModelViewer_Init()
+{
+ #if DEV
+ if ( reloadingScripts )
+ return
+ AddClientCommandCallback( "ModelViewer", ClientCommand_ModelViewer )
+ #endif
+}
+
+function ToggleModelViewer()
+{
+ #if DEV
+ entity player = GetPlayerArray()[ 0 ]
+ if ( !file.active )
+ {
+ file.active = true
+
+ DisablePrecacheErrors()
+ wait 0.5
+
+ ModelViewerDisableConflicts()
+ Remote_CallFunction_NonReplay( player, "ServerCallback_ModelViewerDisableConflicts" )
+
+ ReloadShared()
+
+ if ( !file.initialized )
+ {
+ file.initialized = true
+ ControlsInit()
+ }
+
+ Remote_CallFunction_NonReplay( player, "ServerCallback_MVEnable" )
+
+ file.lastTitanAvailability = level.nv.titanAvailability
+ Riff_ForceTitanAvailability( eTitanAvailability.Never )
+
+ WeaponsRemove()
+ thread UpdateModelBounds()
+ }
+ else
+ {
+ file.active = false
+
+ Remote_CallFunction_NonReplay( player, "ServerCallback_MVDisable" )
+ RestorePrecacheErrors()
+
+ Riff_ForceTitanAvailability( file.lastTitanAvailability )
+
+ WeaponsRestore()
+ }
+ #endif
+}
+
+#if DEV
+function ModelViewerDisableConflicts()
+{
+ disable_npcs() //Just disable_npcs() for now, will probably add things later
+}
+
+function ReloadShared()
+{
+ modelViewerModels = GetModelViewerList()
+}
+
+function ControlsInit()
+{
+ file.gameUIFreezeControls = CreateEntity( "game_ui" )
+ file.gameUIFreezeControls.kv.spawnflags = 32
+ file.gameUIFreezeControls.kv.FieldOfView = -1.0
+
+ DispatchSpawn( file.gameUIFreezeControls )
+}
+
+bool function ClientCommand_ModelViewer( entity player, array<string> args )
+{
+ string command = args[ 0 ]
+ switch ( command )
+ {
+ case "freeze_player":
+ file.gameUIFreezeControls.Fire( "Activate", "!player", 0 )
+ break
+
+ case "unfreeze_player":
+ file.gameUIFreezeControls.Fire( "Deactivate", "!player", 0 )
+ break
+ }
+
+ return true
+}
+
+function UpdateModelBounds()
+{
+ wait( 0.3 )
+
+ foreach ( index, modelName in modelViewerModels )
+ {
+ entity model = CreatePropDynamic( expect asset( modelName ) )
+ local mins = model.GetBoundingMins()
+ local maxs = model.GetBoundingMaxs()
+
+ mins.x = min( -8.0, mins.x )
+ mins.y = min( -8.0, mins.y )
+ mins.z = min( -8.0, mins.z )
+
+ maxs.x = max( 8.0, maxs.x )
+ maxs.y = max( 8.0, maxs.y )
+ maxs.z = max( 8.0, maxs.z )
+
+ Remote_CallFunction_NonReplay( GetPlayerArray()[ 0 ], "ServerCallback_MVUpdateModelBounds", index, mins.x, mins.y, mins.z, maxs.x, maxs.y, maxs.z )
+ model.Destroy()
+ }
+}
+
+function WeaponsRemove()
+{
+ entity player = GetPlayerArray()[0]
+ if ( !IsValid( player ) )
+ return
+
+ file.playerWeapons.clear()
+ file.playerOffhands.clear()
+
+ array<entity> weapons = player.GetMainWeapons()
+ foreach ( weaponEnt in weapons )
+ {
+ string weapon = weaponEnt.GetWeaponClassName()
+ file.playerWeapons.append( weapon )
+ player.TakeWeapon( weapon )
+ }
+
+ array<entity> offhands = player.GetOffhandWeapons()
+ foreach ( index, offhandEnt in offhands )
+ {
+ string offhand = offhandEnt.GetWeaponClassName()
+ file.playerOffhands.append( offhand )
+ player.TakeOffhandWeapon( index )
+ }
+}
+
+function WeaponsRestore()
+{
+ entity player = GetPlayerArray()[0]
+ if ( !IsValid( player ) )
+ return
+
+ foreach ( weapon in file.playerWeapons )
+ {
+ player.GiveWeapon( weapon )
+ }
+
+ foreach ( index, offhand in file.playerOffhands )
+ {
+ player.GiveOffhandWeapon( offhand, index )
+ }
+}
+
+#endif // DEV
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index 2d1ff074..dacd43b0 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut @@ -187,9 +187,19 @@ void function ScoreEvent_TitanKilled( entity victim, entity attacker, var damage return if ( attacker.IsTitan() ) - AddPlayerScore( attacker, "TitanKillTitan", victim.GetTitanSoul().GetOwner() ) + { + if( victim.GetBossPlayer() || victim.IsPlayer() ) // to confirm this is a pet titan or player titan + AddPlayerScore( attacker, "TitanKillTitan", attacker ) // this will show the "Titan Kill" callsign event + else + AddPlayerScore( attacker, "TitanKillTitan" ) + } else - AddPlayerScore( attacker, "KillTitan", victim.GetTitanSoul().GetOwner() ) + { + if( victim.GetBossPlayer() || victim.IsPlayer() ) + AddPlayerScore( attacker, "KillTitan", attacker ) + else + AddPlayerScore( attacker, "KillTitan" ) + } table<int, bool> alreadyAssisted foreach( DamageHistoryStruct attackerInfo in victim.e.recentDamageHistory ) @@ -205,6 +215,9 @@ void function ScoreEvent_TitanKilled( entity victim, entity attacker, var damage Remote_CallFunction_NonReplay( attackerInfo.attacker, "ServerCallback_SetAssistInformation", attackerInfo.damageSourceId, attacker.GetEncodedEHandle(), victim.GetEncodedEHandle(), attackerInfo.time ) } } + + if( !victim.IsNPC() ) // don't let killing a npc titan plays dialogue + KilledPlayerTitanDialogue( attacker, victim ) } void function ScoreEvent_NPCKilled( entity victim, entity attacker, var damageInfo ) @@ -251,3 +264,42 @@ void function ScoreEvent_SetupEarnMeterValuesForTitanModes() { // relatively sure we don't have to do anything here but leaving this function for consistency } + +// faction dialogue +void function KilledPlayerTitanDialogue( entity attacker, entity victim ) +{ + if( !attacker.IsPlayer() ) + return + entity titan + if ( victim.IsTitan() ) + titan = victim + + if( !IsValid( titan ) ) + return + string titanCharacterName = GetTitanCharacterName( titan ) + + switch( titanCharacterName ) + { + case "ion": + PlayFactionDialogueToPlayer( "kc_pilotkillIon", attacker ) + return + case "tone": + PlayFactionDialogueToPlayer( "kc_pilotkillTone", attacker ) + return + case "legion": + PlayFactionDialogueToPlayer( "kc_pilotkillLegion", attacker ) + return + case "scorch": + PlayFactionDialogueToPlayer( "kc_pilotkillScorch", attacker ) + return + case "ronin": + PlayFactionDialogueToPlayer( "kc_pilotkillRonin", attacker ) + return + case "northstar": + PlayFactionDialogueToPlayer( "kc_pilotkillNorthstar", attacker ) + return + default: + PlayFactionDialogueToPlayer( "kc_pilotkilltitan", attacker ) + return + } +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut b/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut index 0984eaa8..153be7cd 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut @@ -42,6 +42,9 @@ global function Battery_StopFXAndHideIconForPlayer global function RemovePlayerAirControl //This function should really be in a server only SP & MP utility script file. No such file exists as of right now. global function RestorePlayerAirControl //This function should really be in a server only SP & MP utility script file. No such file exists as of right now. +// needs these +global function Rodeo_TakeBatteryAwayFromPilot + #if DEV global function SetDebugRodeoPrint global function GetDebugRodeoPrint @@ -338,7 +341,7 @@ void function RodeoBatteryRemoval( entity pilot ) if ( !playerHadBattery ) { - AddPlayerScore( pilot, "PilotBatteryStolen" ) + AddPlayerScore( pilot, "PilotBatteryStolen", pilot ) entity battery = Rodeo_CreateBatteryPack( titan ) Rodeo_PilotPicksUpBattery( pilot, battery ) thread BatteryThiefHighlight( pilot ) @@ -1868,7 +1871,7 @@ void function Rodeo_OnTouchBatteryPack_Internal( entity player, entity batteryPa Battery_StopFX( batteryPack ) //Will be turned on again when player loses cloak Rodeo_PilotPicksUpBattery( player, batteryPack ) - AddPlayerScore( player, "PilotBatteryPickup" ) + AddPlayerScore( player, "PilotBatteryPickup", player ) // MessageToPlayer( player, eEventNotifications.Rodeo_PilotPickedUpBattery ) return } @@ -1893,7 +1896,7 @@ void function Rodeo_PilotAddsBatteryToFriendlyTitan( entity rider, entity titan Rodeo_ApplyBatteryToTitan( battery, titan ) //This destroys the battery - AddPlayerScore( rider, "PilotBatteryApplied" ) + AddPlayerScore( rider, "PilotBatteryApplied", rider ) EmitSoundOnEntityOnlyToPlayer( rider, rider, PILOT_APPLIES_BATTERY_TO_TITAN_HEALTH_RESTORED_SOUND ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut index fbaf9e02..85f5aa05 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut @@ -3263,6 +3263,24 @@ string function Loadouts_GetSetFileForRequestedClass( entity player ) return loadout.race
}
+ #if DEV
+ // these are #if DEV'd until they work as their function names describe they should
+ // atm these only exist to allow the #if DEV'd calls to them for bot code in this file to compile on retail
+ // bots don't work in retail at all, so this doesn't matter for us really, but these should be unDEV'd and api'd properly once they are functional
+
+ PilotLoadoutDef function GetRandomPilotLoadout()
+ {
+ PilotLoadoutDef loadout
+ return loadout
+ }
+
+ TitanLoadoutDef function GetRandomTitanLoadout( string setFile )
+ {
+ TitanLoadoutDef loadout
+ return loadout
+ }
+ #endif
+
bool function Loadouts_TryGivePilotLoadout( entity player )
{
if ( !Loadouts_CanGivePilotLoadout( player ) )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_powerup.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_powerup.gnut new file mode 100644 index 00000000..c390b5f5 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_powerup.gnut @@ -0,0 +1,294 @@ +global function SH_PowerUp_Init +global function GetPowerUpFromIndex +global function GetPowerUpFromItemRef + +//Proto Use Functions +global function PowerUp_Func_GiveEPG +global function PowerUp_Func_GiveHELL +global function PowerUp_Func_GiveLSTAR +global function PowerUp_Func_GiveSHOTGUN +global function PowerUp_Func_GiveArmorSmall +global function PowerUp_Func_GiveArmorMedium +global function PowerUp_Func_GiveArmorLarge +global function PowerUp_Func_TitanBuildTime +global function PowerUp_Func_PilotUpgrade +global function PowerUp_Func_GiveTicks + +global struct PowerUp +{ + int index + string name + asset icon + asset model + asset baseModel + string itemRef + vector modelOffset + vector modelAngles + float respawnDelay + vector glowColor + bool titanPickup + int maxInWorld + void functionref( entity ) destroyFunc + bool functionref() spawnFunc +} + +const bool TITAN_PICKUP = true +const bool PILOT_PICKUP = false + +struct +{ + array<PowerUp> powerUps +}file + +const TEST_MODEL = $"models/communication/terminal_com_station.mdl" +const TEST_ICON = $"vgui/HUD/coop/minimap_coop_nuke_titan" + +void function SH_PowerUp_Init() +{ + #if SERVER || CLIENT + PrecacheWeapon( "mp_weapon_epg" ) + PrecacheWeapon( "mp_weapon_arena1" ) + PrecacheWeapon( "mp_weapon_arena2" ) + PrecacheWeapon( "mp_weapon_arena3" ) + PrecacheWeapon( "mp_weapon_lstar" ) + PrecacheWeapon( "mp_weapon_shotgun_doublebarrel" ) + PrecacheWeapon( "mp_weapon_frag_drone" ) + #endif + + file.powerUps.resize( ePowerUps.count ) + CreatePowerUp( ePowerUps.weaponEPG, "mp_weapon_epg", "EPG", 60.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveEPG, <255,0,0>, PILOT_PICKUP, $"vgui/HUD/op_ammo_mini", $"models/weapons/auto_rocket_launcher_ARL/w_ARL.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > ) + CreatePowerUp( ePowerUps.weaponHELL, "mp_weapon_arena3", "HELL", 90.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveHELL, <255,0,0>, PILOT_PICKUP, $"vgui/HUD/op_ammo_mini", $"models/weapons/defender/w_defender.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > ) + CreatePowerUp( ePowerUps.weaponLSTAR, "mp_weapon_lstar", "LSTAR", 45.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveLSTAR, <255,0,0>, PILOT_PICKUP, $"vgui/HUD/op_ammo_mini", $"models/weapons/lstar/w_lstar.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > ) + CreatePowerUp( ePowerUps.weaponSHOTGUN, "mp_weapon_shotgun_doublebarrel", "Shrapnel Shotgun", 30.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveSHOTGUN, <255,0,0>, PILOT_PICKUP, $"vgui/HUD/op_ammo_mini", $"models/weapons/mastiff_stgn/w_mastiff.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > ) + CreatePowerUp( ePowerUps.armorSmall, "mp_loot_armor_small", "Armor +5", 30.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveArmorSmall, <0,0,255>, PILOT_PICKUP, $"vgui/HUD/op_health_mini", $"models/gameplay/health_pickup_small.mdl", $"models/containers/plastic_pallet_01.mdl", < 0, 0, 32 >, < 0, 0, 0 > ) + CreatePowerUp( ePowerUps.armorMedium, "mp_loot_armor_medium", "Armor +25", 60.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveArmorMedium, <0,0,255>, PILOT_PICKUP, $"vgui/HUD/op_health_mini", $"models/gameplay/health_pickup_small.mdl", $"models/containers/plastic_pallet_01.mdl", < 0, 0, 32 >, < 0, 0, 0 > ) + CreatePowerUp( ePowerUps.armorLarge, "mp_loot_armor_large", "Armor +50", 120.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveArmorLarge, <0,0,255>, PILOT_PICKUP, $"vgui/HUD/op_health_mini", $"models/gameplay/health_pickup_large.mdl", $"models/containers/plastic_pallet_01.mdl", < 0, 0, 32 >, < 0, 0, 0 > ) + CreatePowerUp( ePowerUps.titanTimeReduction, "mp_loot_titan_build_credit", "Titan Build Time", 20.0, 2, FRAShouldSpawnPowerUp, PowerUp_Func_TitanBuildTime, <0,255,0>, PILOT_PICKUP, $"vgui/HUD/op_drone_mini", $"models/titans/medium/titan_medium_battery_static.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > ) + CreatePowerUp( ePowerUps.LTS_TitanTimeReduction, "mp_loot_titan_build_credit_lts", "Titan Build Time", 60.0, 0, LTSShouldSpawnPowerUp, PowerUp_Func_TitanBuildTime, <0,255,0>, PILOT_PICKUP, $"vgui/HUD/op_drone_mini", $"models/titans/medium/titan_medium_battery_static.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > ) + CreatePowerUp( ePowerUps.pilotUpgrade, "mp_loot_pilot_upgrade", "Can of Spinach", 120.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_PilotUpgrade, <0,255,0>, PILOT_PICKUP, $"vgui/HUD/op_drone_mini", $"models/humans/pilots/pilot_light_ged_m.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > ) + CreatePowerUp( ePowerUps.ticks, "mp_weapon_frag_drone", "Ticks", 60.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveTicks, <255,0,0>, PILOT_PICKUP, $"vgui/HUD/op_ammo_mini", $"models/robots/drone_frag/frag_drone_proj.mdl", $"models/robots/drone_frag/frag_drone_proj.mdl", < 0, 0, 32 >, < 0, 0, 0 > ) +} + +bool function FRAShouldSpawnPowerUp() +{ + return GAMETYPE == FREE_AGENCY +} + +bool function LTSShouldSpawnPowerUp() +{ + if ( HasIronRules() ) + return false + + // modified for fw + //return ( GAMETYPE == LAST_TITAN_STANDING || GAMETYPE == LTS_BOMB ) + return ( GAMETYPE == LAST_TITAN_STANDING || GAMETYPE == LTS_BOMB || GAMETYPE == FORT_WAR ) +} + +bool function DefaultShouldSpawnPowerUp() +{ + return GetCurrentPlaylistVarInt( "power_ups_enabled", 0 ) == 1 +} + +void function CreatePowerUp( int enumIndex, string item, string displayName, float respawnTime, int worldLimit, bool functionref() shouldSpawnFunction, void functionref( entity ) destroyFunction, vector color, bool canTitanPickup, asset worldIcon, asset worldModel, asset worldBase, vector worldModelOffset, vector worldModelAngle ) +{ + PowerUp power + power.index = enumIndex + power.name = displayName + power.icon = worldIcon + power.model = worldModel + power.baseModel = worldBase + power.itemRef = item + power.modelOffset = worldModelOffset + power.modelAngles = worldModelAngle + power.respawnDelay = respawnTime + power.destroyFunc = destroyFunction + power.spawnFunc = shouldSpawnFunction + power.glowColor = color + power.titanPickup = canTitanPickup + power.maxInWorld = worldLimit + file.powerUps[enumIndex] = power + + #if CLIENT + PrecacheHUDMaterial( worldIcon ) + #else + PrecacheModel( worldModel ) + PrecacheModel( worldBase ) + #if R1_VGUI_MINIMAP + Minimap_PrecacheMaterial( worldIcon ) + #endif + #endif +} + +PowerUp function GetPowerUpFromIndex( int index ) +{ + return file.powerUps[index] +} + +PowerUp function GetPowerUpFromItemRef( string ref ) +{ + foreach( power in file.powerUps ) + { + if ( power.itemRef == ref ) + return power + } + + Assert( false, "Power Up not found") + unreachable +} + +////////////////////////////////////////////// +// PROTO USE FUNCTIONS - Maybe should be a bunch of new item_ classes with their own healthkit callbacks? +////////////////////////////////////////////// +void function PowerUp_Func_GiveEPG( entity player ) +{ + #if SERVER + if ( player.IsTitan() ) + return + GiveWeaponPowerUp( player, "mp_weapon_arena2" ) + #endif +} + +void function PowerUp_Func_GiveHELL( entity player ) +{ + #if SERVER + if ( player.IsTitan() ) + return + GiveWeaponPowerUp( player, "mp_weapon_arena3" ) + #endif +} + +void function PowerUp_Func_GiveLSTAR( entity player ) +{ + #if SERVER + if ( player.IsTitan() ) + return + GiveWeaponPowerUp( player, "mp_weapon_arena1" ) + #endif +} + +void function PowerUp_Func_GiveSHOTGUN( entity player ) +{ + #if SERVER + if ( player.IsTitan() ) + return + GiveWeaponPowerUp( player, "mp_weapon_shotgun_doublebarrel" ) + #endif +} + +void function PowerUp_Func_GiveTicks( entity player ) +{ + #if SERVER + if ( player.IsTitan() ) + return + player.TakeOffhandWeapon( OFFHAND_ORDNANCE ) + player.GiveOffhandWeapon( "mp_weapon_frag_drone", OFFHAND_ORDNANCE ) + thread RestoreDefaultOffhandWeapon( player ) + #endif +} + +#if SERVER +void function RestoreDefaultOffhandWeapon( entity player ) +{ + player.EndSignal( "OnDeath" ) + player.EndSignal( "OnDestroy" ) + + while( true ) + { + player.WaitSignal( "ThrowGrenade" ) + + if ( player.IsTitan() ) + continue + + entity weapon = player.GetOffhandWeapon( OFFHAND_ORDNANCE ) + if ( weapon.GetWeaponPrimaryClipCount() == 0 ) + { + player.TakeOffhandWeapon( OFFHAND_ORDNANCE ) + int loadoutIndex = GetActivePilotLoadoutIndex( player ) + PilotLoadoutDef loadout = GetPilotLoadoutFromPersistentData( player, loadoutIndex ) + player.GiveOffhandWeapon( loadout.ordnance, OFFHAND_ORDNANCE ) + return + } + } +} + +void function GiveWeaponPowerUp( entity player, string newWeapon ) +{ + array<entity> weapons = player.GetMainWeapons() + string weaponToSwitch = player.GetLatestPrimaryWeapon().GetWeaponClassName() + + if ( player.GetActiveWeapon() != player.GetAntiTitanWeapon() ) + { + foreach ( weapon in weapons ) + { + string weaponClassName = weapon.GetWeaponClassName() + if ( weaponClassName == newWeapon ) + { + weaponToSwitch = weaponClassName + break + } + } + } + + player.TakeWeaponNow( weaponToSwitch ) + player.GiveWeapon( newWeapon ) + player.SetActiveWeaponByName( newWeapon ) +} +#endif + +void function PowerUp_Func_GiveArmorSmall( entity player ) +{ + GiveArmor( player, 5 ) +} + +void function PowerUp_Func_GiveArmorMedium( entity player ) +{ + GiveArmor( player, 25 ) +} + +void function PowerUp_Func_GiveArmorLarge( entity player ) +{ + GiveArmor( player, 50 ) +} + +void function GiveArmor( entity player, int amount ) +{ + #if SERVER + if ( player.IsTitan() ) + return + int currentShieldHealth = player.GetShieldHealth() + int currentMaxShieldHealth = player.GetShieldHealthMax() + player.SetShieldHealth( min( 200, amount + currentShieldHealth ) ) + player.SetShieldHealthMax( min( 200, amount + currentMaxShieldHealth ) ) + #endif +} + +void function PowerUp_Func_TitanBuildTime( entity player ) +{ + #if SERVER + entity battery = Rodeo_CreateBatteryPack() + battery.SetOrigin( player.GetOrigin() ) + #endif +} + + + +void function PowerUp_Func_PilotUpgrade( entity player ) +{ + #if SERVER + if ( player.IsTitan() ) + return + + int loadoutIndex = GetPersistentSpawnLoadoutIndex( player, "pilot" ) + + PilotLoadoutDef loadout = GetPilotLoadoutFromPersistentData( player, loadoutIndex ) + + loadout.primary = "mp_weapon_arena2" + loadout.secondary = "mp_weapon_mgl" + loadout.ordnance = "mp_weapon_grenade_emp" + + UpdateDerivedPilotLoadoutData( loadout ) + + GivePilotLoadout( player, loadout ) + SetActivePilotLoadoutIndex( player, loadoutIndex ) + #endif +}
\ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_server_to_client_stringcommands.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_server_to_client_stringcommands.gnut index a51e528f..18df6a6f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_server_to_client_stringcommands.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_server_to_client_stringcommands.gnut @@ -1,6 +1,4 @@ #if CLIENT -global function ServerToClientStringCommands_Init - global function AddServerToClientStringCommandCallback global function NSClientCodeCallback_RecievedServerToClientStringCommand #endif @@ -14,11 +12,6 @@ struct { table< string, array< void functionref( array<string> args ) > > callbacks } file -void function ServerToClientStringCommands_Init() -{ - getroottable().rawset( "NSClientCodeCallback_RecievedServerToClientStringCommand", NSClientCodeCallback_RecievedServerToClientStringCommand ) -} - void function AddServerToClientStringCommandCallback( string command, void functionref( array<string> args ) callback ) { if ( !( command in file.callbacks ) ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut index c9d986bc..57361362 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut @@ -21,7 +21,6 @@ global function ReplacementTitan global function TryAnnounceTitanfallWarningToEnemyTeam global function GetTitanForPlayer - global function ShouldSetTitanRespawnTimer global function PauseTitanTimers @@ -33,6 +32,7 @@ global function SetReplacementTitanGamemodeRules global function SetRequestTitanGamemodeRules global function CreateTitanForPlayerAndHotdrop +global function SetRequestTitanAllowedCallback struct { array<int> ETATimeThresholds = [ 120, 60, 30, 15 ] @@ -53,6 +53,8 @@ struct { bool functionref( entity ) ReplacementTitanGamemodeRules bool functionref( entity, vector ) RequestTitanGamemodeRules + bool functionref( entity player, array< string > args ) RequestTitanAllowedCallback + } file const nagInterval = 40 @@ -87,6 +89,10 @@ function ReplacementTitans_Init() FlagInit( "LevelHasRoof" ) } +void function SetRequestTitanAllowedCallback( bool functionref( entity player, array<string> args ) RequestTitanAllowedCallback ) +{ + file.RequestTitanAllowedCallback = RequestTitanAllowedCallback +} void function ReplacementTitan_InitPlayer( entity player ) { @@ -424,6 +430,7 @@ function TryETATitanReadyAnnouncement( entity player ) TryReplacementTitanReadyAnnouncement( player ) return } + //This entire loop is probably too complicated now for what it's doing. Simplify next game! //Loop might be pretty hard to read, a particular iteration of the loop is written in comments below @@ -524,6 +531,9 @@ function req() bool function ClientCommand_RequestTitan( entity player, array<string> args ) { + if( file.RequestTitanAllowedCallback != null && !file.RequestTitanAllowedCallback( player, args ) ) + return true + ReplacementTitan( player ) //Separate function because other functions will call ReplacementTitan return true } @@ -877,6 +887,20 @@ void function CreateTitanForPlayerAndHotdrop( entity player, Point spawnPoint, T player.Signal( "titan_impact" ) thread TitanNPC_WaitForBubbleShield_StartAutoTitanBehavior( titan ) + thread PlayerEarnMeter_ReplacementTitanThink( player, titan ) +} + +void function PlayerEarnMeter_ReplacementTitanThink( entity player, entity titan ) +{ + player.EndSignal( "OnDestroy" ) + OnThreadEnd( + function(): ( player ) + { + if( IsValid( player ) ) + PlayerEarnMeter_Reset( player ) + } + ) + titan.WaitSignal( "OnDestroy" ) } void function CleanupTitanFallDisablingEntity( entity titanFallDisablingEntity, entity titan ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans_drop.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans_drop.gnut index 933e9988..6972d5ff 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans_drop.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans_drop.gnut @@ -4,6 +4,7 @@ global function HullTraceDropPoint global function DebugTitanfall global function TitanFindDropNodes global function TitanHulldropSpawnpoint +global function SetRecalculateTitanReplacementPointCallback global const TITANDROP_LOS_DIST = 2000 // 2D distance at which we do the line of sight check to see where the player wants to call in the titan global const TITANDROP_MIN_FOV = 10 @@ -19,8 +20,15 @@ global const TITANDROP_FALLBACK_DIST = 150 // if the ground search hits, we go t struct { int replacementSpawnpointsID + Point functionref(Point originalPoint, entity player) recalculateTitanReplacementPointCallback } file + +void function SetRecalculateTitanReplacementPointCallback(Point functionref(Point originalPoint, entity player) recalculateTitanReplacementPointCallback) +{ + file.recalculateTitanReplacementPointCallback = recalculateTitanReplacementPointCallback +} + void function ReplacementTitansDrop_Init() { AddSpawnCallback( "info_spawnpoint_titan", AddDroppoint ) @@ -117,7 +125,10 @@ Point function GetTitanReplacementPoint( entity player, bool forDebugging = fals vector playerEyeAngles = player.EyeAngles() vector playerOrg = player.GetOrigin() - return CalculateTitanReplacementPoint( playerOrg, playerEyePos, playerEyeAngles, forDebugging ) + Point tempPoint = CalculateTitanReplacementPoint( playerOrg, playerEyePos, playerEyeAngles, forDebugging) + if( file.recalculateTitanReplacementPointCallback != null ) + tempPoint = file.recalculateTitanReplacementPointCallback( tempPoint, player ) + return tempPoint } Point function CalculateTitanReplacementPoint( vector playerOrg, vector playerEyePos, vector playerEyeAngles, bool forDebugging = false ) @@ -165,6 +176,7 @@ Point function CalculateTitanReplacementPoint( vector playerOrg, vector playerEy Point point point.origin = dropPoint point.angles = yawAngles + return point } } @@ -215,7 +227,8 @@ Point function CalculateTitanReplacementPoint( vector playerOrg, vector playerEy Point point point.origin = nodeOrigin point.angles = Vector( 0, yaw, 0 ) - return point + + return point } vector function GetPathNodeSearchPosWithLookPos( vector playerOrg, vector playerEyePos, vector playerEyeForward, vector playerLookPos, bool debug ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan/_titan_health.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan/_titan_health.gnut index d600cb03..396d5624 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/titan/_titan_health.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan/_titan_health.gnut @@ -1010,7 +1010,7 @@ void function AddCreditToTitanCoreBuilder( entity titan, float credit ) if ( IsValid( bossPlayer ) && !coreWasAvailable && IsCoreChargeAvailable( bossPlayer, soul ) ) { - AddPlayerScore( bossPlayer, "TitanCoreEarned" ) + AddPlayerScore( bossPlayer, "TitanCoreEarned", bossPlayer ) // this will show the "Core Earned" callsign event #if MP UpdateTitanCoreEarnedStat( bossPlayer, titan ) PIN_PlayerAbilityReady( bossPlayer, "core" ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan/class_titan.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan/class_titan.gnut index 5f72385e..d0a2d5e4 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/titan/class_titan.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan/class_titan.gnut @@ -68,6 +68,11 @@ bool function ClientCommand_TitanEject( entity player, array<string> args ) if ( !PlayerCanEject( player ) ) return true + // check array length before accessing index to avoid oob access + // prevents crashing a server by just calling `TitanEject` without arguments + if( args.len() < 1 ) + return true + int ejectPressCount = args[ 0 ].tointeger() if ( ejectPressCount < 3 ) return true |