aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobTheBob <32057864+BobTheBob9@users.noreply.github.com>2021-10-14 21:01:40 +0100
committerBobTheBob <32057864+BobTheBob9@users.noreply.github.com>2021-10-14 21:01:40 +0100
commit9a2778eabc7ba968968e41dda9f03525d6c5383d (patch)
tree6d1c5dc64754d542d68a7f47742a701a4eec9308
parentc0a0c7e502f2bc99185d79a485b965f63de7a203 (diff)
downloadNorthstarMods-9a2778eabc7ba968968e41dda9f03525d6c5383d.tar.gz
NorthstarMods-9a2778eabc7ba968968e41dda9f03525d6c5383d.zip
oh fuck i forgot to commit for a while
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_english.txtbin8980 -> 16714 bytes
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_main.nut623
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_map_select.nut9
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_ns_custom_match_settings_categories.nut29
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut53
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut18
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut15
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut12
-rw-r--r--Northstar.Coop/keyvalues/playlists_v2.txt59
-rw-r--r--Northstar.Coop/mod.json25
-rw-r--r--Northstar.Coop/mod/scripts/vscripts/sh_sp_coop.gnut6
-rw-r--r--Northstar.Coop/mod/scripts/vscripts/sh_sp_coop_lobby.gnut19
-rw-r--r--Northstar.Custom/keyvalues/playlists_v2.txt76
-rw-r--r--Northstar.Custom/keyvalues/scripts/weapons/mp_titanweapon_particle_accelerator.txt4
-rw-r--r--Northstar.Custom/mod.json53
-rw-r--r--Northstar.Custom/mod/scripts/levels/mp_bob.rson9
-rw-r--r--Northstar.Custom/mod/scripts/levels/mp_box.rson2
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/_bleedout_damage.gnut137
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/_custom_air_accel.gnut6
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/_custom_oob_timer.gnut7
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut10
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut2
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hs.gnut191
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut6
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_kr.gnut2
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/gamemodes/cl_gamemode_hs.gnut91
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_hs.gnut47
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/mp/levels/mp_bob.nut38
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/mp/levels/mp_bob_temp_props.nut7
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/titan/sh_first_person_embark.gnut6
-rw-r--r--Northstar.Custom/mod/scripts/weapons/mp_weapon_peacekraber.txt6
-rw-r--r--Northstar.Custom/mod/scripts/weapons/mp_weapon_sniper.txt651
-rw-r--r--Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpkbin88553677 -> 95176823 bytes
-rw-r--r--Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpkbin6272 -> 6325 bytes
-rw-r--r--Northstar.CustomServers/mod.json10
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut2
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut17
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut515
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ffa.nut2
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/lobby/_private_lobby.gnut15
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_lobby.gnut23
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut2
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_ai_mp.gnut4
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut1
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp.nut98
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut93
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/levels/_lf_maps_shared.gnut2
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_angel_city.nut10
48 files changed, 1996 insertions, 1017 deletions
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt
index e6175e5bf..ede68b36f 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt
Binary files differ
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_main.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_main.nut
new file mode 100644
index 000000000..9a40f788e
--- /dev/null
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_main.nut
@@ -0,0 +1,623 @@
+global function InitMainMenu
+global function EULA_Dialog
+global function UpdateDataCenterFooter
+global function LaunchGamePurchase
+global function SP_Trial_LaunchGamePurchase
+global function LaunchSPNew
+global function LaunchSPContinue
+global function LaunchSPMissionSelect
+global function LaunchMP
+global function LaunchGame
+global function LaunchSPTrialMission
+global function GetUserSignInState
+
+struct
+{
+ var menu
+ var versionDisplay
+ var trialLabel
+} file
+
+
+void function InitMainMenu()
+{
+ RegisterSignal( "EndOnMainMenu_Open" )
+
+ var menu = GetMenu( "MainMenu" )
+ file.menu = menu
+
+ AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnMainMenu_Open )
+ AddMenuEventHandler( menu, eUIEvent.MENU_NAVIGATE_BACK, OnMainMenu_NavigateBack )
+
+ var titleRui = Hud_GetRui( Hud_GetChild( file.menu, "TitleRui" ) )
+ RuiSetImage( titleRui, "basicImage", $"rui/menu/main_menu/title")
+
+ file.versionDisplay = Hud_GetChild( menu, "versionDisplay" )
+ file.trialLabel = Hud_GetChild( menu, "TrialLabel" )
+
+ #if CONSOLE_PROG
+ AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT", "", null, IsConsoleSignedIn )
+ #if DURANGO_PROG
+ AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_SWITCH_PROFILE", "", null, IsConsoleSignedIn )
+ #endif // DURANGO_PROG
+
+ AddMenuVarChangeHandler( "CONSOLE_isSignedIn", UpdateFooterOptions )
+ #endif // CONSOLE_PROG
+
+ #if PC_PROG
+ AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT", "" )
+ #endif // PC_PROG
+
+ AddMenuFooterOption( menu, BUTTON_X, "#X_BUTTON_INBOX_ACCEPT", "#INBOX_ACCEPT", OpenDataCenterDialog, IsDataCenterFooterValid, UpdateDataCenterFooter )
+
+#if DEV
+ if ( DevStartPoints() )
+ AddMenuFooterOption( menu, BUTTON_Y, "#Y_BUTTON_DEV_MENU", "#DEV_MENU", OpenSinglePlayerDevMenu )
+#endif // DEV
+
+ // do +map stuff
+ if ( Dev_CommandLineHasParm( "+map" ) )
+ thread DelayedMapCommand()
+}
+
+void function DelayedMapCommand()
+{
+ // if we do this too early, game won't run the map command, so we have to wait a bit
+ // 5.0 was determined exclusively by trial and error but seems to work pretty well
+ // might be possible to just do this in native instead, but idk effort
+ wait 5.0
+ SetConVarBool( "ns_auth_allow_insecure", true ) // good for testing
+ ClientCommand( "map " + Dev_CommandLineParmValue( "+map" ) )
+ Dev_CommandLineRemoveParm( "+map" )
+}
+
+#if CONSOLE_PROG
+ bool function IsConsoleSignedIn()
+ {
+ return ( GetMenuVarBool( "CONSOLE_isSignedIn" ) )
+ }
+#endif // CONSOLE_PROG
+
+void function OnMainMenu_Open()
+{
+ Signal( uiGlobal.signalDummy, "EndOnMainMenu_Open" )
+ EndSignal( uiGlobal.signalDummy, "EndOnMainMenu_Open" )
+
+ UpdatePromoData() // On script restarts this gives us the last data until the new request is complete
+ RequestMainMenuPromos() // This will be ignored if there was a recent request. "infoblock_requestInterval"
+
+ TryUnlockCollectiblesAchievement()
+ TryUnlockCompletedGameAchievements()
+
+ Hud_SetText( file.versionDisplay, GetPublicGameVersion() )
+ Hud_Show( file.versionDisplay )
+
+ thread UpdateTrialLabel()
+
+#if PC_PROG
+ ActivatePanel( GetPanel( "MainMenuPanel" ) )
+ return
+#endif // PC_PROG
+
+ int state
+ int lastState = -1
+ var panel
+ var lastPanel
+
+ while ( GetTopNonDialogMenu() == file.menu )
+ {
+ state = GetUserSignInState()
+
+ if ( state != lastState )
+ {
+ if ( state == userSignInState.SIGNED_IN )
+ panel = GetPanel( "MainMenuPanel" )
+ else
+ panel = GetPanel( "EstablishUserPanel" )
+
+ if ( panel != lastPanel )
+ {
+ ActivatePanel( panel )
+ lastPanel = panel
+ }
+ }
+
+ lastState = state
+
+ WaitFrame()
+ }
+}
+
+void function ActivatePanel( var panel )
+{
+ Assert( panel != null )
+
+ array<var> elems = GetElementsByClassname( file.menu, "MainMenuPanelClass" )
+ foreach ( elem in elems )
+ {
+ if ( elem != panel && Hud_IsVisible( elem ) )
+ HidePanel( elem )
+ }
+
+ ShowPanel( panel )
+}
+
+void function OnMainMenu_NavigateBack()
+{
+#if DURANGO_PROG
+ Durango_ShowAccountPicker()
+#endif // DURANGO_PROG
+}
+
+int function GetUserSignInState()
+{
+#if DURANGO_PROG
+ if ( Durango_InErrorScreen() )
+ {
+ return userSignInState.ERROR
+ }
+ else if ( Durango_IsSigningIn() )
+ {
+ return userSignInState.SIGNING_IN
+ }
+ else if ( !Console_IsSignedIn() && !Console_SkippedSignIn() )
+ {
+ //printt( "Console_IsSignedIn():", Console_IsSignedIn(), "Console_SkippedSignIn:", Console_SkippedSignIn() )
+ return userSignInState.SIGNED_OUT
+ }
+
+ Assert( Console_IsSignedIn() || Console_SkippedSignIn() )
+#endif
+ return userSignInState.SIGNED_IN
+}
+
+void function UpdateDataCenterFooter( InputDef data )
+{
+ EndSignal( uiGlobal.signalDummy, "EndFooterUpdateFuncs" )
+
+ int index = int( Hud_GetScriptID( data.vguiElem ) )
+ int ping
+ string name
+
+ while ( data.conditionCheckFunc() )
+ {
+ ping = GetDatacenterPing()
+ name = GetDatacenterName()
+
+ if ( ping > 0 )
+ {
+ if ( IsControllerModeActive() )
+ SetFooterText( file.menu, index, Localize( "#X_BUTTON_DATACENTER_INFO", name, ping ) )
+ else
+ SetFooterText( file.menu, index, Localize( "#DATACENTER_INFO", name, ping ) )
+ }
+ else
+ {
+ if ( IsControllerModeActive() )
+ SetFooterText( file.menu, index, "#X_BUTTON_DATACENTER_CALCULATING" )
+ else
+ SetFooterText( file.menu, index, "#DATACENTER_CALCULATING" )
+ }
+
+ WaitFrame()
+ }
+}
+
+bool function IsDataCenterFooterValid()
+{
+ #if PC_PROG
+ return ( uiGlobal.activeMenu == file.menu )
+ #else
+ return ( uiGlobal.activeMenu == file.menu ) && Console_IsOnline() && Console_IsSignedIn()
+ #endif
+}
+
+void function SP_Trial_LaunchGamePurchase()
+{
+ Disconnect()
+ LaunchGamePurchase()
+}
+
+void function LaunchGamePurchase()
+{
+ ShowGamePurchaseStore()
+}
+
+void function LaunchSPNew()
+{
+ uiGlobal.launching = eLaunching.SINGLEPLAYER_NEW
+ LaunchGame()
+}
+
+void function LaunchSPContinue()
+{
+ uiGlobal.launching = eLaunching.SINGLEPLAYER_CONTINUE
+ LaunchGame()
+}
+
+void function LaunchSPMissionSelect()
+{
+ uiGlobal.launching = eLaunching.SINGLEPLAYER_MISSION_SELECT
+ LaunchGame()
+}
+
+void function LaunchSPTrialMission()
+{
+ uiGlobal.launching = eLaunching.SINGLEPLAYER_MISSION_SELECT
+ SPTrialMission_Start()
+}
+
+void function LaunchMP()
+{
+ uiGlobal.launching = eLaunching.MULTIPLAYER
+ LaunchGame()
+}
+
+void function LaunchGame()
+{
+ Assert( uiGlobal.launching == eLaunching.SINGLEPLAYER_NEW ||
+ uiGlobal.launching == eLaunching.SINGLEPLAYER_CONTINUE ||
+ uiGlobal.launching == eLaunching.SINGLEPLAYER_MISSION_SELECT ||
+ uiGlobal.launching == eLaunching.MULTIPLAYER ||
+ uiGlobal.launching == eLaunching.MULTIPLAYER_INVITE )
+
+ if ( uiGlobal.activeMenu == GetMenu( "PlayVideoMenu" ) )
+ {
+ SetVideoCompleteFunc( null )
+ CloseActiveMenu()
+ }
+
+ if ( !IsGamePartiallyInstalled() )
+ {
+ DoGameNeedsToInstallDialog()
+ return
+ }
+
+ // Because accepting an invite tries to launch the game we need this here
+ if ( !IsGameFullyInstalled() )
+ {
+ printt( "Game is not fully installed." )
+
+ if ( uiGlobal.launching == eLaunching.SINGLEPLAYER_CONTINUE )
+ {
+ string saveName = GetSaveName()
+ string mapName = SaveGame_GetMapName( saveName )
+ int startPointIndex = SaveGame_GetStartPoint( saveName )
+
+ printt( mapName )
+ printt( startPointIndex )
+
+ bool isInTraining = (mapName == "sp_training" && startPointIndex < 5) // "Titanfall" start point
+
+ if ( !isInTraining )
+ {
+ DoGameNeedsToInstallDialog()
+ return
+ }
+
+ printt( "Allowing 'continue' option to load into training." )
+ }
+ else if ( uiGlobal.launching != eLaunching.SINGLEPLAYER_NEW )
+ {
+ DoGameNeedsToInstallDialog()
+ return
+ }
+ }
+
+ #if CONSOLE_PROG
+ if ( !Console_IsSignedIn() )
+ {
+ printt( "Not signed in." )
+ return
+ }
+
+ if ( GetEULAVersionAccepted() < 1 ) // Treat as binary for now, as discussed with Preston.
+ {
+ if ( uiGlobal.activeMenu == GetMenu( "EULADialog" ) )
+ return
+
+ if ( IsDialog( uiGlobal.activeMenu ) )
+ CloseActiveMenu( true )
+
+ EULA_Dialog()
+ return
+ }
+
+ if ( Nucleus_GetState() == NUCLEUS_STATE_INACTIVE )
+ Nucleus_Login()
+
+ if ( !uiGlobal.triedNucleusRegistration && uiGlobal.launching == eLaunching.MULTIPLAYER && !Nucleus_GetSkipRegistration() )
+ {
+ uiGlobal.triedNucleusRegistration = true
+ thread Nucleus_HandleLoginResponse()
+ return
+ }
+
+ if ( !GetConVarBool( "gamma_adjusted" ) )
+ {
+ if ( IsDialog( uiGlobal.activeMenu ) )
+ CloseActiveMenu( true )
+
+ AdvanceMenu( GetMenu( "GammaMenu" ) )
+ return
+ }
+ #endif // CONSOLE_PROG
+
+ if ( ( uiGlobal.launching == eLaunching.MULTIPLAYER || uiGlobal.launching == eLaunching.MULTIPLAYER_INVITE ) && !IsAdvocateGiftComplete() )
+ {
+ if ( IsDialog( uiGlobal.activeMenu ) )
+ CloseActiveMenu( true )
+
+ AdvanceMenu( GetMenu( "AdvocateGiftDialog" ) )
+ return
+ }
+
+ SetMenuWasMultiplayerPlayedLast( true )
+ if ( uiGlobal.launching == eLaunching.SINGLEPLAYER_NEW )
+ NewGameSelected()
+ else if ( uiGlobal.launching == eLaunching.SINGLEPLAYER_CONTINUE )
+ LoadLastCheckpoint()
+ else if ( uiGlobal.launching == eLaunching.SINGLEPLAYER_MISSION_SELECT )
+ AdvanceMenu( GetMenu( "SinglePlayerMenu" ) )
+ else
+ thread StartSearchForPartyServer()
+
+ uiGlobal.launching = eLaunching.FALSE
+}
+
+void function StartSearchForPartyServer()
+{
+ printt( "StartSearchForPartyServer" )
+
+#if DURANGO_PROG
+ // IMPORTANT: As a safety measure leave any party view we are in at this point.
+ // Otherwise, if you are unlucky enough to get stuck in a party view, you will
+ // trash its state by pointing it to your private lobby.
+ Durango_LeaveParty()
+
+ // IMPORTANT: It's possible that you have permission to play multiplayer
+ // because your friend is signed in with his gold account on your machine,
+ // but once that guy signs out, you shouldn't be able to play like you have
+ // xboxlive gold anymore. To fix this, we need to check permissions periodically.
+ // One of the places where we do this periodic check is when you press "PLAY"
+ printt( "Durango - verifying MP permissions" )
+ if ( !Console_HasPermissionToPlayMultiplayer() )
+ Durango_VerifyMultiplayerPermissions()
+#endif // DURANGO_PROG
+
+ Signal( uiGlobal.signalDummy, "OnCancelConnect" )
+ EndSignal( uiGlobal.signalDummy, "OnCancelConnect" )
+
+ if ( IsDialog( uiGlobal.activeMenu ) )
+ CloseActiveMenu( true )
+ OpenConnectingDialog()
+
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "" )
+ Hud_SetText( uiGlobal.ConfirmMenuErrorCode, "" )
+
+ Hud_Show( uiGlobal.ConfirmMenuMessage )
+ Hud_Show( uiGlobal.ConfirmMenuErrorCode )
+
+#if DURANGO_PROG
+ if( !Console_IsOnline() )
+ {
+ printt( "Durango - finding empty party server failed - not online" )
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#DURANGO_NOT_ONLINE" )
+ return
+ }
+#endif // DURANGO_PROG
+
+#if PS4_PROG
+ if( !Console_IsOnline() )
+ {
+ printt( "PS4 - finding empty party server failed - not online" )
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#INTERNET_NOT_FOUND" )
+ return
+ }
+
+ if ( PS4_isNetworkingDown() )
+ {
+ printt( "PS4 - finding empty party server failed - networking is down" )
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#PSN_CANNOT_CONNECT" )
+ return
+ }
+
+ if( !PS4_isUserNetworkingEnabled() )
+ {
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#PSN_CHECKING_USABILITY" )
+ PS4_ScheduleUserNetworkingEnabledTest()
+ WaitFrame()
+
+ if( !PS4_isUserNetworkingResolved() )
+ {
+ printt( "PS4 - finding empty party server stalled - networking isn't resolved yet" )
+ // offer cancel ??
+ while( !PS4_isUserNetworkingResolved())
+ WaitFrame()
+ }
+
+ if( PS4_getUserNetworkingResolution() == PS4_NETWORK_STATUS_NOT_LOGGED_IN )
+ {
+ Hud_SetText( uiGlobal.ConfirmMenuErrorCode, string(PS4_getUserNetworkingErrorStatus()) )
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#PSN_LOGIN" )
+
+ Ps4_LoginDialog_Schedule()
+ while( Ps4_LoginDialog_Running() )
+ WaitFrame()
+
+ PS4_ScheduleUserNetworkingEnabledTest()
+ WaitFrame()
+ if( !PS4_isUserNetworkingResolved() )
+ {
+ Hud_SetText( uiGlobal.ConfirmMenuErrorCode, "" )
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#PSN_CHECKING_USABILITY" )
+ while( !PS4_isUserNetworkingResolved())
+ WaitFrame()
+ }
+ }
+
+ if( PS4_getUserNetworkingResolution() == PS4_NETWORK_STATUS_AGE_RESTRICTION )
+ {
+ Hud_SetText( uiGlobal.ConfirmMenuErrorCode, string(PS4_getUserNetworkingErrorStatus()) )
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#MULTIPLAYER_AGE_RESTRICTED" )
+ return
+ }
+
+ if( PS4_getUserNetworkingResolution() == PS4_NETWORK_STATUS_IN_ERROR )
+ {
+ Hud_SetText( uiGlobal.ConfirmMenuErrorCode, string(PS4_getUserNetworkingErrorStatus()) )
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#PSN_HAD_ERROR" )
+ return
+ }
+
+ if( !PS4_isUserNetworkingEnabled() )
+ {
+ Hud_SetText( uiGlobal.ConfirmMenuErrorCode, string(PS4_getUserNetworkingErrorStatus()) )
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#PSN_NOT_ALLOWED" )
+ return
+ }
+
+ Hud_SetText( uiGlobal.ConfirmMenuErrorCode, "" )
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "" )
+ }
+
+ if ( !Ps4_PSN_Is_Loggedin() )
+ {
+ Ps4_LoginDialog_Schedule()
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#PSN_LOGIN" )
+
+ while( Ps4_LoginDialog_Running() )
+ WaitFrame()
+
+ if ( !Ps4_PSN_Is_Loggedin() )
+ return
+ }
+
+ if( Ps4_CheckPlus_Schedule() )
+ {
+ while( Ps4_CheckPlus_Running() )
+ WaitFrame()
+ if( !Ps4_CheckPlus_Allowed() )
+ {
+ if( Ps4_CheckPlus_GetLastRequestResults() != 0 )
+ {
+ Hud_SetText( uiGlobal.ConfirmMenuErrorCode, string( Ps4_CheckPlus_GetLastRequestResults()) )
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#PSN_HAD_ERROR" )
+ return
+ }
+
+ if( Ps4_ScreenPlusDialog_Schedule() )
+ {
+ while( Ps4_ScreenPlusDialog_Running() )
+ WaitFrame()
+ if( !Ps4_ScreenPlusDialog_Allowed() )
+ {
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#PSN_MUST_BE_PLUS_USER" )
+ return
+ }
+ }
+ else
+ {
+ return
+ }
+ }
+ }
+
+ Hud_SetText( uiGlobal.ConfirmMenuErrorCode, "" )
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "" )
+#endif // #if PS4_PROG
+
+ printt( "Checking if this user has permission to play MP\n" )
+ if ( !Console_HasPermissionToPlayMultiplayer() )
+ {
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#MULTIPLAYER_NOT_AVAILABLE" )
+ return
+ }
+
+ Plat_ShowUGCRestrictionNotice()
+ while ( Plat_IsSystemMessageDialogOpen() )
+ WaitFrame()
+
+ Plat_ShowChatRestrictionNotice()
+ while ( Plat_IsSystemMessageDialogOpen() )
+ WaitFrame()
+
+#if PC_PROG
+ if ( Origin_IsEnabled() )
+ {
+ Origin_RequestTicket()
+ Hud_SetText( uiGlobal.ConfirmMenuMessage, "#WAITING_FOR_ORIGIN" )
+
+ while ( !Origin_IsReady() )
+ WaitFrame()
+ }
+#endif // PC_PROG
+
+ printt( "SearchForPartyServer" )
+ SetMenuWasMultiplayerPlayedLast( true )
+ SearchForPartyServer()
+
+ Hud_SetAutoText( uiGlobal.ConfirmMenuMessage, "", HATT_MATCHMAKING_EMPTY_SERVER_SEARCH_STATE, 0 )
+ Hud_SetAutoText( uiGlobal.ConfirmMenuErrorCode, "", HATT_MATCHMAKING_EMPTY_SERVER_SEARCH_ERROR, 0 )
+}
+
+void function EULA_Dialog()
+{
+ if ( GetUserSignInState() != userSignInState.SIGNED_IN )
+ return
+
+ if ( GetEULAVersionAccepted() >= 1 )
+ return
+
+ AdvanceMenu( GetMenu( "EULADialog" ) )
+}
+
+void function DoGameNeedsToInstallDialog()
+{
+ DialogData dialogData
+ dialogData.header = "#MENU_WAIT_FOR_INTALL"
+
+ int installProgress = int( GetGameFullyInstalledProgress()*100 )
+
+ if ( uiGlobal.launching == eLaunching.MULTIPLAYER && IsGamePartiallyInstalled() && !Script_IsRunningTrialVersion() )
+ {
+ dialogData.message = Localize("#MENU_WAIT_FOR_INTALL_HINT", installProgress )
+ AddDialogButton( dialogData, "#YES", LaunchSPNew )
+ AddDialogButton( dialogData, "#NO" )
+ }
+ else
+ {
+ dialogData.message = Localize("#MENU_WAIT_FOR_INTALL_HINT_NOTRAINING", installProgress )
+ AddDialogButton( dialogData, "#OK" )
+ }
+
+ AddDialogFooter( dialogData, "#A_BUTTON_SELECT" )
+ AddDialogFooter( dialogData, "#B_BUTTON_CANCEL" )
+
+ OpenDialog( dialogData )
+}
+
+void function UpdateTrialLabel()
+{
+ bool isTrialVersion
+ bool lastIsTrialVersion = Script_IsRunningTrialVersion()
+
+ Hud_SetVisible( file.trialLabel, lastIsTrialVersion )
+
+ while ( GetTopNonDialogMenu() == file.menu )
+ {
+ isTrialVersion = Script_IsRunningTrialVersion()
+
+ if ( isTrialVersion != lastIsTrialVersion )
+ Hud_SetVisible( file.trialLabel, isTrialVersion )
+
+ lastIsTrialVersion = isTrialVersion
+
+ WaitFrame()
+ }
+}
+
+void function OpenSinglePlayerDevMenu( var button )
+{
+ AdvanceMenu( GetMenu( "SinglePlayerDevMenu" ) )
+}
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_map_select.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_map_select.nut
index 7ed0d1773..29daf0a8a 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/menu_map_select.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_map_select.nut
@@ -59,7 +59,12 @@ void function UpdateVisibleMaps()
if ( buttonID < file.mapsPerPage && mapID < GetPrivateMatchMaps().len() )
{
string name = mapsArray[ mapID ]
- SetButtonRuiText( button, GetMapDisplayName( name ) )
+
+ bool sp = name.find( "sp_" ) == 0
+ if ( sp )
+ SetButtonRuiText( button, Localize( "#PRIVATE_MATCH_SINGLEPLAYER_LEVEL", Localize( GetMapDisplayName( name ) ) ) )
+ else
+ SetButtonRuiText( button, GetMapDisplayName( name ) )
Hud_SetEnabled( button, true )
if ( IsItemInEntitlementUnlock( name ) && IsValid( GetUIPlayer() ) )
@@ -73,7 +78,7 @@ void function UpdateVisibleMaps()
bool mapSupportsMode = PrivateMatch_IsValidMapModeCombo( name, PrivateMatch_GetSelectedMode() )
Hud_SetLocked( button, !mapSupportsMode )
- if ( !mapSupportsMode )
+ if ( !mapSupportsMode && !sp )
SetButtonRuiText( button, Localize( "#PRIVATE_MATCH_UNAVAILABLE", Localize( GetMapDisplayName( name ) ) ) )
}
else
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_custom_match_settings_categories.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_custom_match_settings_categories.nut
index 711cbbbcf..be2a10483 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_custom_match_settings_categories.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_custom_match_settings_categories.nut
@@ -25,31 +25,14 @@ void function OnNorthstarCustomMatchSettingsCategoryMenuOpened()
array<string> categories = GetPrivateMatchSettingCategories()
array<var> buttons = GetElementsByClassname( GetMenu( "CustomMatchSettingsCategoryMenu" ), "MatchSettingCategoryButton" )
- for ( int i = 0, j = 0; j < categories.len() && i < buttons.len(); i++, j++ )
+ foreach ( var button in buttons )
{
- Hud_SetEnabled( buttons[ i ], false )
- Hud_SetVisible( buttons[ i ], false )
+ Hud_SetEnabled( button, false )
+ Hud_SetVisible( button, false )
+ }
- // skip gamemode/playlist categories for modes that aren't the current one
- // todo this fucking breaks everything lmao
- //bool gamemode = categories[ j ].find( "#GAMEMODE_" ) == 0
- //if ( gamemode || categories[ j ].find( "#PL_" ) == 0 )
- //{
- // if ( gamemode )
- // {
- // if ( categories[ j ].slice( 10 ) != PrivateMatch_GetSelectedMode() )
- // {
- // i--
- // continue
- // }
- // }
- // else if ( categories[ j ].slice( 4 ) != PrivateMatch_GetSelectedMode() )
- // {
- // i--
- // continue
- // }
- //}
-
+ for ( int i = 0, j = 0; j < categories.len() && i < buttons.len(); i++, j++ )
+ {
Hud_SetText( buttons[ i ], Localize( categories[ j ] ) + " ->" )
Hud_SetEnabled( buttons[ i ], true )
Hud_SetVisible( buttons[ i ], true )
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut
index 4a56891e3..588fe7050 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut
@@ -1,6 +1,10 @@
global function AddNorthstarModMenu
global function AddNorthstarModMenu_MainMenuFooter
+struct {
+ bool shouldReloadModsOnEnd
+} file
+
void function AddNorthstarModMenu()
{
AddMenu( "ModListMenu", $"resource/ui/menus/modlist.menu", InitModMenu )
@@ -21,15 +25,21 @@ void function InitModMenu()
var menu = GetMenu( "ModListMenu" )
AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnModMenuOpened )
+ AddMenuEventHandler( menu, eUIEvent.MENU_CLOSE, OnModMenuClosed )
AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" )
- AddMenuFooterOption( menu, BUTTON_Y, "#Y_RELOAD_MODS", "#RELOAD_MODS", ReloadMods )
+ AddMenuFooterOption( menu, BUTTON_Y, "#Y_RELOAD_MODS", "#RELOAD_MODS", OnReloadModsButtonPressed )
foreach ( var button in GetElementsByClassname( GetMenu( "ModListMenu" ), "ModButton" ) )
+ {
AddButtonEventHandler( button, UIE_GET_FOCUS, OnModMenuButtonFocused )
+ AddButtonEventHandler( button, UIE_CLICK, OnModMenuButtonPressed )
+ }
}
void function OnModMenuOpened()
{
+ file.shouldReloadModsOnEnd = false
+
Hud_SetText( Hud_GetChild( GetMenu( "ModListMenu" ), "Title" ), "#MENU_TITLE_MODS" )
array<var> buttons = GetElementsByClassname( GetMenu( "ModListMenu" ), "ModButton" )
@@ -47,10 +57,36 @@ void function OnModMenuOpened()
Hud_SetEnabled( buttons[ i ], true )
Hud_SetVisible( buttons[ i ], true )
- SetButtonRuiText( buttons[ i ], modNames[ i ] + " v" + NSGetModVersionByModName( modNames[ i ] ) )
+ SetModMenuNameText( buttons[ i ] )
}
}
+void function OnModMenuClosed()
+{
+ if ( file.shouldReloadModsOnEnd )
+ ReloadMods()
+}
+
+void function SetModMenuNameText( var button )
+{
+ string modName = NSGetModNames()[ int ( Hud_GetScriptID( button ) ) ]
+
+ // should be localisation at some point
+ if ( NSIsModEnabled( modName ) )
+ SetButtonRuiText( button, modName + " v" + NSGetModVersionByModName( modName ) )
+ else
+ SetButtonRuiText( button, modName + " (DISABLED)" )
+}
+
+void function OnModMenuButtonPressed( var button )
+{
+ string modName = NSGetModNames()[ int ( Hud_GetScriptID( button ) ) ]
+ NSSetModEnabled( modName, !NSIsModEnabled( modName ) )
+ SetModMenuNameText( button )
+
+ file.shouldReloadModsOnEnd = true
+}
+
void function OnModMenuButtonFocused( var button )
{
string modName = NSGetModNames()[ int ( Hud_GetScriptID( button ) ) ]
@@ -101,8 +137,17 @@ string function FormatModDescription( string modName )
return ret
}
-void function ReloadMods( var button )
+void function OnReloadModsButtonPressed( var button )
+{
+ ReloadMods()
+}
+
+void function ReloadMods()
{
NSReloadMods()
- OnModMenuOpened() // temp, until we start doing uiscript_reset here
+ ClientCommand( "reload_localization" )
+ ClientCommand( "loadPlaylists" )
+ // ClientCommand( "weapon_reparse" ) // this doesn't work, weapon_reparse only works if a server is running and sv_cheats is 1, gotta figure this out eventually
+ // note: the logic for this seems really odd, unsure why it doesn't seem to update, since the same code seems to get run irregardless of whether we've read weapon data before
+ ClientCommand( "uiscript_reset" )
} \ No newline at end of file
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut
index bbeb0d0b9..121de6141 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut
@@ -195,4 +195,22 @@ void function ThreadedAuthAndConnectToServer( string password = "" )
if ( NSWasAuthSuccessful() )
NSConnectToAuthedServer()
+ else
+ {
+ print( "fuck" )
+
+ DialogData dialogData
+ dialogData.header = "#ERROR"
+ dialogData.message = "Authentication Failed"
+ dialogData.image = $"ui/menu/common/dialog_error"
+
+ #if PC_PROG
+ AddDialogButton( dialogData, "#DISMISS" )
+
+ AddDialogFooter( dialogData, "#A_BUTTON_SELECT" )
+ #endif // PC_PROG
+ AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" )
+
+ OpenDialog( dialogData )
+ }
} \ No newline at end of file
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut
index d203a6730..417214553 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut
@@ -91,6 +91,19 @@ const table<asset> mapImages =
mp_rise = $"loadscreens/mp_rise_lobby",
mp_lf_township = $"loadscreens/mp_lf_township_lobby",
mp_lf_uma = $"loadscreens/mp_lf_uma_lobby",
+
+ // not really sure if this should be here, whatever
+ // might be good to make this modular in the future?
+ sp_training = $"rui/menu/level_select/level_image1",
+ sp_crashsite = $"rui/menu/level_select/level_image2",
+ sp_sewers1 = $"rui/menu/level_select/level_image3",
+ sp_boomtown_start = $"rui/menu/level_select/level_image4",
+ sp_hub_timeshift = $"rui/menu/level_select/level_image5",
+ sp_beacon = $"rui/menu/level_select/level_image6",
+ sp_tday = $"rui/menu/level_select/level_image7",
+ sp_s2s = $"rui/menu/level_select/level_image8",
+ sp_skyway_v1 = $"rui/menu/level_select/level_image9",
+
}
void function MenuPrivateMatch_Init()
@@ -630,7 +643,7 @@ function UpdateLobby()
{
bool shouldBreak = false
- foreach ( string category in GetPrivateMatchSettingCategories() )
+ foreach ( string category in GetPrivateMatchSettingCategories( true ) )
{
foreach ( CustomMatchSettingContainer setting in GetPrivateMatchCustomSettingsForCategory( category ) )
{
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut
index acd11237d..d42a2331d 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut
@@ -32,6 +32,11 @@ const DEBUG_PERMISSIONS = false
void function InitMainMenuPanel()
{
+ // disable communities because of the cool openinvite exploit (not required anymore but keeping here anyway
+ SetConVarBool( "communities_enabled", false )
+ SetConVarString( "communities_hostname", "localhost" )
+
+
RegisterSignal( "EndShowMainMenuPanel" )
file.panel = GetPanel( "MainMenuPanel" )
@@ -77,7 +82,7 @@ void function InitMainMenuPanel()
var multiplayerHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MULTIPLAYER_ALLCAPS" )
file.mpButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MULTIPLAYER_LAUNCH" )
Hud_AddEventHandler( file.mpButton, UIE_CLICK, OnPlayMPButton_Activate )
- file.fdButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#GAMEMODE_COOP" )
+ file.fdButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_LAUNCH_NORTHSTAR" )
Hud_AddEventHandler( file.fdButton, UIE_CLICK, OnPlayFDButton_Activate )
headerIndex++
@@ -443,7 +448,7 @@ void function UpdatePlayButton( var button )
//else
//{
//ComboButton_SetText( file.fdButton, "#MULTIPLAYER_LAUNCH_FD" )
- ComboButton_SetText( file.fdButton, "Launch Northstar" ) // this needs to use localised text at some point when we have a modular way of doing that
+ ComboButton_SetText( file.fdButton, "#MENU_LAUNCH_NORTHSTAR" ) // this needs to use localised text at some point when we have a modular way of doing that
Hud_SetEnabled( file.fdButton, true )
//}
@@ -521,6 +526,9 @@ void function TryAuthWithLocalServer()
if ( NSWasAuthSuccessful() )
NSCompleteAuthWithLocalServer()
+ if ( GetConVarString( "mp_gamemode" ) == "solo" )
+ SetConVarString( "mp_gamemode", "tdm" )
+
ClientCommand( "setplaylist tdm" )
ClientCommand( "map mp_lobby" )
}
diff --git a/Northstar.Coop/keyvalues/playlists_v2.txt b/Northstar.Coop/keyvalues/playlists_v2.txt
new file mode 100644
index 000000000..e3a241b7c
--- /dev/null
+++ b/Northstar.Coop/keyvalues/playlists_v2.txt
@@ -0,0 +1,59 @@
+playlists
+{
+ Playlists
+ {
+ sp_coop
+ {
+ inherit defaults
+ vars
+ {
+ name #PL_sp_coop
+ lobbytitle #PL_sp_coop_lobby
+ description #PL_sp_coop_desc
+ hint #PL_sp_coop_hint
+ abbreviation #PL_sp_coop_abbr
+ image ffa
+
+ // taken from solo gamemode
+ always_enable_autotitans 1
+ burn_meter_enabled 0
+ cinematic_mode 1
+ classic_mp 0
+ hud_score_enabled 0
+ max_players 16
+ max_teams 1
+ ranking_supported 0
+ riff_allow_npcs 1
+ riff_minimap_state 1
+ riff_titan_availability 3
+ riff_titan_exit_enabled 3
+ rodeo_battery_disembark_to_pickup 0
+ titan_build_time 300
+ titan_health_bar_display default
+ titan_mode_change_allowed 0
+ titan_rebuild_time 195
+ titan_segmented_health 0
+ titan_shield_regen 1
+ }
+
+ gamemodes
+ {
+ solo
+ {
+ maps
+ {
+ sp_training 1
+ sp_crashsite 1
+ sp_sewers1 1
+ sp_boomtown_start 1
+ sp_hub_timeshift 1
+ sp_beacon 1
+ sp_tday 1
+ sp_s2s 1
+ sp_skyway_v1 1
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Northstar.Coop/mod.json b/Northstar.Coop/mod.json
new file mode 100644
index 000000000..b4dfaeb27
--- /dev/null
+++ b/Northstar.Coop/mod.json
@@ -0,0 +1,25 @@
+{
+ "Name" : "Northstar.Coop",
+ "Description" : "Allows the singleplayer campaign to be played in multiplayer",
+
+ "LoadPriority": 0,
+
+ "Scripts": [
+ {
+ "Path": "sh_sp_coop.gnut",
+ "RunOn": "SP"
+ },
+
+ {
+ "Path": "sh_sp_coop_lobby.gnut",
+ "RunOn": "( CLIENT || SERVER ) && MP",
+ "ClientCallback": {
+ "After": "SingleplayerCoopLobby_Init"
+ },
+
+ "ServerCallback": {
+ "After": "SingleplayerCoopLobby_Init"
+ }
+ },
+ ],
+} \ No newline at end of file
diff --git a/Northstar.Coop/mod/scripts/vscripts/sh_sp_coop.gnut b/Northstar.Coop/mod/scripts/vscripts/sh_sp_coop.gnut
new file mode 100644
index 000000000..09293a70c
--- /dev/null
+++ b/Northstar.Coop/mod/scripts/vscripts/sh_sp_coop.gnut
@@ -0,0 +1,6 @@
+global function IsSPCoopMode
+
+bool function IsSPCoopMode()
+{
+ return GAMETYPE == "solo" && GetCurrentPlaylistName() == "sp_coop"
+} \ No newline at end of file
diff --git a/Northstar.Coop/mod/scripts/vscripts/sh_sp_coop_lobby.gnut b/Northstar.Coop/mod/scripts/vscripts/sh_sp_coop_lobby.gnut
new file mode 100644
index 000000000..59a31ee87
--- /dev/null
+++ b/Northstar.Coop/mod/scripts/vscripts/sh_sp_coop_lobby.gnut
@@ -0,0 +1,19 @@
+global function SingleplayerCoopLobby_Init
+
+void function SingleplayerCoopLobby_Init()
+{
+ if ( !IsLobby() )
+ return
+
+ AddPrivateMatchMode( "sp_coop" )
+
+ AddPrivateMatchMap( "sp_training" )
+ AddPrivateMatchMap( "sp_crashsite" )
+ AddPrivateMatchMap( "sp_sewers1" )
+ AddPrivateMatchMap( "sp_boomtown_start" )
+ AddPrivateMatchMap( "sp_hub_timeshift" )
+ AddPrivateMatchMap( "sp_beacon" )
+ AddPrivateMatchMap( "sp_tday" )
+ AddPrivateMatchMap( "sp_s2s" )
+ AddPrivateMatchMap( "sp_skyway_v1" )
+} \ No newline at end of file
diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt
index 30ea69807..813accb64 100644
--- a/Northstar.Custom/keyvalues/playlists_v2.txt
+++ b/Northstar.Custom/keyvalues/playlists_v2.txt
@@ -185,6 +185,23 @@ playlists
gamemode_bullet_005 #GAMEMODE_BULLET_CTF_005
}
}
+ hs
+ {
+ inherit defaults
+ vars
+ {
+ name #GAMEMODE_hs
+ lobbytitle #PL_hs_lobby
+ description #PL_hs_desc
+ hint #PL_hs_hint
+ abbreviation #PL_hs_abbr
+ image tdm
+ timelimit 10
+ max_players 16
+
+ gamemode_score_hint #GAMEMODE_SCORE_HINT_TDM
+ }
+ }
}
Playlists
{
@@ -242,6 +259,7 @@ playlists
lobbytitle #PL_tt_lobby
description #PL_tt_desc
hint #PL_tt_hint
+ image lts
abbreviation #PL_tt_abbr
visible 0
}
@@ -279,6 +297,7 @@ playlists
lobbytitle #PL_inf_lobby
description #PL_inf_desc
hint #PL_inf_hint
+ image ps
abbreviation #PL_inf_abbr
visible 0
}
@@ -376,7 +395,7 @@ playlists
description #PL_kr_desc
hint #PL_kr_hint
abbreviation #PL_kr_abbr
-
+ image ctf
max_players 16
max_teams 16
classic_mp 1
@@ -424,7 +443,7 @@ playlists
description #PL_fastball_desc
hint #PL_fastball_hint
abbreviation #PL_fastball_abbr
-
+ image ffa
max_players 16
max_teams 2
classic_mp 1
@@ -469,6 +488,7 @@ playlists
description #PL_fw_desc
hint #PL_fw_hint
abbreviation #PL_fw_abbr
+ image fw
max_players 16
max_teams 2
@@ -568,5 +588,57 @@ playlists
}
}
}
+ hs
+ {
+ inherit defaults
+ vars
+ {
+ name #GAMEMODE_hs
+ lobbytitle #PL_hs_lobby
+ description #PL_hs_desc
+ hint #PL_hs_hint
+ abbreviation #PL_hs_abbr
+ image tdm
+ timelimit 10
+ max_players 16
+
+ gamemode_score_hint #GAMEMODE_SCORE_HINT_TDM
+ }
+ gamemodes
+ {
+ hs
+ {
+ mp_complex3 1
+ mp_drydock 1
+ mp_glitch 1
+ mp_homestead 2
+ mp_eden 1
+ mp_forwardbase_kodai 1
+ mp_black_water_canal 1
+ mp_glitch 1
+ mp_angel_city 1
+ mp_colony02 1
+ mp_relic02 1
+ mp_grave 1
+ mp_homestead 1
+ mp_drydock 1
+ mp_glitch 1
+ mp_thaw 1
+ mp_eden 2
+ mp_black_water_canal 1
+ mp_glitch 1
+ mp_relic02 1
+ mp_wargames 1
+ mp_rise 1
+ mp_crashsite3 1
+ mp_lf_stacks 1
+ mp_lf_deck 1
+ mp_lf_meadow 1
+ mp_lf_traffic 1
+ mp_lf_township 1
+ mp_lf_uma 1
+ }
+ }
+ }
}
} \ No newline at end of file
diff --git a/Northstar.Custom/keyvalues/scripts/weapons/mp_titanweapon_particle_accelerator.txt b/Northstar.Custom/keyvalues/scripts/weapons/mp_titanweapon_particle_accelerator.txt
deleted file mode 100644
index a30ed8f8f..000000000
--- a/Northstar.Custom/keyvalues/scripts/weapons/mp_titanweapon_particle_accelerator.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-WeaponData
-{
- "playermodel" "models/SPOILER_w_titan_particle_accelerator.mdl"
-}
diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json
index d1ebeec32..8a09c7563 100644
--- a/Northstar.Custom/mod.json
+++ b/Northstar.Custom/mod.json
@@ -249,6 +249,27 @@
"RunOn": "CLIENT && MP"
},
+ // hide and seek
+ {
+ "Path": "gamemodes/sh_gamemode_hs.gnut",
+ "RunOn": "( CLIENT || SERVER ) && MP",
+ "ClientCallback": {
+ "Before": "Sh_GamemodeHideAndSeek_Init"
+ },
+
+ "ServerCallback": {
+ "Before": "Sh_GamemodeHideAndSeek_Init"
+ }
+ },
+ {
+ "Path": "gamemodes/_gamemode_hs.gnut",
+ "RunOn": "SERVER && MP"
+ },
+ {
+ "Path": "gamemodes/cl_gamemode_hs.gnut",
+ "RunOn": "CLIENT && MP"
+ },
+
// ctf comp
{
"Path": "gamemodes/sh_gamemode_ctf_comp.gnut",
@@ -267,10 +288,12 @@
"RunOn": "( CLIENT || SERVER ) && MP",
"ClientCallback": {
"Before": "FirstPersonEmbark_Init",
+ "After": "FirstPersonEmbark_InitPlaylistVars"
},
"ServerCallback": {
- "Before": "FirstPersonEmbark_Init"
+ "Before": "FirstPersonEmbark_Init",
+ "After": "FirstPersonEmbark_InitPlaylistVars"
}
},
@@ -285,7 +308,7 @@
{
"Path": "_custom_air_accel.gnut",
- "RunOn": "MP",
+ "RunOn": "CLIENT || SERVER",
"ClientCallback": {
"After": "CustomAirAccelVars_Init"
},
@@ -306,6 +329,32 @@
"After": "Promode_Init"
}
},
+
+ {
+ "Path": "_bleedout_damage.gnut",
+ "RunOn": "( CLIENT || SERVER ) && MP",
+ "ClientCallback": {
+ "Before": "BleedoutDamage_PreInit",
+ "After": "BleedoutDamage_Init"
+ },
+
+ "ServerCallback": {
+ "Before": "BleedoutDamage_PreInit",
+ "After": "BleedoutDamage_Init"
+ }
+ },
+
+ {
+ "Path": "_custom_oob_timer.gnut",
+ "RunOn": "( CLIENT || SERVER ) && MP",
+ "ClientCallback": {
+ "After": "CustomOOBTimer_Init"
+ },
+
+ "ServerCallback": {
+ "After": "CustomOOBTimer_Init"
+ }
+ }
],
"Localisation": [
diff --git a/Northstar.Custom/mod/scripts/levels/mp_bob.rson b/Northstar.Custom/mod/scripts/levels/mp_bob.rson
new file mode 100644
index 000000000..58c8a1ca5
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/levels/mp_bob.rson
@@ -0,0 +1,9 @@
+//C:\depot\r2dev\game autofastfunction.pl
+
+IsTestMap: false
+When: "SERVER"
+Scripts:
+[
+ mp/levels/mp_bob_temp_props.nut
+ mp/levels/mp_bob.nut
+] \ No newline at end of file
diff --git a/Northstar.Custom/mod/scripts/levels/mp_box.rson b/Northstar.Custom/mod/scripts/levels/mp_box.rson
index 1a8d1ee70..3056c5058 100644
--- a/Northstar.Custom/mod/scripts/levels/mp_box.rson
+++ b/Northstar.Custom/mod/scripts/levels/mp_box.rson
@@ -1,6 +1,6 @@
//C:\depot\r2dev\game autofastfunction.pl
-IsTestMap: false
+IsTestMap: true
When: "SERVER"
Scripts:
[
diff --git a/Northstar.Custom/mod/scripts/vscripts/_bleedout_damage.gnut b/Northstar.Custom/mod/scripts/vscripts/_bleedout_damage.gnut
new file mode 100644
index 000000000..8b21184ad
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/vscripts/_bleedout_damage.gnut
@@ -0,0 +1,137 @@
+// note: this is technically vanilla content, since bleedout was shipped with retail, but it needs custom remote functions which would break vanilla compatiblity, so it's not in Northstar.CustomServers
+// idk why bleedout was even shipped in retail lmao
+global function BleedoutDamage_PreInit
+global function BleedoutDamage_Init
+global function SetShouldPlayerStartBleedoutFunc
+
+struct {
+ array<entity> bleedingPlayers // this is in _bleedout already, but it doesn't expose a way to track it, so we have to track it ourselves
+ bool functionref( entity, var ) shouldPlayerStartBleedoutFunc = null
+} file
+
+void function BleedoutDamage_PreInit()
+{
+ AddCallback_OnRegisteringCustomNetworkVars( Bleedout_RegisterRemoteFunctions )
+}
+
+void function Bleedout_RegisterRemoteFunctions()
+{
+ Remote_RegisterFunction( "ServerCallback_BLEEDOUT_StartFirstAidProgressBar" )
+ Remote_RegisterFunction( "ServerCallback_BLEEDOUT_StopFirstAidProgressBar" )
+ Remote_RegisterFunction( "ServerCallback_BLEEDOUT_ShowWoundedMarker" )
+ Remote_RegisterFunction( "ServerCallback_BLEEDOUT_HideWoundedMarker" )
+}
+
+// copied from sh_bleedout
+const float DEFAULT_BLEEDOUT_TIME = 30.0
+const float DEFAULT_FIRSTAID_TIME = 3.0
+const float DEFAULT_FIRSTAID_TIME_SELF = -1.0
+const float DEFAULT_FIRSTAID_HEAL_PERCENT = 1.0
+const float DEFAULT_AI_BLEEDING_PLAYER_MISS_CHANCE = 0.0
+const bool DEFAULT_FORCE_WEAPON_HOLSTER = false
+const bool DEFAULT_DEATH_ON_TEAM_BLEEDOUT = false
+
+void function BleedoutDamage_Init()
+{
+ AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_BLEEDOUT", "riff_player_bleedout", [ "Default", "Disabled", "Enabled" ], "0" )
+ AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_BLEEDOUT", "player_bleedout_forceHolster", [ "Disabled", "Enabled" ], DEFAULT_FORCE_WEAPON_HOLSTER.tostring() )
+ AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_BLEEDOUT", "player_bleedout_forceDeathOnTeamBleedout", [ "Disabled", "Enabled" ], DEFAULT_DEATH_ON_TEAM_BLEEDOUT.tostring() )
+ AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_BLEEDOUT", "player_bleedout_bleedoutTime", DEFAULT_BLEEDOUT_TIME.tostring() )
+ AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_BLEEDOUT", "player_bleedout_firstAidTime", DEFAULT_FIRSTAID_TIME.tostring() )
+ AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_BLEEDOUT", "player_bleedout_firstAidTimeSelf", DEFAULT_FIRSTAID_TIME_SELF.tostring() )
+ AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_BLEEDOUT", "player_bleedout_firstAidHealPercent", DEFAULT_FIRSTAID_HEAL_PERCENT.tostring() )
+ AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_BLEEDOUT", "player_bleedout_aiBleedingPlayerMissChance", DEFAULT_AI_BLEEDING_PLAYER_MISS_CHANCE.tostring() )
+
+ #if CLIENT
+ // because playlist var overrides fucking suck, they aren't actually updated by this point
+ // client bleedout can be inited late enough that we can just init it on local player spawn
+ AddCallback_LocalClientPlayerSpawned( InitClientBleedoutForLocalPlayer )
+ #elseif SERVER
+ // sh_riff_settings should set this correctly on server
+ if ( !Riff_PlayerBleedout() )
+ return
+
+ AddDamageCallback( "player", HandleDamageForBleedout ) // do this irregardless of whether scripts inited, given it should always be used for bleedout
+ Bleedout_SetCallback_OnPlayerStartBleedout( OnPlayerBleedoutBegin ) // kinda sucks we have to use this callback since game scripts could be using it
+
+ // dont init if scripts already inited it manually
+ if ( !Bleedout_IsBleedoutLogicActive() )
+ {
+ InitSharedBleedoutWithPlaylistVars()
+ Bleedout_Init()
+ }
+ #endif
+}
+
+void function SetShouldPlayerStartBleedoutFunc( bool functionref( entity, var ) func )
+{
+ file.shouldPlayerStartBleedoutFunc = func
+}
+
+void function InitSharedBleedoutWithPlaylistVars()
+{
+ BleedoutShared_Init(
+ GetCurrentPlaylistVarFloat( "player_bleedout_bleedoutTime", DEFAULT_BLEEDOUT_TIME ),
+ GetCurrentPlaylistVarFloat( "player_bleedout_firstAidTime", DEFAULT_FIRSTAID_TIME ),
+ GetCurrentPlaylistVarFloat( "player_bleedout_firstAidTimeSelf", DEFAULT_FIRSTAID_TIME_SELF ),
+ GetCurrentPlaylistVarFloat( "player_bleedout_firstAidHealPercent", DEFAULT_FIRSTAID_HEAL_PERCENT ),
+ GetCurrentPlaylistVarFloat( "player_bleedout_aiBleedingPlayerMissChance", DEFAULT_AI_BLEEDING_PLAYER_MISS_CHANCE ),
+ GetCurrentPlaylistVarInt( "player_bleedout_forceHolster", int( DEFAULT_FORCE_WEAPON_HOLSTER ) ) == 1,
+ GetCurrentPlaylistVarInt( "player_bleedout_forceDeathOnTeamBleedout", int( DEFAULT_DEATH_ON_TEAM_BLEEDOUT ) ) == 1
+ )
+}
+
+#if CLIENT
+void function InitClientBleedoutForLocalPlayer( entity player )
+{
+ // dont init if bleedout is disabled or scripts already inited it
+ if ( !Riff_PlayerBleedout() || Bleedout_IsBleedoutLogicActive() )
+ return
+
+ InitSharedBleedoutWithPlaylistVars()
+ BleedoutClient_Init()
+}
+#endif
+
+#if SERVER
+void function HandleDamageForBleedout( entity player, var damageInfo )
+{
+ if ( IsInstantDeath( damageInfo ) || DamageInfo_GetForceKill( damageInfo ) || player.IsTitan() || file.bleedingPlayers.contains( player ) )
+ return
+
+ if ( file.shouldPlayerStartBleedoutFunc != null )
+ if ( !file.shouldPlayerStartBleedoutFunc( player, damageInfo ) )
+ return
+
+ // check if damage would kill player
+ if ( player.GetHealth() - DamageInfo_GetDamage( damageInfo ) <= 0 )
+ {
+ Bleedout_StartPlayerBleedout( player, DamageInfo_GetAttacker( damageInfo ) )
+ DamageInfo_SetDamage( damageInfo, 1 ) // prevent player from dying, but if we set it to 0, player won't receive any knockback from damage source
+ }
+}
+
+void function OnPlayerBleedoutBegin( entity player )
+{
+ file.bleedingPlayers.append( player )
+
+ // would prefer to use Bleedout_SetCallback_OnPlayerGiveFirstAid for this, but it doesn't expose the player that's receiving first aid for some reason
+ thread TrackPlayerBleedout( player )
+}
+
+void function TrackPlayerBleedout( entity player )
+{
+ player.EndSignal( "OnDeath" )
+ player.EndSignal( "OnDestroy" )
+
+ OnThreadEnd( function() : ( player )
+ {
+ file.bleedingPlayers.remove( file.bleedingPlayers.find( player ) )
+ })
+
+ WaitFrame() // wait a frame, since this gets called before this status effect is added
+
+ while ( StatusEffect_Get( player, eStatusEffect.bleedoutDOF ) != 0 )
+ WaitFrame()
+}
+#endif \ No newline at end of file
diff --git a/Northstar.Custom/mod/scripts/vscripts/_custom_air_accel.gnut b/Northstar.Custom/mod/scripts/vscripts/_custom_air_accel.gnut
index 8ebef0342..faa924804 100644
--- a/Northstar.Custom/mod/scripts/vscripts/_custom_air_accel.gnut
+++ b/Northstar.Custom/mod/scripts/vscripts/_custom_air_accel.gnut
@@ -1,8 +1,10 @@
global function CustomAirAccelVars_Init
void function CustomAirAccelVars_Init()
-{
- AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_PILOT", "custom_air_accel_pilot", "500" ) // 500 is the default airaccel
+{
+ #if MP
+ AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_PILOT", "custom_air_accel_pilot", "500" ) // 500 is the default airaccel
+ #endif
#if SERVER
AddCallback_OnPlayerRespawned( ApplyCustomPlayerAirAccel )
diff --git a/Northstar.Custom/mod/scripts/vscripts/_custom_oob_timer.gnut b/Northstar.Custom/mod/scripts/vscripts/_custom_oob_timer.gnut
new file mode 100644
index 000000000..9689302c1
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/vscripts/_custom_oob_timer.gnut
@@ -0,0 +1,7 @@
+global function CustomOOBTimer_Init
+
+void function CustomOOBTimer_Init()
+{
+ AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_MATCH", "oob_timer_enabled", [ "Disabled", "Enabled" ], "1" )
+ level.disableOutOfBounds <- GetCurrentPlaylistVarInt( "oob_timer_enabled", 1 ) == 0
+} \ No newline at end of file
diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut
index b59cd2dd4..00c193105 100644
--- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut
+++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut
@@ -27,7 +27,6 @@ void function GamemodeFastball_Init()
SetTimeoutWinnerDecisionFunc( FastballDecideWinner )
AddCallback_OnClientConnected( FastballInitPlayer )
- AddCallback_OnPlayerKilled( FastballOnPlayerKilled ) // move this to a system in _gamestate soon!!
// setup spawns
// first is a, second is b, third is c
@@ -164,15 +163,6 @@ function FastballOnPanelHacked( panel, player, success )
}
}
-void function FastballOnPlayerKilled( entity victim, entity attacker, var damageInfo )
-{
- if ( !victim.IsPlayer() || GetGameState() != eGameState.Playing )
- return
-
- if ( GetPlayerArrayOfTeam_Alive( victim.GetTeam() ).len() == 0 )
- SetWinner( GetOtherTeam( victim.GetTeam() ) )
-}
-
int function FastballDecideWinner()
{
int militiaPanels
diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut
index b9ee40f1f..e01780347 100644
--- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut
+++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut
@@ -5,7 +5,7 @@ void function GamemodeGG_Init()
SetSpawnpointGamemodeOverride( FFA )
SetShouldUseRoundWinningKillReplay( true )
- Evac_SetEnabled( false )
+ ClassicMP_ForceDisableEpilogue( true )
SetLoadoutGracePeriodEnabled( false ) // prevent modifying loadouts with grace period
SetWeaponDropsEnabled( false )
Riff_ForceTitanAvailability( eTitanAvailability.Never )
diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hs.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hs.gnut
new file mode 100644
index 000000000..bc65e0b6d
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hs.gnut
@@ -0,0 +1,191 @@
+global function GamemodeHideAndSeek_Init
+
+struct {
+ entity intermissionCam
+ array<entity> droppodSpawns
+
+ float hidingTime
+ bool autobalance
+
+ float hidingStartTime
+} file
+
+void function GamemodeHideAndSeek_Init()
+{
+ SetSpawnpointGamemodeOverride( FFA )
+ Riff_ForceTitanAvailability( eTitanAvailability.Never )
+ Riff_ForceBoostAvailability( eBoostAvailability.Disabled )
+ SetRespawnsEnabled( false )
+ Riff_ForceSetEliminationMode( eEliminationMode.Pilots )
+
+ SetTimeoutWinnerDecisionFunc( HideAndSeekDecideWinner )
+ ClassicMP_SetCustomIntro( GamemodeHideAndSeekIntroSetup, 0.0 )
+
+ AddCallback_OnPlayerRespawned( SetupHideAndSeekPlayer )
+ AddCallback_OnPlayerKilled( TryNotifyLastPlayerAlive )
+ AddSpawnCallback( "info_intermission", SetIntermissionCam )
+ AddSpawnCallback( "info_spawnpoint_droppod_start", AddDroppodSpawn )
+
+ file.hidingTime = GetCurrentPlaylistVarFloat( "hideandseek_hiding_time", 60.0 )
+ file.autobalance = GetCurrentPlaylistVarInt( "hideandseek_balance_teams", 1 ) == 1
+}
+
+void function GamemodeHideAndSeekIntroSetup()
+{
+ AddCallback_GameStateEnter( eGameState.Prematch, HideAndSeekIntroPrematch )
+ AddCallback_OnClientConnected( AddPlayerToHideAndSeekIntro )
+}
+
+void function SetIntermissionCam( entity cam )
+{
+ file.intermissionCam = cam
+}
+
+void function AddDroppodSpawn( entity spawn )
+{
+ file.droppodSpawns.append( spawn )
+}
+
+void function AddPlayerToHideAndSeekIntro( entity player )
+{
+ if ( GetGameState() < eGameState.Prematch || Time() - file.hidingStartTime > file.hidingTime )
+ return
+
+ // seeker/hider autobalance
+ // try to have 1/6 of players be seekers
+ if ( file.autobalance )
+ {
+ int wantedSeekers = int( max( 1, GetPlayerArray().len() / 6 ) )
+
+ if ( GetPlayerArrayOfTeam( HIDEANDSEEK_TEAM_SEEKER ).len() < wantedSeekers )
+ SetTeam( player, HIDEANDSEEK_TEAM_SEEKER )
+ }
+
+ ScreenFadeFromBlack( player, 1.0, 0.75 )
+ Remote_CallFunction_NonReplay( player, "ServerCallback_ShowHideAndSeekCountdown", file.hidingStartTime + file.hidingTime )
+
+ if ( player.GetTeam() == HIDEANDSEEK_TEAM_HIDER )
+ {
+ player.kv.visibilityFlags = ENTITY_VISIBLE_TO_FRIENDLY
+ Highlight_ClearEnemyHighlight( player )
+
+ thread HiderIntroThread( player )
+ }
+ else
+ thread SeekerIntroThread( player )
+
+ thread DelayedRoleAnnounce( player )
+}
+
+void function HideAndSeekIntroPrematch()
+{
+ ClassicMP_OnIntroStarted()
+
+ file.hidingStartTime = Time()
+
+ foreach ( entity player in GetPlayerArray() )
+ AddPlayerToHideAndSeekIntro( player )
+
+ // this intro is mostly done in playing, so just finish the intro up now and we can do fully custom logic from here
+ WaitFrame()
+ ClassicMP_OnIntroFinished()
+
+ thread GlobalSeekerIntroThread()
+}
+
+void function HiderIntroThread( entity player )
+{
+ RespawnAsPilot( player )
+
+ wait ( file.hidingStartTime + file.hidingTime ) - Time()
+
+ player.kv.visibilityFlags = ENTITY_VISIBLE_TO_EVERYONE // make sure everyone can see us again
+}
+
+void function SeekerIntroThread( entity player )
+{
+ MuteHalfTime( player )
+
+ player.SetObserverModeStaticPosition( file.intermissionCam.GetOrigin() )
+ player.SetObserverModeStaticAngles( file.intermissionCam.GetAngles() )
+ player.StartObserverMode( OBS_MODE_STATIC_LOCKED )
+
+ wait ( file.hidingStartTime + file.hidingTime ) - Time()
+ UnMuteAll( player )
+}
+
+void function DelayedRoleAnnounce( entity player )
+{
+ wait 1.75
+ Remote_CallFunction_NonReplay( player, "ServerCallback_AnnounceHideAndSeekRole" )
+}
+
+void function GlobalSeekerIntroThread()
+{
+ wait file.hidingTime
+
+
+ PlayMusicToAll( eMusicPieceID.GAMEMODE_1 )
+ foreach ( entity hider in GetPlayerArrayOfTeam( HIDEANDSEEK_TEAM_HIDER ) )
+ Remote_CallFunction_NonReplay( hider, "ServerCallback_SeekersIncoming" )
+
+ array<entity> seekers = GetPlayerArrayOfTeam( HIDEANDSEEK_TEAM_SEEKER )
+ entity podSpawn = file.droppodSpawns.getrandom()
+ SpawnPlayersInDropPod( seekers, podSpawn.GetOrigin(), podSpawn.GetAngles() )
+
+ foreach ( entity seeker in seekers )
+ if ( IsValid( seeker ) )
+ Highlight_SetEnemyHighlight( seeker, "enemy_sonar" )
+}
+
+void function SetupHideAndSeekPlayer( entity player )
+{
+ foreach ( entity weapon in player.GetMainWeapons() )
+ player.TakeWeapon( weapon.GetWeaponClassName() )
+
+ player.TakeWeapon( player.GetOffhandWeapon( OFFHAND_ORDNANCE ).GetWeaponClassName() )
+
+ player.GiveWeapon( "mp_weapon_rocket_launcher" )
+ player.SetActiveWeaponByName( "mp_weapon_rocket_launcher" )
+
+ Highlight_SetFriendlyHighlight( player, "sp_friendly_pilot" )
+
+ if ( player.GetTeam() == HIDEANDSEEK_TEAM_HIDER )
+ {
+ player.TakeWeapon( player.GetMeleeWeapon().GetWeaponClassName() )
+
+ // set visibility flags if we're hiding, so seekers can't see us on intermission cam
+ if ( Time() - file.hidingStartTime < file.hidingTime )
+ player.kv.visiblityFlags = ENTITY_VISIBLE_TO_FRIENDLY
+
+ // remove red outline, ideally should work tm
+ Highlight_ClearEnemyHighlight( player )
+ }
+ else
+ player.TakeWeapon( "mp_weapon_grenade_sonar" ) // seekers should not have pulse blade
+}
+
+void function TryNotifyLastPlayerAlive( entity victim, entity attacker, var damageInfo )
+{
+ if ( victim.GetTeam() == HIDEANDSEEK_TEAM_HIDER )
+ {
+ array<entity> hiders = GetPlayerArrayOfTeam( HIDEANDSEEK_TEAM_HIDER )
+ if ( hiders.len() == 1 )
+ {
+ PlayMusicToAll( eMusicPieceID.GAMEMODE_2 )
+
+ // let them know they're the last hider
+ Remote_CallFunction_NonReplay( hiders[ 0 ], "ServerCallback_LastHiderAlive" )
+ StimPlayer( hiders[ 0 ], 9999.9 ) // can't do endless since we don't get the visual effect in endless
+
+ // tell seekers
+ foreach ( entity player in GetPlayerArrayOfTeam( HIDEANDSEEK_TEAM_SEEKER ) )
+ Remote_CallFunction_NonReplay( player, "ServerCallback_LastHiderAlive" )
+ }
+ }
+}
+
+int function HideAndSeekDecideWinner()
+{
+ return HIDEANDSEEK_TEAM_HIDER // on timeout, hiders always win
+} \ No newline at end of file
diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut
index 8706d53b1..b2e76aaf8 100644
--- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut
+++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut
@@ -13,6 +13,7 @@ void function GamemodeInfection_Init()
Riff_ForceTitanAvailability( eTitanAvailability.Never )
Riff_ForceBoostAvailability( eBoostAvailability.Disabled )
+ SetShouldPlayerStartBleedoutFunc( InfectionShouldPlayerStartBleedout )
AddCallback_OnClientConnected( InfectionInitPlayer )
AddCallback_OnPlayerKilled( InfectionOnPlayerKilled )
AddCallback_OnPlayerRespawned( RespawnInfected )
@@ -176,4 +177,9 @@ int function TimeoutCheckSurvivors()
return INFECTION_TEAM_SURVIVOR
return INFECTION_TEAM_INFECTED
+}
+
+bool function InfectionShouldPlayerStartBleedout( entity player, var damageInfo )
+{
+ return player.GetTeam() != INFECTION_TEAM_INFECTED
} \ No newline at end of file
diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_kr.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_kr.gnut
index cf9d6bc57..7a226e210 100644
--- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_kr.gnut
+++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_kr.gnut
@@ -13,7 +13,7 @@ void function GamemodeKR_Init()
SetSpawnpointGamemodeOverride( FFA )
- Evac_SetEnabled( false )
+ ClassicMP_ForceDisableEpilogue( true )
Riff_ForceTitanAvailability( eTitanAvailability.Never )
Riff_ForceBoostAvailability( eBoostAvailability.Disabled )
diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/cl_gamemode_hs.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/cl_gamemode_hs.gnut
new file mode 100644
index 000000000..8bfbb10e0
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/cl_gamemode_hs.gnut
@@ -0,0 +1,91 @@
+global function ClGamemodeHideAndSeek_Init
+global function ServerCallback_ShowHideAndSeekCountdown
+global function ServerCallback_AnnounceHideAndSeekRole
+global function ServerCallback_SeekersIncoming
+global function ServerCallback_LastHiderAlive
+
+struct {
+ var countdownRui
+} file
+
+void function ClGamemodeHideAndSeek_Init()
+{
+ ClGameState_RegisterGameStateAsset( $"ui/gamestate_info_lts.rpak" )
+
+ RegisterLevelMusicForTeam( eMusicPieceID.GAMEMODE_1, "music_mp_fd_midwave", HIDEANDSEEK_TEAM_SEEKER )
+ RegisterLevelMusicForTeam( eMusicPieceID.GAMEMODE_1, "music_skyway_01_intro", HIDEANDSEEK_TEAM_HIDER )
+
+ RegisterLevelMusicForTeam( eMusicPieceID.GAMEMODE_2, "music_skyway_04_smartpistolrun", TEAM_IMC )
+ RegisterLevelMusicForTeam( eMusicPieceID.GAMEMODE_2, "music_skyway_04_smartpistolrun", TEAM_MILITIA )
+}
+
+void function ServerCallback_ShowHideAndSeekCountdown( float endTime )
+{
+ file.countdownRui = CreateCockpitRui( $"ui/dropship_intro_countdown.rpak", 0 )
+ RuiSetResolutionToScreenSize( file.countdownRui )
+ RuiSetGameTime( file.countdownRui, "gameStartTime", endTime )
+}
+
+void function ServerCallback_AnnounceHideAndSeekRole()
+{
+ if ( GetLocalViewPlayer().GetTeam() == HIDEANDSEEK_TEAM_SEEKER )
+ {
+ AnnouncementData announcement = Announcement_Create( "#HIDEANDSEEK_YOU_ARE_SEEKER" )
+ Announcement_SetSubText( announcement, Localize( "#HIDEANDSEEK_SEEKER_DESC", GetCurrentPlaylistVarFloat( "hideandseek_hiding_time", 60.0 ).tostring() ) )
+ Announcement_SetTitleColor( announcement, <0,0,1> )
+ Announcement_SetPurge( announcement, true )
+ Announcement_SetPriority( announcement, 200 ) //Be higher priority than Titanfall ready indicator etc
+ Announcement_SetSoundAlias( announcement, SFX_HUD_ANNOUNCE_QUICK )
+ Announcement_SetStyle( announcement, ANNOUNCEMENT_STYLE_QUICK )
+ AnnouncementFromClass( GetLocalViewPlayer(), announcement )
+ }
+ else
+ {
+ AnnouncementData announcement = Announcement_Create( "#HIDEANDSEEK_YOU_ARE_HIDER" )
+ Announcement_SetSubText( announcement, "#HIDEANDSEEK_HIDER_DESC" )
+ Announcement_SetTitleColor( announcement, <0,0,1> )
+ Announcement_SetPurge( announcement, true )
+ Announcement_SetPriority( announcement, 200 ) //Be higher priority than Titanfall ready indicator etc
+ Announcement_SetSoundAlias( announcement, SFX_HUD_ANNOUNCE_QUICK )
+ Announcement_SetStyle( announcement, ANNOUNCEMENT_STYLE_QUICK )
+ AnnouncementFromClass( GetLocalViewPlayer(), announcement )
+ }
+}
+
+void function ServerCallback_SeekersIncoming()
+{
+ AnnouncementData announcement = Announcement_Create( "#HIDEANDSEEK_SEEKERS_INCOMING" )
+ Announcement_SetSubText( announcement, "#HIDEANDSEEK_DONT_GET_FOUND" )
+ Announcement_SetTitleColor( announcement, <1,0,0> )
+ Announcement_SetPurge( announcement, true )
+ Announcement_SetPriority( announcement, 200 ) //Be higher priority than Titanfall ready indicator etc
+ Announcement_SetSoundAlias( announcement, SFX_HUD_ANNOUNCE_QUICK )
+ Announcement_SetStyle( announcement, ANNOUNCEMENT_STYLE_QUICK )
+ AnnouncementFromClass( GetLocalViewPlayer(), announcement )
+}
+
+void function ServerCallback_LastHiderAlive()
+{
+ if ( GetLocalViewPlayer().GetTeam() == HIDEANDSEEK_TEAM_SEEKER )
+ {
+ AnnouncementData announcement = Announcement_Create( Localize( "#HIDEANDSEEK_GET_LAST_HIDER", GetPlayerArrayOfTeam_Alive( HIDEANDSEEK_TEAM_HIDER )[ 0 ].GetPlayerName() ) )
+ Announcement_SetTitleColor( announcement, <1,0,0> )
+ Announcement_SetPurge( announcement, true )
+ Announcement_SetPriority( announcement, 200 ) //Be higher priority than Titanfall ready indicator etc
+ Announcement_SetSoundAlias( announcement, SFX_HUD_ANNOUNCE_QUICK )
+ Announcement_SetStyle( announcement, ANNOUNCEMENT_STYLE_QUICK )
+ AnnouncementFromClass( GetLocalViewPlayer(), announcement )
+ }
+ else
+ {
+ AnnouncementData announcement = Announcement_Create( "#HIDEANDSEEK_YOU_ARE_LAST_HIDER" )
+ Announcement_SetSubText( announcement, "#HIDEANDSEEK_GOT_STIM" )
+ Announcement_SetTitleColor( announcement, <1,0,0> )
+ Announcement_SetPurge( announcement, true )
+ Announcement_SetPriority( announcement, 200 ) //Be higher priority than Titanfall ready indicator etc
+ Announcement_SetSoundAlias( announcement, SFX_HUD_ANNOUNCE_QUICK )
+ Announcement_SetStyle( announcement, ANNOUNCEMENT_STYLE_QUICK )
+ AnnouncementFromClass( GetLocalViewPlayer(), announcement )
+ }
+}
+
diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_hs.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_hs.gnut
new file mode 100644
index 000000000..f4269ac42
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_hs.gnut
@@ -0,0 +1,47 @@
+global function Sh_GamemodeHideAndSeek_Init
+
+global const string GAMEMODE_HIDEANDSEEK = "hs"
+global const int HIDEANDSEEK_TEAM_SEEKER = TEAM_IMC
+global const int HIDEANDSEEK_TEAM_HIDER = TEAM_MILITIA
+
+void function Sh_GamemodeHideAndSeek_Init()
+{
+ // create custom gamemode
+ AddCallback_OnCustomGamemodesInit( CreateGamemodeHideAndSeek )
+ AddCallback_OnRegisteringCustomNetworkVars( HideAndSeekRegisterNetworkVars )
+}
+
+void function CreateGamemodeHideAndSeek()
+{
+ GameMode_Create( GAMEMODE_HIDEANDSEEK )
+ GameMode_SetName( GAMEMODE_HIDEANDSEEK, "#GAMEMODE_hs" )
+ GameMode_SetDesc( GAMEMODE_HIDEANDSEEK, "#PL_hs_desc" )
+ GameMode_SetGameModeAnnouncement( GAMEMODE_HIDEANDSEEK, "ffa_modeDesc" )
+ GameMode_SetColor( GAMEMODE_HIDEANDSEEK, [147, 204, 57, 255] )
+
+ AddPrivateMatchMode( GAMEMODE_HIDEANDSEEK ) // add to private lobby modes
+ AddPrivateMatchModeSettingEnum( "#GAMEMODE_hs", "hideandseek_balance_teams", [ "Disabled", "Enabled" ], "1" )
+ AddPrivateMatchModeSettingArbitrary( "#GAMEMODE_hs", "hideandseek_hiding_time", "60" )
+
+ #if SERVER
+ GameMode_AddServerInit( GAMEMODE_HIDEANDSEEK, GamemodeHideAndSeek_Init )
+ GameMode_SetPilotSpawnpointsRatingFunc( GAMEMODE_HIDEANDSEEK, RateSpawnpoints_Generic )
+ GameMode_SetTitanSpawnpointsRatingFunc( GAMEMODE_HIDEANDSEEK, RateSpawnpoints_Generic )
+ #elseif CLIENT
+ GameMode_AddClientInit( GAMEMODE_HIDEANDSEEK, ClGamemodeHideAndSeek_Init )
+ #endif
+ #if !UI
+ GameMode_SetScoreCompareFunc( GAMEMODE_HIDEANDSEEK, CompareAssaultScore )
+ #endif
+}
+
+void function HideAndSeekRegisterNetworkVars()
+{
+ if ( GAMETYPE != GAMEMODE_HIDEANDSEEK )
+ return
+
+ Remote_RegisterFunction( "ServerCallback_ShowHideAndSeekCountdown" )
+ Remote_RegisterFunction( "ServerCallback_SeekersIncoming" )
+ Remote_RegisterFunction( "ServerCallback_LastHiderAlive" )
+ Remote_RegisterFunction( "ServerCallback_AnnounceHideAndSeekRole" )
+} \ No newline at end of file
diff --git a/Northstar.Custom/mod/scripts/vscripts/mp/levels/mp_bob.nut b/Northstar.Custom/mod/scripts/vscripts/mp/levels/mp_bob.nut
new file mode 100644
index 000000000..afd4fc371
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/vscripts/mp/levels/mp_bob.nut
@@ -0,0 +1,38 @@
+untyped
+global function CodeCallback_MapInit
+
+const float PLATFORM_TRAVEL_TIME = 20.0
+
+struct {
+ array<entity> platformMoverNodes
+ entity platformMover
+} file
+
+void function CodeCallback_MapInit()
+{
+ AddCallback_EntitiesDidLoad( BobMap_EntitiesDidLoad )
+}
+
+void function BobMap_EntitiesDidLoad()
+{
+ BobMap_InitTempProps()
+
+ file.platformMoverNodes = GetEntityLinkChain( GetEntByScriptName( "mp_bob_movingplatform_node_0" ) )
+ file.platformMover = GetEntByScriptName( "mp_bob_movingplatform" )
+ file.platformMover.SetOrigin( file.platformMoverNodes[ 0 ].GetOrigin() )
+
+ entity platformProp = CreatePropDynamic( file.platformMover.GetValueForModelKey(), file.platformMover.GetOrigin(), file.platformMover.GetAngles() )
+ platformProp.SetParent( file.platformMover )
+
+ thread MovingPlatformThink()
+}
+
+void function MovingPlatformThink()
+{
+ int currentNodeIdx = 0
+ while ( true )
+ {
+ file.platformMover.SetOrigin( file.platformMoverNodes[ currentNodeIdx % file.platformMoverNodes.len() ].GetOrigin() )
+ file.platformMover.MoveTo( file.platformMoverNodes[ ++currentNodeIdx % file.platformMoverNodes.len() ].GetOrigin(), PLATFORM_TRAVEL_TIME, 0, 0 )
+ }
+} \ No newline at end of file
diff --git a/Northstar.Custom/mod/scripts/vscripts/mp/levels/mp_bob_temp_props.nut b/Northstar.Custom/mod/scripts/vscripts/mp/levels/mp_bob_temp_props.nut
new file mode 100644
index 000000000..84ffe3e94
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/vscripts/mp/levels/mp_bob_temp_props.nut
@@ -0,0 +1,7 @@
+global function BobMap_InitTempProps
+
+void function BobMap_InitTempProps()
+{
+ PrecacheModel( $"models/vistas/planet_blue_sun.mdl" )
+ CreatePropDynamic( $"models/vistas/planet_blue_sun.mdl", GetEnt( "skybox_cam_level" ).GetOrigin(), GetEnt( "skybox_cam_level" ).GetAngles() )
+} \ No newline at end of file
diff --git a/Northstar.Custom/mod/scripts/vscripts/titan/sh_first_person_embark.gnut b/Northstar.Custom/mod/scripts/vscripts/titan/sh_first_person_embark.gnut
index 0c95ae4cd..0c47c0140 100644
--- a/Northstar.Custom/mod/scripts/vscripts/titan/sh_first_person_embark.gnut
+++ b/Northstar.Custom/mod/scripts/vscripts/titan/sh_first_person_embark.gnut
@@ -1,4 +1,5 @@
global function FirstPersonEmbark_Init
+global function FirstPersonEmbark_InitPlaylistVars
#if CLIENT
global function ServerCallback_HideHudForFPEmbark
@@ -24,6 +25,11 @@ void function FirstPersonEmbark_RegisterCustomNetworkFunctions()
Remote_RegisterFunction( "ServerCallback_HideHudForFPEmbark" )
}
+void function FirstPersonEmbark_InitPlaylistVars()
+{
+ AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_TITAN", "fp_embark_enabled", [ "Disabled", "Enabled" ], "0" )
+}
+
#if CLIENT
void function ServerCallback_HideHudForFPEmbark()
{
diff --git a/Northstar.Custom/mod/scripts/weapons/mp_weapon_peacekraber.txt b/Northstar.Custom/mod/scripts/weapons/mp_weapon_peacekraber.txt
index c5e61f938..59219cab1 100644
--- a/Northstar.Custom/mod/scripts/weapons/mp_weapon_peacekraber.txt
+++ b/Northstar.Custom/mod/scripts/weapons/mp_weapon_peacekraber.txt
@@ -335,13 +335,9 @@ WeaponData
crosshairMovementY weapon_is_reloading
}
- Crosshair_2
+ Crosshair_2
{
"ui" "ui/crosshair_lstar"
"base_spread" "4"
- Args
- {
-
- }
}
} \ No newline at end of file
diff --git a/Northstar.Custom/mod/scripts/weapons/mp_weapon_sniper.txt b/Northstar.Custom/mod/scripts/weapons/mp_weapon_sniper.txt
deleted file mode 100644
index ede43d7de..000000000
--- a/Northstar.Custom/mod/scripts/weapons/mp_weapon_sniper.txt
+++ /dev/null
@@ -1,651 +0,0 @@
-WeaponData
-{
- // General
- "printname" "#WPN_SNIPER"
- "shortprintname" "#WPN_SNIPER_SHORT"
- "description" "#WPN_SNIPER_DESC"
- "longdesc" "#WPN_SNIPER_LONGDESC"
-
- "menu_icon" "r2_ui/menus/loadout_icons/primary_weapon/primary_kraber"
- "hud_icon" "r2_ui/menus/loadout_icons/primary_weapon/primary_kraber"
-
- "weaponClass" "human"
- "weaponSubClass" "sniper"
- "body_type" "heavy"
- "fire_mode" "semi-auto"
- "pickup_hold_prompt" "Hold [USE] [WEAPONNAME]"
- "pickup_press_prompt" "[USE] [WEAPONNAME]"
- "minimap_reveal_distance" "32000"
- "leveled_pickup" "1"
-
- "OnWeaponActivate" "OnWeaponActivate_weapon_sniper"
- "OnClientAnimEvent" "OnClientAnimEvent_weapon_sniper"
- "OnWeaponPrimaryAttack" "OnWeaponPrimaryAttack_weapon_sniper"
- "OnWeaponNpcPrimaryAttack" "OnWeaponNpcPrimaryAttack_weapon_sniper"
- "OnProjectileCollision" "OnProjectileCollision_weapon_sniper"
-
- "viewmodel_offset_ads" "0 0 0"
-
- // Menu
- "menu_category" "sniper"
- "menu_anim_class" "large"
- "stat_damage" "100"
- "stat_range" "100"
- "stat_accuracy" "60"
- "stat_rof" "15"
-
- "ads_dof_disable" "1"
-
- // Models
- "viewmodel" "models/weapons/at_rifle/ptpov_at_rifle.mdl"
- "playermodel" "models/weapons/at_rifle/w_at_rifle.mdl"
- "projectilemodel" "models/weapons/bullets/projectile_20mm.mdl"
-
- // Effects
- "impact_effect_table" "titan_bullet"
- "projectile_trail_effect_0" "weapon_kraber_projectile"
- "projectile_do_predict_impact_effects" "1"//0"
- "vortex_absorb_effect" "wpn_vortex_projectile_20mm_FP"
- "vortex_absorb_effect_third_person" "wpn_vortex_projectile_20mm"
- "vortex_absorb_sound" "Vortex_Shield_AbsorbBulletLarge"
- "vortex_absorb_sound_1p_vs_3p" "Vortex_Shield_AbsorbBulletLarge_1P_VS_3P"
- "projectile_adjust_to_gun_barrel" "1"
-
- // Sounds
- "sound_dryfire" "rifle_dryfire"
- "sound_pickup" "wpn_pickup_Rifle_1P"
- "sound_zoom_in" "Weapon_Rangemaster_Kraber_ADS_In"
- "sound_zoom_out" "Weapon_Rangemaster_Kraber_ADS_Out"
- "fire_sound_1_player_1p" "large_shell_drop"
- "fire_sound_1_player_3p" "large_shell_drop"
- "fire_sound_1_npc" "large_shell_drop"
- "fire_sound_2_player_1p" "Weapon_Kraber_Fire_1P"
- "fire_sound_2_player_3p" "Weapon_Kraber_Fire_3P"
- "fire_sound_2_npc" "Weapon_Kraber_Fire_npc"
-
- "low_ammo_sound_name_1" "Kraber_LowAmmo_Shot1"
- "low_ammo_sound_name_2" "Kraber_LowAmmo_Shot2"
- "low_ammo_sound_name_3" "Kraber_LowAmmo_Shot3"
-
- "fx_shell_eject_view" "wpn_shelleject_rifle_large_FP"
- "fx_shell_eject_world" "wpn_shelleject_rifle_large"
- "fx_shell_eject_attach" "shell"
- "fx_shell_eject_attach_scoped" "shell_scoped"
-
- "fx_muzzle_flash_view" "wpn_muzzleflash_snp_hmn_FP"
- "fx_muzzle_flash_world" "wpn_muzzleflash_snp_hmn"
- "fx_muzzle_flash_attach" "muzzle_flash"
- "fx_muzzle_flash_attach_scoped" "muzzle_flash_scoped"
-
- // Bolt info
- "bolt_hitsize" "0.0"
- "bolt_hitsize_grow1_time" "0.035"
- "bolt_hitsize_grow1_size" "0.5"
- "bolt_hitsize_grow2_time" "0.08"
- "bolt_hitsize_grow2_size" "1.0"
- "bolt_hitsize_growfinal_lerptime" "0.18"
- "bolt_hitsize_growfinal_size" "2.0"
-
- "bolt_gravity_enabled" "1"
- "bolt_gravity_amount" "0.2500"//0.500"
-
- "bolt_bounce_frac" "0.000"
- "projectile_damage_reduction_per_bounce" "0.0"
- "projectile_damages_owner" "0"
- "projectile_ricochet_max_count" "0"
-
- "pass_through_depth" "64"
- "pass_through_damage_preserved_scale" "1"
-
- "bolt_speed" "10000"
-
- // Damage - When Used by Players
- "damage_flags" "DF_BULLET | DF_KNOCK_BACK | DF_DISMEMBERMENT"
- "damage_type" "bullet"
-
- "damage_headshot_scale" "1.5"
-
- "impulse_force" "10"
-
- "ammo_clip_size" "4"
-
- "titanarmor_critical_hit_required" "1"
- "critical_hit" "1"
-
-
- MP_BASE
- {
- "ammo_default_total" "40"
- "ammo_stockpile_max" "40"
- "ammo_no_remove_from_stockpile" "1"
- "ammo_min_to_fire" "1"
-
-
- "damage_near_value" "350"
- "damage_far_value" "350"
- "damage_near_value_titanarmor" "430"
- "damage_far_value_titanarmor" "430"
- "damage_rodeo" "900"
- "damage_near_distance" "2000"
- "damage_far_distance" "15000"
-
- "red_crosshair_range" "15000"
-
- "critical_hit_damage_scale" "1"
-
- // Damage - When Used by NPCs
- "npc_damage_near_value" "49"
- "npc_damage_far_value" "49"
- "npc_damage_near_value_titanarmor" "50"
- "npc_damage_far_value_titanarmor" "25"
-
- "npc_accuracy_multiplier_pilot" "1.0"
-
- "npc_suppress_lsp_allowed" "0"
-
- "enable_highlight_networking_on_creation" "<KEEP_DEFAULT>"
-
- "damage_heavyarmor_nontitan_scale" "0.35"
-
- "zoom_toggle_lerp_time" "<KEEP_DEFAULT>"
- "zoom_toggle_fov" "<KEEP_DEFAULT>"
- }
-
- SP_BASE
- {
- "zoom_toggle_lerp_time" "0.2"
- "zoom_toggle_fov" "7"
-
- "ammo_default_total" "12"
- "ammo_stockpile_max" "28"
- "ammo_no_remove_from_stockpile" "0"
- "ammo_min_to_fire" "1"
-
-
- "damage_near_value" "200"
- "damage_far_value" "200"
- "damage_near_value_titanarmor" "500"
- "damage_far_value_titanarmor" "500"
- "damage_rodeo" "900"
- "damage_near_distance" "2000"
- "damage_far_distance" "15000"
-
- "red_crosshair_range" "15000"
-
- "critical_hit_damage_scale" "1.5"
-
- // Damage - When Used by NPCs
- "npc_damage_near_value" "49"
- "npc_damage_far_value" "49"
- "npc_damage_near_value_titanarmor" "50"
- "npc_damage_far_value_titanarmor" "25"
-
- "npc_accuracy_multiplier_pilot" "3.0"
-
- "npc_suppress_lsp_allowed" "<KEEP_DEFAULT>"
-
- "enable_highlight_networking_on_creation" "1"
-
- "damage_heavyarmor_nontitan_scale" "1"
- }
-
- // NPC
- "proficiency_poor_spreadscale" "3.0"
- "proficiency_average_spreadscale" "2.2"
- "proficiency_good_spreadscale" "2.0"
- "proficiency_very_good_spreadscale" "1.5"
-
- "npc_min_engage_range" "500"
- "npc_max_engage_range" "8000"
- "npc_min_engage_range_heavy_armor" "500"
- "npc_max_engage_range_heavy_armor" "8000"
- "npc_min_range" "0"
- "npc_max_range" "8000"
-
- "npc_min_burst" "1"
- "npc_max_burst" "1"
- "npc_rest_time_between_bursts_min" "2.0"
- "npc_rest_time_between_bursts_max" "3.0"
-
- "dof_zoom_nearDepthStart" "0"
- "dof_zoom_nearDepthEnd" "0"
- "dof_nearDepthStart" "4.750"
- "dof_nearDepthEnd" "9"
-
- // Behavior
- "fire_rate" "1.85"
- "zoom_time_in" "0.4"//0.48"//1.1"//1.25"//0.45"
- "zoom_time_out" "0.3"
- "zoom_fov" "26.26" //3x zoom
- "zoom_scope_frac_start" "0.2"//0.2"
- "zoom_scope_frac_end" "0.7"//0.85"
- "zoom_angle_shift_pitch" "0.3"
- "zoom_angle_shift_yaw" "0.65"
- "rechamber_time" "1.60"//1.30"
- "reload_time" "2.5"
- "reload_time_late1" "1.52"
- "reload_time_late2" "0.63"
- "reloadempty_time" "3.61"
- "reloadempty_time_late1" "2.63"
- "reloadempty_time_late2" "1.75"
- "reloadempty_time_late3" "0.55"
- "holster_time" "0.5"
- "deploy_time" "0.8"
- "lower_time" "0.25"
- "raise_time" "0.3"
- "vortex_refire_behavior" "bullet"
- "allow_empty_fire" "0"
- "reload_enabled" "1"
- "allow_empty_click" "1"
- "empty_reload_only" "0"
- "trigger_snipercam" "1"
- "allow_headshots" "1"
- "ads_move_speed_scale" "0.5"//0.35"
- "aimassist_disable_hipfire" "1"
- "aimassist_disable_ads" "1"
- "aimassist_disable_hipfire_titansonly" "1"
- "aimassist_disable_ads_titansonly" "1"
- "gamepad_use_yaw_speed_for_pitch_ads" "1"
- "ads_fov_zoomfrac_start" "0.5"
- "ads_fov_zoomfrac_end" "0.9"
-
- "sprint_fractional_anims" "0"
-
- // Spread
- "spread_stand_hip" "10"
- "spread_stand_hip_run" "12"
- "spread_stand_ads" "0.0" //"0.1"
- "spread_crouch_hip" "8"
- "spread_crouch_ads" "0"
- "spread_air_hip" "12"
- "spread_air_ads" "0.0" //".15"
-
- "ammo_suck_behavior" "primary_weapons"
-
- // View Kick
- "viewkick_spring" "sniper"
-
- "viewkick_pitch_base" "-0.5625"//"-1.25"//
- "viewkick_pitch_random" "0.0225"//"0.05"//
- "viewkick_pitch_softScale" "0.8"
- "viewkick_pitch_hardScale" "2"
-
- "viewkick_yaw_base" "-0.135"//"-0.3"//
- "viewkick_yaw_random" "0.045"//"0.1"//
- "viewkick_yaw_softScale" "1.0"
- "viewkick_yaw_hardScale" "1.5"
-
- "viewkick_roll_base" "0"
- "viewkick_roll_randomMin" "0.5"
- "viewkick_roll_randomMax" "0.5"
- "viewkick_roll_softScale" "0.2"
- "viewkick_roll_hardScale" "3.0"
-
- "viewkick_hipfire_weaponFraction" "0.4"
- "viewkick_hipfire_weaponFraction_vmScale" "0.55"
- "viewkick_ads_weaponFraction" "0.0"//"0.45"//
- "viewkick_ads_weaponFraction_vmScale" "0.0"//"-0.3"//
-
- "viewkick_perm_pitch_base" "0.0"
- "viewkick_perm_pitch_random" "0.0"
- "viewkick_perm_pitch_random_innerexclude" "0.0"
- "viewkick_perm_yaw_base" "0.0"
- "viewkick_perm_yaw_random" "0.0"
- "viewkick_perm_yaw_random_innerexclude" "0.0"
-
- //
- "viewmodel_shake_forward" "0.5"
- "viewmodel_shake_up" "0.1"
- "viewmodel_shake_right" "0.0"
-
- // Bob
- "bob_cycle_time" "0.4"
- "bob_vert_dist" "0.19"
- "bob_horz_dist" "0.1"
- "bob_max_speed" "150"
- "bob_pitch" "0.75"
- "bob_yaw" "-1.7"
- "bob_roll" "1.2"
-
- // Bob_Zoomed
- "bob_cycle_time_zoomed" "0.4"
- "bob_vert_dist_zoomed" "0.0025"
- "bob_horz_dist_zoomed" "0.0025"
- "bob_max_speed_zoomed" "150"
- //"bob_pitch_zoomed" "0.002"
- //"bob_yaw_zoomed" "-.002"
- //"bob_roll_zoomed" ".002"
-
- // Rumble
- "fire_rumble" "rumble_sniper"
-
- // Sway
- "sway_rotate_attach" "SWAY_ROTATE"
- "sway_min_x" "-0.5"
- "sway_min_y" "-0.5"
- "sway_min_z" "-0.6"
- "sway_max_x" "0.5"
- "sway_max_y" "0.5"
- "sway_max_z" "0.6"
- "sway_min_pitch" "-3"
- "sway_min_yaw" "-2.5"
- "sway_min_roll" "-4"
- "sway_max_pitch" "3"
- "sway_max_yaw" "2.5"
- "sway_max_roll" "4"
- "sway_translate_gain" "2.5"
- "sway_rotate_gain" "7"
- "sway_move_forward_translate_x" "-0.1"
- "sway_move_forward_translate_z" "-0.5"
- "sway_move_back_translate_x" "0.2"
- "sway_move_back_translate_z" "-0.2"
- "sway_move_left_translate_y" "-1"
- "sway_move_left_translate_z" "-0.5"
- "sway_move_left_rotate_roll" "-4"
- "sway_move_right_translate_y" "1"
- "sway_move_right_translate_z" "-0.5"
- "sway_move_right_rotate_roll" "4"
- "sway_move_up_translate_z" "-1"
- "sway_move_down_translate_z" "1"
- "sway_turn_left_rotate_yaw" "-2.5"
- "sway_turn_right_rotate_yaw" "2.5"
-
- "sway_turn_left_translate_y" ".5"
- "sway_turn_right_translate_y" "-.5"
- "sway_turn_up_translate_z" ".2"
- "sway_turn_down_translate_z" "-.2"
- "sway_turn_up_translate_x" ".1"
- "sway_turn_down_translate_x" "-.1"
-
- "sway_turn_left_rotate_roll" "4"
- "sway_turn_right_rotate_roll" "-4"
- "sway_turn_up_rotate_pitch" "3"
- "sway_turn_down_rotate_pitch" "-3"
- "sway_turn_up_rotate_roll" "-0.8"
- "sway_turn_down_rotate_roll" "0.8"
-
- // Zoomed Sway
- "sway_rotate_attach_zoomed" "jx_c_pov"
- "sway_rotate_attach_blend_time_zoomed" "0.2"
- "sway_rotate_gain_zoomed" "5"
-
- "sway_min_yaw_zoomed" "-0.085"
- "sway_max_yaw_zoomed" "0.085"
- "sway_turn_left_rotate_yaw_zoomed" "0.085"
- "sway_turn_right_rotate_yaw_zoomed" "-0.085"
-
- "sway_min_roll_zoomed" "-1"
- "sway_max_roll_zoomed" "1"
- "sway_turn_left_rotate_roll_zoomed" "-1"
- "sway_turn_right_rotate_roll_zoomed" "1"
-
- "sway_move_right_rotate_roll_zoomed" "0.2"
- "sway_move_left_rotate_roll_zoomed" "-0.2"
-
- "sway_min_pitch_zoomed" "-0.25"
- "sway_max_pitch_zoomed" "0.25"
- "sway_turn_up_rotate_pitch_zoomed" "-0.25"
- "sway_turn_down_rotate_pitch_zoomed" "0.25"
-
- // WeaponED Unhandled Key/Values and custom script Key/Values
- "sprintcycle_time" ".55"
- "is_sniper" "1"
-
- // Bodygroups:
- "bodygroup1_name" "scope_dcom"
- "bodygroup1_set" "1"
- "bodygroup2_name" "scope_zoom"
- "bodygroup2_set" "0"
- "bodygroup3_name" "ammo"
- "bodygroup3_set" "1"
- "bodygroup4_name" "scope_outline"
- "bodygroup4_set" "0"
- "bodygroup5_name" "scope_oracle"
- "bodygroup5_set" "0"
- "bodygroup6_name" "proscreen"
- "bodygroup6_set" "0"
- // "bodygroup7_name" "suppressor_sq_lg"
- // "bodygroup7_set" "0"
-
- "bodygroup_ads_scope_name" "ads_scopes"
- "bodygroup_ads_scope_set" "3"
-
-
- "anim_alt_idleAttack" "0"
-
- "clip_bodygroup" "at_rifle_magazine"
- "clip_bodygroup_index_shown" "0"
- "clip_bodygroup_index_hidden" "1"
- "clip_bodygroup_show_for_milestone_0" "1"
- "clip_bodygroup_show_for_milestone_1" "0"
- "clip_bodygroup_show_for_milestone_2" "1"
- "clip_bodygroup_show_for_milestone_3" "1"
-
- "bodygroup_ammo_index_count" "6"
-
- Mods
- {
- iron_sights
- {
-
- }
- scope_4x
- {
- //Use this for Variable Zoom
- "ui7_enable" "1"
-
- "bodygroup1_set" "0"
- "bodygroup2_set" "0"
- "bodygroup4_set" "1"
- "bodygroup5_set" "0"
- "bodygroup_ads_scope_set" "2"
- "zoom_toggle_lerp_time" "0.2"
- "zoom_toggle_fov" "7"
- //"ui6_enable" "1"
- }
- extended_ammo
- {
- "ammo_stockpile_max" "90"
- "ammo_clip_size" "7"
- "ammo_default_total" "90"
- }
- stabilizer
- {
- "bodygroup1_set" "0"
- "bodygroup2_set" "0"
- "bodygroup4_set" "0"
- "bodygroup5_set" "1"
- "bodygroup_ads_scope_set" "0"
-
- // "viewdrift_ads_stand_scale_pitch" "*0.5"
- // "viewdrift_ads_crouch_scale_pitch" "*0.5"
- // "viewdrift_ads_air_scale_pitch" "*0.5"
- // "viewdrift_ads_air_scale_yaw" "*0.5"
- // "viewdrift_ads_stand_scale_yaw" "*0.5"
- // "viewdrift_ads_crouch_scale_yaw" "*0.5"
- // "viewdrift_ads_speed_pitch" "*0.5"
- // "viewdrift_ads_speed_yaw" "*0.5"
-
- "viewmodel_offset_ads" "0 -2.95 0.31"
- //"viewmodel_offset_lerp_endFrac" "1"
-
- "ads_fov_zoomfrac_start" "0.3"
- "ads_fov_zoomfrac_end" "0.8"
-
- "dof_zoom_nearDepthStart" "7.0"
- "dof_zoom_nearDepthEnd" "7.2"
-
- "anim_alt_idleAttack" "1"
- }
- ricochet
- {
- "bolt_bounce_frac" "0.7"
- "projectile_damage_reduction_per_bounce" "0.0"
- "projectile_damages_owner" "0"
- "projectile_ricochet_max_count" "2"
- }
- slammer
- {
- }
- threat_scope
- {
- "bodygroup1_set" "0"
- "bodygroup2_set" "1"
- "bodygroup4_set" "0"
- "bodygroup5_set" "0"
- "bodygroup_ads_scope_set" "1"
-
- "threat_scope_enabled" "1"
- "threat_scope_bounds_width" "1.5"
- "threat_scope_bounds_height" "1.1"
- "threat_scope_zoomfrac_start" "0.85"
- "viewmodel_offset_ads" "0 0.5 0"
- dof_zoom_focusArea_horizontal 0.068
- dof_zoom_focusArea_top 0.065
- dof_zoom_focusArea_bottom -0.046
- }
- pro_screen
- {
- "ui8_enable" "1"
- "bodygroup6_set" "1"
- }
- tactical_cdr_on_kill
- {
-
- }
- pas_fast_reload
- {
- "reload_time" "*0.7"
- "reload_time_late1" "*0.7"
- "reloadempty_time" "*0.7"
- "reloadempty_time_late1" "*0.7"
- }
- pas_fast_ads
- {
- //Fast ADS
- "zoom_time_in" "*0.5"
- "zoom_time_out" "*0.6"
- }
- pas_fast_swap
- {
- //Fast Swap
- "fast_swap_to" "1"
- }
- burn_mod_sniper
- {
- "is_burn_mod" "1"
- //FX
- "fx_muzzle_flash_view" "wpn_muzzleflash_snp_hmn_FP_burn"
- "fx_muzzle_flash_world" "wpn_muzzleflash_snp_hmn_burn"
- "projectile_trail_effect_0" "weapon_kraber_projectile_burn"
- //"impact_effect_table" "titan_bullet_elec"
-
- "damage_near_value" "450"
- "damage_far_value" "450"
- "damage_near_value_titanarmor" "580"
- "damage_far_value_titanarmor" "580"
-
- // reimplement tf1 amped kraber
- "explosion_damage" "150"
- "explosion_damage_heavy_armor" "150"
- "explosion_inner_radius" "25"
- "explosionradius" "75"
- "explosion_shake_radius" "250"
- "explosion_shake_amplitude" "10"
- "explosion_shake_frequency" "50"
- "explosion_shake_duration" "0.6"
- "impact_effect_table" "exp_small"
- }
- pve_elite
- {
- //"ammo_stockpile_max" "90"
- //"ammo_clip_size" "7"
- //"ammo_default_total" "90"
- //"reload_time" "0.1"
- //"fire_rate" "0.1"
- "npc_damage_near_value" "70"
- "npc_damage_far_value" "70"
- }
- }
-
- "ui1_enable" "1"
- UiData1
- {
- "ui" "ui/kraber_ammo_counter"
- "mesh" "models/weapons/attachments/kraber_rui_lower"
- Args
- {
- vis player_zoomfrac
- ammo weapon_ammo
- clipSize weapon_clipSize
- }
- }
-
- "ui6_enable" "0"
- UiData6
- {
- "ui" "ui/red_dot_basic"
- "mesh" "models/weapons/attachments/sniper_scope_rui_upper"
- Args
- {
- vis player_zoomfrac
- ammo weapon_ammo
- clipSize weapon_clipSize
- clipCount weapon_stockpileClipCount
- }
- }
-
- "ui7_enable" "0"
- UiData7
- {
- "ui" "ui/variable_zoom_crosshair"
- "mesh" "models/weapons/attachments/attach_scope_ads_2_crosshair"
- Args
- {
- vis player_zoomfrac
- ammo weapon_ammo
- clipSize weapon_clipSize
- clipCount weapon_stockpileClipCount
- }
- }
-
- "ui8_enable" "0"
- UiData8
- {
- "ui" "ui/pro_screen_panel"
- "mesh" "models/weapons/attachments/pro_screen_rui_upper"
- Args
- {
- proValue proscreen_int0
- proOwnedByPlayer proscreen_owner_is_player
- }
- }
-
- active_crosshair_count "1"
- rui_crosshair_index "0"
-
- RUI_CrosshairData
- {
- DefaultArgs
- {
- adjustedSpread weapon_spread
- adsFrac player_zoomFrac
- isSprinting player_is_sprinting
- isReloading weapon_is_reloading
- teamColor crosshair_team_color
- isAmped weapon_is_amped
- crosshairMovementX crosshair_movement_x
- crosshairMovementY crosshair_movement_y
- }
-
- Crosshair_1
- {
- "ui" "ui/crosshair_sniper_amped"
- "base_spread" "10"
- Args
- {
- isFiring weapon_is_firing
- }
- }
- }
-}
diff --git a/Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpk b/Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpk
index 1b8ef3968..35313d15c 100644
--- a/Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpk
+++ b/Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpk
Binary files differ
diff --git a/Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpk b/Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpk
index 4d71f9778..2d5cd687f 100644
--- a/Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpk
+++ b/Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpk
Binary files differ
diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json
index 547a1b8c4..ac826d1a2 100644
--- a/Northstar.CustomServers/mod.json
+++ b/Northstar.CustomServers/mod.json
@@ -10,6 +10,16 @@
{
"Name": "ns_should_return_to_lobby",
"DefaultValue": "1"
+ },
+
+ {
+ "Name": "ns_private_match_last_mode",
+ "DefaultValue": "aitdm"
+ },
+
+ {
+ "Name": "ns_private_match_last_map",
+ "DefaultValue": "mp_forwardbase_kodai"
}
],
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut
index 2b7b90b3b..58d38ce7f 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut
@@ -221,14 +221,12 @@ bool function ClientCommandCallback_SetFactionChoicePersistenceSlot( entity play
bool function ClientCommandCallback_LoadoutMenuClosed( entity player, array<string> args )
{
- SavePdataForEntityIndex( player.GetPlayerIndex() )
TryGivePilotLoadoutForGracePeriod( player )
return true
}
bool function ClientCommandCallback_InGameMPMenuClosed( entity player, array<string> args )
{
- SavePdataForEntityIndex( player.GetPlayerIndex() )
//TryGivePilotLoadoutForGracePeriod( player )
return true
}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut
index c116ac33b..d0820dd6a 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut
@@ -7,11 +7,18 @@ void function MenuCallbacks_Init()
bool function ClientCommandCallback_LeaveMatch( entity player, array<string> args )
{
- // todo: ideally, it'd be nice to get clients to return to lobby here, rather than just dcing them
- // kind of a pain tho, since we'd have to get it to call script code without a remote func, since that'd break compatibility
+ thread WritePersistenceAndLeave( player )
+ return true
+}
- ClientCommand( player, "disconnect" )
- //ClientCommand( player, "setplaylist tdm; map mp_lobby" )
+void function WritePersistenceAndLeave( entity player )
+{
+ // write player persistence before we leave, since leaving player might load local lobby before server writes persistence, so they won't get newest
+ // not super essential, but a nice qol thing
+ NSEarlyWritePlayerPersistenceForLeave( player )
+ while ( NSIsWritingPlayerPersistence() )
+ WaitFrame()
- return true
+ // this is a custom concommand which can be called on clients, it causes them to leave and doesn't have issues if they're host
+ ClientCommand( player, "ns_leave_to_lobby" )
} \ 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 ba473cae9..c0242cc19 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
@@ -1,315 +1,360 @@
untyped
-
global function Evac_Init
-global function Evac_AddLocation
-global function Evac_SetSpacePosition
-global function Evac_SetEnabled
-global function Evac_IsEnabled
+global function AddEvacNode
+global function SetEvacSpaceNode
global function IsEvacDropship
-global function EvacMain
+global function EvacEpilogueSetup
+global function Evac
+
+const float EVAC_INITIAL_WAIT = 5.0
const float EVAC_ARRIVAL_TIME = 40.0
const float EVAC_WAIT_TIME = 18.0
-struct {
- bool enabled = true
+// we don't use these because they're busted, just keeping them
+const array<string> EVAC_EMBARK_ANIMS_1P = [
+ "ptpov_e3_rescue_side_embark_A",
+ "ptpov_e3_rescue_side_embark_B",
+ "ptpov_e3_rescue_side_embark_C",
+ "ptpov_e3_rescue_side_embark_D",
+ "ptpov_e3_rescue_side_embark_E",
+ "ptpov_e3_rescue_side_embark_F",
+ "ptpov_e3_rescue_side_embark_G",
+ "ptpov_e3_rescue_side_embark_H"
+]
+
+const array<string> EVAC_EMBARK_ANIMS_3P = [
+ "pt_e3_rescue_side_embark_A",
+ "pt_e3_rescue_side_embark_B",
+ "pt_e3_rescue_side_embark_C",
+ "pt_e3_rescue_side_embark_D",
+ "pt_e3_rescue_side_embark_E",
+ "pt_e3_rescue_side_embark_F",
+ "pt_e3_rescue_side_embark_G",
+ "pt_e3_rescue_side_embark_H"
+]
- array<Point> evacPoints
- Point spacePosition
+const array<string> EVAC_IDLE_ANIMS_1P = [
+ "ptpov_e3_rescue_side_embark_A_idle",
+ "ptpov_e3_rescue_side_embark_B_idle",
+ "ptpov_e3_rescue_side_embark_C_idle",
+ "ptpov_e3_rescue_side_embark_D_idle",
+ "ptpov_e3_rescue_side_embark_E_idle",
+ "ptpov_e3_rescue_side_embark_F_idle",
+ "ptpov_e3_rescue_side_embark_G_idle",
+ "ptpov_e3_rescue_side_embark_H_idle"
+]
+
+const array<string> EVAC_IDLE_ANIMS_3P = [
+ "pt_e3_rescue_side_idle_A",
+ "pt_e3_rescue_side_idle_B",
+ "pt_e3_rescue_side_idle_C",
+ "pt_e3_rescue_side_idle_D",
+ "pt_e3_rescue_side_idle_E",
+ "pt_e3_rescue_side_idle_F",
+ "pt_e3_rescue_side_idle_G",
+ "pt_e3_rescue_side_idle_H"
+]
+
+struct {
+ array<entity> evacNodes
+ entity spaceNode
entity evacDropship
- array<entity> evacPlayers
+ entity evacIcon
} file
void function Evac_Init()
{
EvacShared_Init()
-
- AddCallback_GameStateEnter( eGameState.Epilogue, Evac_OnEpilogue )
}
-void function Evac_SetEnabled( bool enabled )
+void function AddEvacNode( entity evacNode )
{
- file.enabled = enabled
+ file.evacNodes.append( evacNode )
}
-bool function Evac_IsEnabled()
+void function SetEvacSpaceNode( entity spaceNode )
{
- return false // shit is busted rn lol
- //return file.enabled && GetClassicMPMode() && !IsRoundBased()
+ file.spaceNode = spaceNode
}
-void function Evac_AddLocation( vector origin, vector angles )
+bool function IsEvacDropship( entity ent )
{
- Point evacPoint
- evacPoint.origin = origin
- evacPoint.angles = angles
-
- file.evacPoints.append( evacPoint )
+ return file.evacDropship == ent && IsValid( file.evacDropship )
}
-void function Evac_SetSpacePosition( vector origin, vector angles )
+// evac epilogue
+void function EvacEpilogueSetup()
{
- file.spacePosition.origin = origin
- file.spacePosition.angles = angles
+ AddCallback_GameStateEnter( eGameState.Epilogue, EvacEpilogue )
}
-bool function IsEvacDropship( entity ent )
+void function EvacEpilogue()
{
- return file.evacDropship == ent && IsValid( file.evacDropship )
+ thread Evac( GetPlayerArray()[0].GetTeam(), EVAC_INITIAL_WAIT, EVAC_ARRIVAL_TIME, EVAC_WAIT_TIME, EvacEpiloguePlayerCanBoard, EvacEpilogueShouldLeaveEarly, EvacEpilogueCompleted )
}
-void function Evac_OnEpilogue()
+bool function EvacEpiloguePlayerCanBoard( entity dropship, entity player )
{
- if ( Evac_IsEnabled() )
- thread EvacMain( GetOtherTeam( GameScore_GetWinningTeam() ) )
+ // can't board a dropship on a different team
+ if ( dropship.GetTeam() != player.GetTeam() )
+ return false
+
+ // check if there are any free slots on the dropship, if there are then they can board
+ foreach ( entity player in dropship.s.evacSlots )
+ if ( !IsValid( player ) )
+ return true
+
+ // no empty slots
+ return false
}
-void function EvacMain( int winningTeam )
+bool function EvacEpilogueShouldLeaveEarly( entity dropship )
{
- if ( file.evacPoints.len() == 0 )
+ int numEvacing
+ foreach ( entity player in dropship.s.evacSlots )
+ if ( IsValid( player ) )
+ numEvacing++
+
+ return GetPlayerArrayOfTeam( dropship.GetTeam() ).len() == numEvacing || numEvacing == dropship.s.evacSlots.len()
+}
+
+void function EvacEpilogueCompleted( entity dropship )
+{
+ wait 5.0
+ print( dropship )
+
+ foreach ( entity player in dropship.s.evacSlots )
{
- // automatically add evac locations if they aren't registered yet
- int i = 1
- entity current = null
- while ( true )
- {
- current = GetEnt( "escape_node" + i )
- print( current )
-
- if ( current != null )
- Evac_AddLocation( current.GetOrigin(), current.GetAngles() )
- else
- break
-
- i++
- }
+ if ( !IsValid( player ) )
+ continue
- if ( file.evacPoints.len() == 0 )
- unreachable
+ ScreenFadeToBlackForever( player, 2.0 )
}
- if ( file.spacePosition.origin == < 0, 0, 0 > )
+ wait 2.0
+
+ 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 )
+{
+ wait initialWait
+
+ // setup evac nodes if not manually registered
+ if ( file.evacNodes.len() == 0 )
{
- // automatically add a space node if not registered yet
- entity defaultSpaceNode = GetEnt( "spaceNode" )
- if ( defaultSpaceNode == null )
- unreachable
-
- Evac_SetSpacePosition( defaultSpaceNode.GetOrigin(), defaultSpaceNode.GetAngles() )
+ for ( int i = 1; ; i++ )
+ {
+ entity newNode = GetEnt( "escape_node" + i )
+ if ( !IsValid( newNode ) )
+ break
+
+ file.evacNodes.append( newNode )
+ }
}
- Point evacPoint = file.evacPoints[ RandomInt( file.evacPoints.len() ) ]
+ // setup space node if not manually registered
+ if ( !IsValid( file.spaceNode ) )
+ file.spaceNode = GetEnt( "spaceNode" )
+
+ entity evacNode = file.evacNodes.getrandom()
+
+ // setup client evac position
+ file.evacIcon = CreateEntity( "info_target" )
+ file.evacIcon.SetOrigin( evacNode.GetOrigin() )
+ file.evacIcon.kv.spawnFlags = SF_INFOTARGET_ALWAYS_TRANSMIT_TO_CLIENT
+ DispatchSpawn( file.evacIcon )
+ file.evacIcon.DisableHibernation()
+
+ 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 )
+ SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtract", Time() + arrivalTime, file.evacIcon )
- // create an entity for the evac point that clients will get
- entity evacPointEntity = CreateEntity( MARKER_ENT_CLASSNAME )
- evacPointEntity.SetOrigin( evacPoint.origin )
- evacPointEntity.kv.spawnflags = SF_INFOTARGET_ALWAYS_TRANSMIT_TO_CLIENT
- DispatchSpawn( evacPointEntity )
- evacPointEntity.DisableHibernation()
-
- // set objectives
- //SetTeamActiveObjective( winningTeam, "EG_DropshipExtract", Time() + EVAC_ARRIVAL_TIME, evacPointEntity )
- //SetTeamActiveObjective( GetOtherTeam( winningTeam ), "EG_StopExtract", Time() + EVAC_ARRIVAL_TIME, evacPointEntity )
-
- // wanted to do this with an actual dropship to calculate embarkStartDelay but spawning it before it should exist ingame is weird
- // could probably do it with a dummy entity but effort
- wait EVAC_ARRIVAL_TIME - 4.33333//embarkStartDelay
-
- // create dropship
- entity dropship = CreateDropship( winningTeam, evacPoint.origin, evacPoint.angles )
- file.evacDropship = dropship
+ // would've liked to use cd_dropship_rescue_side_start length here, but can't since this is done before dropship spawn, can't
+ 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" )
DispatchSpawn( dropship )
- dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) // gotta do this after dispatch for some reason
- vector startPos = dropship.Anim_GetStartForRefEntity( "cd_dropship_rescue_side_start", evacPointEntity, "origin" ).origin
- dropship.SetOrigin( startPos ) // set origin so the dropship isn't in the map
+ dropship.s.evacSlots <- [ null, null, null, null, null, null, null, null ]
+
dropship.EndSignal( "OnDestroy" )
+ OnThreadEnd( function() : ( evacTeam, completionCallback, dropship )
+ {
+ if ( "evacTrigger" in dropship.s )
+ dropship.s.evacTrigger.Destroy()
+
+ // this should be for both teams
+ SetTeamActiveObjective( evacTeam, "EG_DropshipExtractDropshipDestroyed" )
+ SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_DropshipExtractDropshipDestroyed" )
- // calculate time until idle
+ foreach ( entity player in dropship.s.evacSlots )
+ {
+ if ( !IsValid( player ) )
+ continue
+
+ player.ClearInvulnerable()
+ }
+
+ // this is called whether dropship is destroyed or evac finishes, callback can handle this itself
+ thread completionCallback( dropship )
+ })
+
+ // flyin
+ thread PlayAnim( dropship, "cd_dropship_rescue_side_start", evacNode )
+
+ // calculate time until idle start
float sequenceDuration = dropship.GetSequenceDuration( "cd_dropship_rescue_side_start" )
float cycleFrac = dropship.GetScriptedAnimEventCycleFrac( "cd_dropship_rescue_side_start", "ReadyToLoad" )
- float embarkStartDelay = sequenceDuration * cycleFrac
+ wait sequenceDuration * cycleFrac
+
+ thread PlayAnim( dropship, "cd_dropship_rescue_side_idle", evacNode )
+
+ // eta until leave
+ SetTeamActiveObjective( evacTeam, "EG_DropshipExtract2", Time() + EVAC_WAIT_TIME, file.evacIcon )
+ SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtract2", Time() + EVAC_WAIT_TIME, file.evacIcon )
+
+ // setup evac trigger
+ entity trigger = CreateEntity( "trigger_cylinder" )
+ trigger.SetRadius( 150 )
+ trigger.SetAboveHeight( 100 )
+ trigger.SetBelowHeight( 100 )
+ trigger.SetOrigin( dropship.GetOrigin() )
+ trigger.SetParent( dropship, "ORIGIN" )
+ DispatchSpawn( trigger )
+ // have to do this inline since we capture the completionCallback
+ trigger.SetEnterCallback( void function( entity trigger, entity player ) : ( canBoardCallback, dropship )
+ {
+ if ( !player.IsPlayer() || !IsAlive( player ) || !canBoardCallback( dropship, player ) || PlayerInDropship( player, dropship ) )
+ return
- // play anim
- thread PlayAnim( dropship, "cd_dropship_rescue_side_start", evacPointEntity )
- wait embarkStartDelay
-
- print( "evac flyin done! ready to load players" )
+ thread AddPlayerToEvacDropship( dropship, player )
+ })
- // set objectives again
- SetTeamActiveObjective( winningTeam, "EG_DropshipExtract2", Time() + EVAC_WAIT_TIME, evacPointEntity )
- SetTeamActiveObjective( GetOtherTeam( winningTeam ), "EG_StopExtract2", Time() + EVAC_WAIT_TIME, evacPointEntity )
-
- thread EvacShipThink( dropship ) // let people enter it
+ dropship.s.evacTrigger <- trigger
+
+ float waitStartTime = Time()
+ while ( Time() - waitStartTime < waitTime )
+ {
+ if ( shouldLeaveEarlyCallback( dropship ) )
+ break
+
+ WaitFrame()
+ }
- wait EVAC_WAIT_TIME
+ // holster all weapons
+ foreach ( entity player in dropship.s.evacSlots )
+ if ( IsValid( player ) )
+ player.HolsterWeapon()
// fly away
- thread PlayAnim( dropship, "cd_dropship_rescue_side_end", evacPointEntity )
+ thread PlayAnim( dropship, "cd_dropship_rescue_side_end", evacNode )
+
+ SetTeamActiveObjective( evacTeam, "EG_DropshipExtractDropshipFlyingAway" )
+ SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtractDropshipFlyingAway" )
- // set objectives again
- SetTeamActiveObjective( winningTeam, "EG_DropshipExtractDropshipFlyingAway" )
- SetTeamActiveObjective( GetOtherTeam( winningTeam ), "EG_StopExtractDropshipFlyingAway" )
+ // todo: play the warpout effect somewhere here
wait dropship.GetSequenceDuration( "cd_dropship_rescue_side_end" ) - WARPINFXTIME
- foreach ( entity player in file.evacPlayers )
- {
- Remote_CallFunction_Replay( player, "ServerCallback_PlayScreenFXWarpJump" )
- }
+ foreach ( entity player in dropship.s.evacSlots )
+ if ( IsValid( player ) )
+ Remote_CallFunction_NonReplay( player, "ServerCallback_PlayScreenFXWarpJump" )
- // todo screen effects and shit
- //WaittillAnimDone( dropship )
wait WARPINFXTIME
- // space
- dropship.SetOrigin( file.spacePosition.origin )
- dropship.SetAngles( file.spacePosition.angles )
- thread PlayAnim( dropship, "ds_space_flyby_dropshipA" )
-
- // display player [Evacuated] in killfeed
- foreach ( entity player in GetPlayerArray() )
- {
- foreach ( entity evacPlayer in file.evacPlayers )
- Remote_CallFunction_NonReplay( player, "ServerCallback_EvacObit", evacPlayer.GetEncodedEHandle() )
- }
-
- foreach ( entity player in file.evacPlayers )
- {
- // set skybox to space for all evac players
+ // go to space
+ // hardcoded angles here are a hack, spacenode position doesn't face the planet in the skybox, for some reason
+ file.spaceNode.SetAngles( < 30, -75, 20 >)
+ dropship.SetOrigin( file.spaceNode.GetOrigin() )
+ dropship.SetAngles( file.spaceNode.GetAngles() )
+ dropship.SetInvulnerable()
+ thread PlayAnim( dropship, "ds_space_flyby_dropshipA", file.spaceNode )
+
+ foreach( entity player in GetPlayerArray() )
+ {
+ // evac-ed players only beyond this point
+ if ( !PlayerInDropship( player, dropship ) )
+ {
+ if ( player.GetTeam() == dropship.GetTeam() )
+ SetPlayerActiveObjective( player, "EG_DropshipExtractFailedEscape" )
+
+ return
+ }
+
+ SetPlayerActiveObjective( player, "EG_DropshipExtractSuccessfulEscape" )
+
+ // skybox
player.SetSkyCamera( GetEnt( "skybox_cam_intro" ) )
Remote_CallFunction_NonReplay( player, "ServerCallback_DisableHudForEvac" )
+ Remote_CallFunction_NonReplay( player, "ServerCallback_SetClassicSkyScale", dropship.GetEncodedEHandle(), 0.7 )
+ Remote_CallFunction_NonReplay( player, "ServerCallback_SetMapSettings", 4.0, false, 0.4, 0.125 )
+
+ // display player [Evacuated] in killfeed
+ foreach ( entity otherPlayer in GetPlayerArray() )
+ Remote_CallFunction_NonReplay( otherPlayer, "ServerCallback_EvacObit", player.GetEncodedEHandle() )
}
- wait 5.0
-
- foreach ( entity player in GetPlayerArray() )
- ScreenFadeToBlackForever( player, 2.0 )
-
- wait 2.0
-
- // end game lol
- SetGameState( eGameState.Postmatch )
}
-void function EvacShipThink( entity dropship )
+void function AddPlayerToEvacDropship( entity dropship, entity player )
{
- dropship.EndSignal( "OnDestroy" )
-
- // this is the easiest way i could figure out to get a bounding box that's parented to the dropship
- entity mover1 = CreateScriptMover( dropship.GetOrigin(), dropship.GetAngles() )
- mover1.SetParent( dropship )
- mover1.SetLocalOrigin( dropship.GetBoundingMaxs() - < 0, 0, 100> )
-
- entity mover2 = CreateScriptMover( dropship.GetOrigin(), dropship.GetAngles() )
- mover2.SetParent( dropship )
- mover2.SetLocalOrigin( dropship.GetBoundingMins() - < 0, 0, 100 > )
-
- while ( true )
+ int slot = RandomInt( dropship.s.evacSlots.len() )
+ for ( int i = 0; i < dropship.s.evacSlots.len(); i++ )
{
- foreach ( entity player in GetPlayerArrayOfTeam( dropship.GetTeam() ) )
+ if ( !IsValid( dropship.s.evacSlots[ slot ] ) )
{
- if ( file.evacPlayers.contains( player ) || !IsAlive( player ) )
- continue
-
- vector playerPos = player.GetOrigin()
-
- vector mover1Pos = mover1.GetOrigin()
- vector mover2Pos = mover2.GetOrigin()
- vector maxPos
- maxPos.x = mover1Pos.x > mover2Pos.x ? mover1Pos.x : mover2Pos.x
- maxPos.y = mover1Pos.y > mover2Pos.y ? mover1Pos.y : mover2Pos.y
- maxPos.z = mover1Pos.z > mover2Pos.z ? mover1Pos.z : mover2Pos.z
-
- vector minPos
- minPos.x = mover1Pos.x < mover2Pos.x ? mover1Pos.x : mover2Pos.x
- minPos.y = mover1Pos.y < mover2Pos.y ? mover1Pos.y : mover2Pos.y
- minPos.z = mover1Pos.z < mover2Pos.z ? mover1Pos.z : mover2Pos.z
-
- print( "\n" )
- print( player )
- print( playerPos )
- print( minPos )
- print( maxPos )
-
- if ( playerPos.x > minPos.x && playerPos.y > minPos.y && playerPos.z > minPos.z &&
- playerPos.x < maxPos.x && playerPos.y < maxPos.y && playerPos.z < maxPos.z )
- {
- print( player + " is evacuating!" )
-
- file.evacPlayers.append( player )
- player.SetParent( dropship )
-
- // super duper temp
- player.SetLocalOrigin( dropship.GetOrigin() - < 0, 10, 80 > )
- }
+ dropship.s.evacSlots[ slot ] = player
+ break
}
-
- WaitFrame()
- }
-}
-
-/*void function TestEvac()
-{
- if ( file.evacShipSpawns.len() == 0 )
- Evac_AddLocation( GetEnt( "escape_node1" ).GetOrigin(), GetEnt( "escape_node1" ).GetAngles() )
-
- Point shipSpawn = file.evacShipSpawns[ RandomInt( file.evacShipSpawns.len() ) ]
-
- entity dropship = CreateDropship( GetPlayerArray()[0].GetTeam(), shipSpawn.origin, shipSpawn.angles )
- file.evacDropship = dropship
- DispatchSpawn( dropship )
-
- dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" )
-
- print( dropship.GetSequenceDuration( "cd_dropship_rescue_side_start" ) )
- print( dropship.GetScriptedAnimEventCycleFrac( "cd_dropship_rescue_side_start", "ReadyToLoad" ) )
- float embarkStart = dropship.GetSequenceDuration( "cd_dropship_rescue_side_start" ) * dropship.GetScriptedAnimEventCycleFrac( "cd_dropship_rescue_side_start", "ReadyToLoad" )
- print( embarkStart )
+ slot = ( slot + 1 ) % expect int( dropship.s.evacSlots.len() )
+ }
- thread PlayAnim( dropship, "cd_dropship_rescue_side_start" )
- wait embarkStart
- print( "evac start anim done" )
- thread TestEvacThink( dropship )
- SetTeamActiveObjective( GetPlayerArray()[0].GetTeam(), "EG_DropshipExtract2", Time() + 30, dropship )
+ // no slots available
+ if ( !PlayerInDropship( player, dropship ) )
+ return
+
+ player.SetInvulnerable()
+ player.UnforceCrouch()
+ player.ForceStand()
- thread PlayAnim( dropship, "cd_dropship_rescue_side_idle", GetEnt( "escape_node1" ) )
+ FirstPersonSequenceStruct fp
+ //fp.firstPersonAnim = EVAC_EMBARK_ANIMS_1P[ slot ]
+ fp.thirdPersonAnim = EVAC_EMBARK_ANIMS_3P[ slot ]
+ fp.attachment = "RESCUE"
+ fp.teleport = true
+ fp.thirdPersonCameraAttachments = [ "VDU" ] // this seems wrong, firstperson anim has better angles, but no head
+
+ EmitSoundOnEntityOnlyToPlayer( player, player, SHIFTER_START_SOUND_3P )
+ // should play SHIFTER_START_SOUND_1P when they actually arrive in the ship i think, unsure how this is supposed to be done
+ PlayPhaseShiftDisappearFX( player )
+ waitthread FirstPersonSequence( fp, player, dropship )
+
+ FirstPersonSequenceStruct idleFp
+ idleFp.firstPersonAnimIdle = EVAC_IDLE_ANIMS_1P[ slot ]
+ idleFp.thirdPersonAnimIdle = EVAC_IDLE_ANIMS_3P[ slot ]
+ idleFp.attachment = "RESCUE"
+ idleFp.teleport = true
+ idleFp.hideProxy = true
+ idleFp.viewConeFunction = ViewConeWide
+
+ thread FirstPersonSequence( idleFp, player, dropship )
+ ViewConeWide( player ) // gotta do this after for some reason, adding it to idleFp does not work for some reason
}
-void function TestEvacThink( entity dropship )
+bool function PlayerInDropship( entity player, entity dropship )
{
- dropship.EndSignal( "OnDestroy" )
-
- // these numbers are probably innacurate but there's no real way of getting accurate ones and these are good enough
- entity mover = CreateScriptMover( dropship.GetOrigin(), dropship.GetAngles() )
- mover.SetParent( dropship )
- mover.SetLocalOrigin( dropship.GetBoundingMaxs() - < 0, 0, 100> )
-
- entity mover2 = CreateScriptMover( dropship.GetOrigin(), dropship.GetAngles() )
- mover2.SetParent( dropship )
- mover2.SetLocalOrigin( dropship.GetBoundingMins() - < 0, 0, 100> )
-
- while ( true )
- {
- foreach ( entity player in GetPlayerArrayOfTeam( dropship.GetTeam() ) )
- {
- if ( !IsAlive( player ) )
- continue
-
- vector playerOrigin = player.GetOrigin()
-
- vector dropshipMax = mover.GetOrigin()
- vector dropshipMin = mover2.GetOrigin()
+ // couldn't get "player in dropship.s.evacSlots" to work for some reason, likely due to static typing?
+ foreach ( entity dropshipPlayer in dropship.s.evacSlots )
+ if ( dropshipPlayer == player )
+ return true
- // temp, might be permenant but idk if box triggers are a thing in script
- if ( playerOrigin.x > dropshipMin.x && playerOrigin.y > dropshipMin.y && playerOrigin.z > dropshipMin.z &&
- playerOrigin.x < dropshipMax.x && playerOrigin.y < dropshipMax.y && playerOrigin.z < dropshipMax.z )
- player.Die()
- }
-
- WaitFrame()
- }
-}*/ \ No newline at end of file
+ return false
+} \ No newline at end of file
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ffa.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ffa.nut
index 932f14b7d..85b4aefbd 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ffa.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ffa.nut
@@ -2,7 +2,7 @@ global function FFA_Init
void function FFA_Init()
{
- Evac_SetEnabled( false )
+ ClassicMP_ForceDisableEpilogue( true )
AddCallback_OnPlayerKilled( OnPlayerKilled )
}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/lobby/_private_lobby.gnut b/Northstar.CustomServers/mod/scripts/vscripts/lobby/_private_lobby.gnut
index 60daa4528..63b2c81ac 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/lobby/_private_lobby.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/lobby/_private_lobby.gnut
@@ -13,6 +13,11 @@ void function PrivateLobby_Init()
print( "PrivateLobby_Init()" )
//ClearPlaylistVarOverrides()
+ file.map = GetConVarString( "ns_private_match_last_map" )
+ file.mode = GetConVarString( "ns_private_match_last_mode" )
+
+ thread SetupPrivateMatchUIVarsWhenReady()
+
AddClientCommandCallback( "PrivateMatchLaunch", ClientCommandCallback_PrivateMatchLaunch )
AddClientCommandCallback( "PrivateMatchSetMode", ClientCommandCallback_PrivateMatchSetMode )
AddClientCommandCallback( "SetCustomMap", ClientCommandCallback_SetCustomMap )
@@ -22,6 +27,14 @@ void function PrivateLobby_Init()
AddClientCommandCallback( "ResetMatchSettingsToDefault", ClientCommandCallback_ResetMatchSettingsToDefault )
}
+void function SetupPrivateMatchUIVarsWhenReady()
+{
+ // have to wait until end of first frame for SetUIVar to work
+ WaitEndFrame()
+ SetUIVar( level, "privatematch_map", GetPrivateMatchMapIndex( file.map ) )
+ SetUIVar( level, "privatematch_mode", GetPrivateMatchModeIndex( file.mode ) )
+}
+
bool function ClientCommandCallback_PrivateMatchLaunch( entity player, array<string> args )
{
if ( file.startState == ePrivateMatchStartState.STARTING )
@@ -127,6 +140,8 @@ void function StartMatch()
RefreshPlayerTeams()
+ SetConVarString( "ns_private_match_last_map", file.map )
+ SetConVarString( "ns_private_match_last_mode", file.mode )
SetConVarBool( "ns_should_return_to_lobby", true ) // potentially temp?
// TEMP for now: start game
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_lobby.gnut b/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_lobby.gnut
index 2c02ebdc2..605b23fd9 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_lobby.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_lobby.gnut
@@ -189,11 +189,32 @@ void function AddPrivateMatchModeSettingEnumEx( string category, string playlist
#endif
}
-array< string > function GetPrivateMatchSettingCategories()
+array< string > function GetPrivateMatchSettingCategories( bool uiAllowAllModeCategories = false )
{
array< string > categories
foreach ( string k, v in file.customMatchSettingsByCategory )
+ {
+ // can only do this in ui because it relies on GetUIVar
+ #if UI
+ bool gamemode = k.find( "#GAMEMODE_" ) == 0
+ if ( !uiAllowAllModeCategories && ( gamemode || k.find( "#PL_" ) == 0 ) )
+ {
+ if ( gamemode )
+ {
+ if ( k.slice( 10 ) != PrivateMatch_GetSelectedMode() )
+ {
+ continue
+ }
+ }
+ else if ( k.slice( 4 ) != PrivateMatch_GetSelectedMode() )
+ {
+ continue
+ }
+ }
+ #endif
+
categories.append( k )
+ }
return categories
}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut b/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut
index 8991ebb0e..5cd4de503 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut
@@ -4,6 +4,8 @@ void function PrivateMatchModesInit()
{
// match settings
// super temp: do localisation strings later
+ AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_MATCH", "classic_mp", [ "Disabled", "Enabled" ], "1" )
+ AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_MATCH", "run_epilogue", [ "Disabled", "Enabled" ], "1" )
AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_MATCH", "scorelimit", "5" ) //, "Score Limit" )
AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_MATCH", "roundscorelimit", "0" ) //, "Score Limit (round-based modes)" )
AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_MATCH", "timelimit", "12" ) //, "Time Limit" )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_ai_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_ai_mp.gnut
index ac0c309b7..4cbab84c2 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_ai_mp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_ai_mp.gnut
@@ -30,12 +30,12 @@ bool function IsAutoPopulateEnabled( var team = null )
return true
}
-void function SPMP_UpdateNPCProficiency(entity ent)
+void function SPMP_UpdateNPCProficiency( entity ent )
{
}
-bool function SPMP_Callback_ForceAIMissPlayer(entity npc, entity player)
+bool function SPMP_Callback_ForceAIMissPlayer( entity npc, entity player )
{
return true
} \ No newline at end of file
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 d7db601bc..38803e04c 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut
@@ -219,6 +219,7 @@ void function CodeCallback_OnPlayerRespawned( entity player )
player.s.respawnTime = Time()
Loadouts_TryGivePilotLoadout( player )
+ SetHumanRagdollImpactTable( player )
foreach ( void functionref( entity ) callback in svGlobal.onPlayerRespawnedCallbacks )
callback( player )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp.nut
index ac8a397f7..66bb3d6a4 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp.nut
@@ -1,53 +1,80 @@
untyped
global function ClassicMp_Init
-global function ClassicMP_TryDefaultIntroSetup // called in mp_sh_init
+global function ClassicMP_TryDefaultIntroSetup
+
+// intro setups
+global function ClassicMP_SetLevelIntro
global function ClassicMP_SetCustomIntro
+global function ClassicMP_SetupIntro
+
+// intro funcs
global function ClassicMP_OnIntroStarted
global function ClassicMP_OnIntroFinished
global function ClassicMP_GetIntroLength
+
+// epilogue setups
+global function ClassicMP_ForceDisableEpilogue
+global function ClassicMP_SetEpilogue
+global function ClassicMP_SetupEpilogue
+global function ClassicMP_ShouldRunEpilogue
+
global function GetClassicMPMode
struct {
- void functionref() introSetupFunc
- float introLength
+ // level intros have a lower priority than custom intros
+ // level intros are used only if a custom intro was not specified
+ void functionref() levelIntroSetupFunc
+ float levelIntroLength
+
+ void functionref() customIntroSetupFunc
+ float customIntroLength
+
+ bool epilogueForceDisabled = false
+ void functionref() epilogueSetupFunc
} file
void function ClassicMp_Init()
{
- // literally nothing to do here atm lol
+ // default level intros
+ if ( IsFFAGame() )
+ ClassicMP_SetLevelIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() )
+ else
+ ClassicMP_SetLevelIntro( ClassicMP_DefaultDropshipIntro_Setup, DROPSHIP_INTRO_LENGTH )
}
+// stub func, called in mp_sh_init
void function ClassicMP_TryDefaultIntroSetup()
{
- if ( file.introSetupFunc == null )
- {
- if ( IsFFAGame() )
- ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() )
- else
- ClassicMP_SetCustomIntro( ClassicMP_DefaultDropshipIntro_Setup, DROPSHIP_INTRO_LENGTH )
- }
-
- thread DelayedDoDefaultIntroSetup()
+
}
-void function DelayedDoDefaultIntroSetup()
+void function ClassicMP_SetLevelIntro( void functionref() setupFunc, float introLength )
{
- // wait a frame for CodeCallback_MapInit to run which generally sets custom intros
- WaitFrame()
- file.introSetupFunc()
+ file.levelIntroSetupFunc = setupFunc
+ file.levelIntroLength = introLength
}
void function ClassicMP_SetCustomIntro( void functionref() setupFunc, float introLength )
{
- file.introSetupFunc = setupFunc
- file.introLength = introLength
+ file.customIntroSetupFunc = setupFunc
+ file.customIntroLength = introLength
+}
+
+void function ClassicMP_SetupIntro()
+{
+ if ( file.customIntroSetupFunc != null )
+ file.customIntroSetupFunc()
+ else
+ file.levelIntroSetupFunc()
}
void function ClassicMP_OnIntroStarted()
{
print( "started intro!" )
- SetServerVar( "gameStartTime", Time() + file.introLength )
- SetServerVar( "roundStartTime", Time() + file.introLength )
+
+ float introLength = ClassicMP_GetIntroLength()
+ SetServerVar( "gameStartTime", Time() + introLength )
+ SetServerVar( "roundStartTime", Time() + introLength )
}
void function ClassicMP_OnIntroFinished()
@@ -58,10 +85,37 @@ void function ClassicMP_OnIntroFinished()
float function ClassicMP_GetIntroLength()
{
- return file.introLength
+ if ( file.customIntroSetupFunc != null )
+ return file.customIntroLength
+
+ return file.levelIntroLength
+}
+
+void function ClassicMP_ForceDisableEpilogue( bool disabled )
+{
+ file.epilogueForceDisabled = disabled
+}
+
+void function ClassicMP_SetEpilogue( void functionref() setupFunc )
+{
+ file.epilogueSetupFunc = setupFunc
+}
+
+void function ClassicMP_SetupEpilogue()
+{
+ if ( file.epilogueSetupFunc == null ) // default is evac
+ ClassicMP_SetEpilogue( EvacEpilogueSetup )
+
+ file.epilogueSetupFunc()
}
bool function GetClassicMPMode()
{
return GetCurrentPlaylistVarInt( "classic_mp", 1 ) == 1
+}
+
+bool function ClassicMP_ShouldRunEpilogue()
+{
+ // note: there is a run_evac playlist var, but it's unused, and default 0, so use a new one
+ return !file.epilogueForceDisabled && GetClassicMPMode() && !IsRoundBased() && GetCurrentPlaylistVarInt( "run_epilogue", 1 ) == 1
} \ 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 197ac5e90..e3f7e0b00 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
@@ -92,7 +92,8 @@ void function SetGameState( int newState )
void function GameState_EntitiesDidLoad()
{
- // nothing of importance to put here, this is referenced in _gamestate though so need it
+ if ( GetClassicMPMode() )
+ ClassicMP_SetupIntro()
}
void function WaittillGameStateOrHigher( int gameState )
@@ -185,9 +186,29 @@ void function GameStateEnter_Prematch()
int timeLimit = GameMode_GetTimeLimit( GAMETYPE ) * 60
if ( file.switchSidesBased )
timeLimit /= 2 // endtime is half of total per side
-
+
SetServerVar( "gameEndTime", Time() + timeLimit + ClassicMP_GetIntroLength() )
SetServerVar( "roundEndTime", Time() + ClassicMP_GetIntroLength() + GameMode_GetRoundTimeLimit( GAMETYPE ) * 60 )
+
+ if ( !GetClassicMPMode() )
+ thread StartGameWithoutClassicMP()
+}
+
+void function StartGameWithoutClassicMP()
+{
+ WaitFrame() // wait for callbacks to finish
+
+ // need these otherwise game will complain
+ SetServerVar( "gameStartTime", Time() )
+ SetServerVar( "roundStartTime", Time() )
+
+ foreach ( entity player in GetPlayerArray() )
+ {
+ RespawnAsPilot( player )
+ ScreenFadeFromBlack( player, 0 )
+ }
+
+ SetGameState( eGameState.Playing )
}
@@ -246,38 +267,53 @@ void function GameStateEnter_WinnerDetermined()
void function GameStateEnter_WinnerDetermined_Threaded()
{
- bool killcamsWereEnabled = KillcamsEnabled()
- if ( killcamsWereEnabled ) // dont want killcams to interrupt stuff
- SetKillcamsEnabled( false )
-
+ // do win announcement
+ int winningTeam = GetWinningTeam()
+
+ foreach ( entity player in GetPlayerArray() )
+ {
+ int announcementSubstr
+ if ( winningTeam != TEAM_UNASSIGNED )
+ announcementSubstr = player.GetTeam() == winningTeam ? file.announceRoundWinnerWinningSubstr : file.announceRoundWinnerLosingSubstr
+
+ if ( IsRoundBased() )
+ Remote_CallFunction_NonReplay( player, "ServerCallback_AnnounceRoundWinner", GetWinningTeam(), announcementSubstr, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME, GameRules_GetTeamScore2( TEAM_MILITIA ), GameRules_GetTeamScore2( TEAM_IMC ) )
+ else
+ Remote_CallFunction_NonReplay( player, "ServerCallback_AnnounceWinner", GetWinningTeam(), announcementSubstr, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME )
+ }
+
WaitFrame() // wait a frame so other scripts can setup killreplay stuff
entity replayAttacker = file.roundWinningKillReplayAttacker
- bool doReplay = Replay_IsEnabled() && !( !IsRoundBased() && Evac_IsEnabled() ) && IsRoundWinningKillReplayEnabled() && IsValid( replayAttacker )
+ bool doReplay = Replay_IsEnabled() && !ClassicMP_ShouldRunEpilogue() && IsRoundWinningKillReplayEnabled() && IsValid( replayAttacker )
&& Time() - file.roundWinningKillReplayTime <= ROUND_WINNING_KILL_REPLAY_LENGTH_OF_REPLAY
float replayLength = 2.0 // extra delay if no replay
if ( doReplay )
{
+ bool killcamsWereEnabled = KillcamsEnabled()
+ if ( killcamsWereEnabled ) // dont want killcams to interrupt stuff
+ SetKillcamsEnabled( false )
+
replayLength = ROUND_WINNING_KILL_REPLAY_LENGTH_OF_REPLAY
if ( "respawnTime" in replayAttacker.s && Time() - replayAttacker.s.respawnTime < replayLength )
replayLength += Time() - expect float ( replayAttacker.s.respawnTime )
SetServerVar( "roundWinningKillReplayEntHealthFrac", file.roundWinningKillReplayHealthFrac )
- }
-
- foreach ( entity player in GetPlayerArray() )
- thread PlayerWatchesRoundWinningKillReplay( player, doReplay, replayLength )
-
- wait ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME
- CleanUpEntitiesForRoundEnd() // fade should be done by this point, so cleanup stuff now when people won't see
- wait replayLength
-
- WaitFrame() // prevent a race condition with PlayerWatchesRoundWinningKillReplay
- file.roundWinningKillReplayAttacker = null // clear this
+
+ foreach ( entity player in GetPlayerArray() )
+ thread PlayerWatchesRoundWinningKillReplay( player, doReplay, replayLength )
- if ( killcamsWereEnabled )
- SetKillcamsEnabled( true )
+ wait ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME
+ CleanUpEntitiesForRoundEnd() // fade should be done by this point, so cleanup stuff now when people won't see
+ wait replayLength
+
+ WaitFrame() // prevent a race condition with PlayerWatchesRoundWinningKillReplay
+ file.roundWinningKillReplayAttacker = null // clear this
+
+ if ( killcamsWereEnabled )
+ SetKillcamsEnabled( true )
+ }
if ( IsRoundBased() )
{
@@ -299,8 +335,11 @@ void function GameStateEnter_WinnerDetermined_Threaded()
}
else
{
- if ( Evac_IsEnabled() )
+ if ( ClassicMP_ShouldRunEpilogue() )
+ {
+ ClassicMP_SetupEpilogue()
SetGameState( eGameState.Epilogue )
+ }
else
SetGameState( eGameState.Postmatch )
}
@@ -309,18 +348,8 @@ void function GameStateEnter_WinnerDetermined_Threaded()
void function PlayerWatchesRoundWinningKillReplay( entity player, bool doReplay, float replayLength )
{
player.FreezeControlsOnServer()
-
- int winningTeam = GetWinningTeam()
- int announcementSubstr
- if ( winningTeam != TEAM_UNASSIGNED )
- announcementSubstr = player.GetTeam() == winningTeam ? file.announceRoundWinnerWinningSubstr : file.announceRoundWinnerLosingSubstr
-
- if ( IsRoundBased() )
- Remote_CallFunction_NonReplay( player, "ServerCallback_AnnounceRoundWinner", winningTeam, announcementSubstr, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME, GameRules_GetTeamScore2( TEAM_MILITIA ), GameRules_GetTeamScore2( TEAM_IMC ) )
- else
- Remote_CallFunction_NonReplay( player, "ServerCallback_AnnounceWinner", winningTeam, announcementSubstr, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME )
- if ( IsRoundBased() || !Evac_IsEnabled() ) // if we're doing evac, then no fades or killreplay
+ if ( IsRoundBased() || !ClassicMP_ShouldRunEpilogue() ) // if we're doing evac, then no fades or killreplay
{
ScreenFadeToBlackForever( player, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME )
wait ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/_lf_maps_shared.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/_lf_maps_shared.gnut
index d61d6baa6..178b6560a 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/_lf_maps_shared.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/_lf_maps_shared.gnut
@@ -4,5 +4,5 @@ global function SetupLiveFireMaps
void function SetupLiveFireMaps()
{
Riff_ForceTitanAvailability( eTitanAvailability.Never )
- ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() )
+ ClassicMP_SetLevelIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() )
} \ No newline at end of file
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_angel_city.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_angel_city.nut
index 68b49ad59..87c9ea985 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_angel_city.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_angel_city.nut
@@ -2,12 +2,12 @@ global function CodeCallback_MapInit
void function CodeCallback_MapInit()
{
- Evac_AddLocation( < 2527.889893, -2865.360107, 753.002991 >, < 0, -80.54, 0 > )
- Evac_AddLocation( < 1253.530029, -554.075012, 811.125 >, < 0, 180, 0 > )
- Evac_AddLocation( < 2446.989990, 809.364014, 576.0 >, < 0, 90.253, 0 > )
- Evac_AddLocation( < -2027.430054, 960.395020, 609.007996 >, < 0, 179.604, 0 > )
+ AddEvacNode( CreateScriptRef( < 2527.889893, -2865.360107, 753.002991 >, < 0, -80.54, 0 > ) )
+ AddEvacNode( CreateScriptRef( < 1253.530029, -554.075012, 811.125 >, < 0, 180, 0 > ) )
+ AddEvacNode( CreateScriptRef( < 2446.989990, 809.364014, 576.0 >, < 0, 90.253, 0 > ) )
+ AddEvacNode( CreateScriptRef( < -2027.430054, 960.395020, 609.007996 >, < 0, 179.604, 0 > ) )
- Evac_SetSpacePosition( < -1700, -5500, -7600 >, < -3.620642, 270.307129, 0 > )
+ SetEvacSpaceNode( CreateScriptRef( < -1700, -5500, -7600 >, < -3.620642, 270.307129, 0 > ) )
// todo: also we need to change the powerup spawns on this map, they use a version from an older patch