diff --git a/.gitattributes b/.gitattributes index c6a941dff..1bb89156e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,4 @@ -/Northstar.Client/mod/resource/northstar_client_localisation_*.txt text diff working-tree-encoding=UTF-16LE-BOM \ No newline at end of file +/Northstar.Client/mod/resource/northstar_client_localisation_*.txt text diff working-tree-encoding=UTF-16LE-BOM + +# Highlight `.gnut` like `.nut` files +*.gnut linguist-language=Squirrel diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 8397232d3..1148d3e58 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -502,6 +502,25 @@ "returnTypeString":"array", "argTypes":"string modName" }, + { + "name": "NSIsModDownloadable", + "helpText": "checks whether a mod is verified and can be auto-downloaded", + "returnTypeString": "bool", + "argTypes": "string name, string version" + + }, + { + "name": "NSDownloadMod", + "helpText": "downloads a given mod from distant API to local game profile", + "returnTypeString": "void", + "argTypes": "string name, string version" + }, + { + "name": "NSGetModInstallState", + "helpText": "get status of the mod currently being installed", + "returnTypeString": "ModInstallState", + "argTypes": "" + }, { "name":"NSReloadMods", "helpText":"", diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index a22f49fdf..44937a2b0 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -5,6 +5,10 @@ "LoadPriority": 0, "InitScript": "cl_northstar_client_init.nut", "ConVars": [ + { + "Name": "allow_mod_auto_download", + "DefaultValue": "0" + }, { "Name": "filter_hide_empty", "DefaultValue": "0" @@ -82,6 +86,10 @@ "After": "NSUpdateGameStateClientStart" } }, + { + "Path": "ui/menu_ns_moddownload.nut", + "RunOn": "UI" + }, { "Path": "ui/menu_ns_serverbrowser.nut", "RunOn": "UI", diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index c7b25a706..9bb369406 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -366,5 +366,25 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "PROGRESSION_DISABLED_BODY" "^CCCC0000Progression has been disabled.^\n\nTitans, Weapons, Factions, Skins, etc. will all be unlocked and usable at any time.\n\nThis can be changed at any time in the multiplayer lobby." "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Progression can now be enabled!^\n\nNorthstar now supports vanilla progression, meaning you can choose to unlock Weapons, Skins, Titans, etc. through levelling up and completing challenges.\n\nYou can enable progression using the button at the bottom of the lobby screen.\n\nThis can be changed at any time." + + // Mod downloading + "MISSING_MOD" "Missing mod \"%s1\" v%s2" + "MOD_NOT_VERIFIED" "(mod is not verified, and couldn't be downloaded automatically)" + "MOD_DL_DISABLED" "(automatic mod downloading is disabled)" + "DOWNLOADING_MOD_TITLE" "Downloading mod" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Downloading mod (%s1%)" + "DOWNLOADING_MOD_TEXT" "Downloading %s1 v%s2..." + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Downloading %s1 v%s2...\n(%s3/%s4 MB)" + "CHECKSUMING_TITLE" "Checksuming mod" + "CHECKSUMING_TEXT" "Verifying contents of %s1 v%s2..." + "EXTRACTING_MOD_TITLE" "Extracting mod (%s1%)" + "EXTRACTING_MOD_TEXT" "Extracting %s1 v%s2...\n(%s3/%s4 MB)" + "FAILED_DOWNLOADING" "Failed downloading mod" + "FAILED_READING_ARCHIVE" "An error occurred while reading mod archive." + "FAILED_WRITING_TO_DISK" "An error occurred while extracting mod files to the filesystem." + "MOD_FETCHING_FAILED" "Mod archive could not be downloaded from Thunderstore." + "MOD_CORRUPTED" "Downloaded archive checksum does not match verified signature." + "NO_DISK_SPACE_AVAILABLE" "There is not enough space on your disk." + "MOD_FETCHING_FAILED_GENERAL" "Mod extraction failed. Check logs for more details." } } diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut index 765d29c32..3560fd562 100644 --- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -53,3 +53,11 @@ global struct MasterServerAuthResult string errorCode string errorMessage } + +global struct ModInstallState +{ + int status + int progress + int total + float ratio +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut new file mode 100644 index 000000000..4d299362d --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut @@ -0,0 +1,117 @@ +global function DownloadMod +global function DisplayModDownloadErrorDialog + +global enum eModInstallStatus +{ + DOWNLOADING, + CHECKSUMING, + EXTRACTING, + DONE, + FAILED, + FAILED_READING_ARCHIVE, + FAILED_WRITING_TO_DISK, + MOD_FETCHING_FAILED, + MOD_CORRUPTED, + NO_DISK_SPACE_AVAILABLE, + NOT_FOUND +} + +const int MB = 1024*1000; + +bool function DownloadMod( RequiredModInfo mod ) +{ + // Downloading mod UI + DialogData dialogData + dialogData.header = Localize( "#DOWNLOADING_MOD_TITLE" ) + dialogData.message = Localize( "#DOWNLOADING_MOD_TEXT", mod.name, mod.version ) + dialogData.showSpinner = true; + + // Prevent user from closing dialog + dialogData.forceChoice = true; + OpenDialog( dialogData ) + + // Save reference to UI elements, to update their content + var menu = GetMenu( "Dialog" ) + var header = Hud_GetChild( menu, "DialogHeader" ) + var body = GetSingleElementByClassname( menu, "DialogMessageClass" ) + + // Start actual mod downloading + NSDownloadMod( mod.name, mod.version ) + + ModInstallState state = NSGetModInstallState() + while ( state.status < eModInstallStatus.DONE ) + { + state = NSGetModInstallState() + UpdateModDownloadDialog( mod, state, menu, header, body ) + WaitFrame() + } + + printt( "Mod status:", state.status ) + + // Close loading dialog + CloseActiveMenu() + + return state.status == eModInstallStatus.DONE +} + +void function UpdateModDownloadDialog( RequiredModInfo mod, ModInstallState state, var menu, var header, var body ) +{ + switch ( state.status ) + { + case eModInstallStatus.DOWNLOADING: + Hud_SetText( header, Localize( "#DOWNLOADING_MOD_TITLE_W_PROGRESS", string( state.ratio ) ) ) + Hud_SetText( body, Localize( "#DOWNLOADING_MOD_TEXT_W_PROGRESS", mod.name, mod.version, floor( state.progress / MB ), floor( state.total / MB ) ) ) + break + case eModInstallStatus.CHECKSUMING: + Hud_SetText( header, Localize( "#CHECKSUMING_TITLE" ) ) + Hud_SetText( body, Localize( "#CHECKSUMING_TEXT", mod.name, mod.version ) ) + break + case eModInstallStatus.EXTRACTING: + Hud_SetText( header, Localize( "#EXTRACTING_MOD_TITLE", string( state.ratio ) ) ) + Hud_SetText( body, Localize( "#EXTRACTING_MOD_TEXT", mod.name, mod.version, floor( state.progress / MB ), floor( state.total / MB ) ) ) + break + default: + break + } +} + +void function DisplayModDownloadErrorDialog( string modName ) +{ + ModInstallState state = NSGetModInstallState() + + DialogData dialogData + dialogData.header = Localize( "#FAILED_DOWNLOADING", modName ) + dialogData.image = $"ui/menu/common/dialog_error" + + switch ( state.status ) + { + case eModInstallStatus.FAILED_READING_ARCHIVE: + dialogData.message = Localize( "#FAILED_READING_ARCHIVE" ) + break + case eModInstallStatus.FAILED_WRITING_TO_DISK: + dialogData.message = Localize( "#FAILED_WRITING_TO_DISK" ) + break + case eModInstallStatus.MOD_FETCHING_FAILED: + dialogData.message = Localize( "#MOD_FETCHING_FAILED" ) + break + case eModInstallStatus.MOD_CORRUPTED: + dialogData.message = Localize( "#MOD_CORRUPTED" ) + break + case eModInstallStatus.NO_DISK_SPACE_AVAILABLE: + dialogData.message = Localize( "#NO_DISK_SPACE_AVAILABLE" ) + break + case eModInstallStatus.NOT_FOUND: + dialogData.message = Localize( "#NOT_FOUND" ) + break + case eModInstallStatus.FAILED: + default: + dialogData.message = Localize( "#MOD_FETCHING_FAILED_GENERAL" ) + break + } + + AddDialogButton( dialogData, "#DISMISS" ) + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + + OpenDialog( dialogData ) +} 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 efc8d66ce..29c7621c2 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -951,33 +951,65 @@ string function FillInServerModsLabel( array mods ) void function OnServerSelected( var button ) +{ + thread OnServerSelected_Threaded( button ) +} + +void function OnServerSelected_Threaded( var button ) { if ( NSIsRequestingServerList() || NSGetServerCount() == 0 || file.serverListRequestFailed ) return ServerInfo server = file.focusedServer - file.lastSelectedServer = server + // Count mods that have been successfully downloaded + bool autoDownloadAllowed = GetConVarBool( "allow_mod_auto_download" ) + int downloadedMods = 0; + foreach ( RequiredModInfo mod in server.requiredMods ) { if ( !NSGetModNames().contains( mod.name ) ) { - DialogData dialogData - dialogData.header = "#ERROR" - dialogData.message = format( "Missing mod \"%s\" v%s", mod.name, mod.version ) - dialogData.image = $"ui/menu/common/dialog_error" + // Check if mod can be auto-downloaded + bool modIsVerified = NSIsModDownloadable( mod.name, mod.version ) + + // Display an error message if not + if ( !modIsVerified || !autoDownloadAllowed ) + { + DialogData dialogData + dialogData.header = "#ERROR" + dialogData.message = Localize( "#MISSING_MOD", mod.name, mod.version ) + dialogData.image = $"ui/menu/common/dialog_error" + + // Specify error (only if autoDownloadAllowed is set) + if ( autoDownloadAllowed ) + { + dialogData.message += "\n" + Localize( "#MOD_NOT_VERIFIED" ) + } - #if PC_PROG AddDialogButton( dialogData, "#DISMISS" ) AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) - #endif // PC_PROG - AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) - OpenDialog( dialogData ) + OpenDialog( dialogData ) + + return + } - return + else // Launch download + { + if ( DownloadMod( mod ) ) + { + downloadedMods++ + } + else + { + DisplayModDownloadErrorDialog( mod.name ) + return + } + } } else { @@ -1018,6 +1050,13 @@ void function OnServerSelected( var button ) } } + // Make Northstar aware new mods have been added + if ( downloadedMods > 0 ) + { + print( "Some new mods have been downloaded or enabled, reloading mods." ) + NSReloadMods(); + } + if ( server.requiresPassword ) { OnCloseServerBrowserMenu() diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 0eecfb662..d6e36d092 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -24,6 +24,11 @@ { "Name": "ns_force_melee", "DefaultValue": "" + }, + { + "Name": "ns_show_event_models", + "DefaultValue": "1", + "Flags": "ARCHIVE_PLAYERPROFILE" } ], "Scripts": [ @@ -446,6 +451,20 @@ }, "UICallback": { "Before": "Testing_Init" + } + }, + { + "Path": "_event_models.gnut", + "RunOn": "SERVER && LOBBY", + "ServerCallback": { + "Before": "EventModelsInit" + } + }, + { + "Path": "ui/ns_custom_mod_settings.gnut", + "RunOn": "UI", + "UICallback":{ + "Before": "NSCustomModSettings" } } ], diff --git a/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vmt b/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vmt new file mode 100644 index 000000000..22b81e9ac --- /dev/null +++ b/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vmt @@ -0,0 +1,18 @@ +"UnlitTexture" +{ + $basetexture "models/northstartree/lightsflicker" + $color "[1.5 1.5 1.5]" + + Proxies + { + + TextureScroll + { + texturescrollvar $basetexturetransform + texturescrollrate 0.33 + texturescrollangle 45 + } + + } + +} diff --git a/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vtf b/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vtf new file mode 100644 index 000000000..227756be1 Binary files /dev/null and b/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vtf differ diff --git a/Northstar.Custom/mod/models/northstartree/winter_holiday_floor.mdl b/Northstar.Custom/mod/models/northstartree/winter_holiday_floor.mdl new file mode 100644 index 000000000..aaf703634 Binary files /dev/null and b/Northstar.Custom/mod/models/northstartree/winter_holiday_floor.mdl differ diff --git a/Northstar.Custom/mod/models/northstartree/winter_holiday_tree.mdl b/Northstar.Custom/mod/models/northstartree/winter_holiday_tree.mdl new file mode 100644 index 000000000..4690475f4 Binary files /dev/null and b/Northstar.Custom/mod/models/northstartree/winter_holiday_tree.mdl differ diff --git a/Northstar.Custom/mod/scripts/vscripts/_event_models.gnut b/Northstar.Custom/mod/scripts/vscripts/_event_models.gnut new file mode 100644 index 000000000..0802d7698 --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/_event_models.gnut @@ -0,0 +1,21 @@ +global function EventModelsInit + +void function EventModelsInit() +{ + if( !GetConVarBool( "ns_show_event_models" ) ) + return + + table timeParts = GetUnixTimeParts() + int month = expect int( timeParts[ "month" ] ) + int day = expect int( timeParts[ "day" ] ) + + // 18th December to 6th January + if( ( ( month == 12 ) && ( day >= 18 ) ) || ( ( month == 1 ) && ( day <= 6 ) ) ) + { + PrecacheModel( $"models/northstartee/winter_holiday_tree.mdl" ) + PrecacheModel( $"models/northstartree/winter_holiday_floor.mdl" ) + + CreatePropDynamic( $"models/northstartree/winter_holiday_tree.mdl", < -60, 740, 30 >, < 0, 0, 0 >, SOLID_VPHYSICS, 1000 ) + CreatePropDynamic( $"models/northstartree/winter_holiday_floor.mdl", < -60, 740, 30 >, < 0, 0, 0 >, SOLID_VPHYSICS, 1000 ) + } +} diff --git a/Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut b/Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut new file mode 100644 index 000000000..5a7d80b76 --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut @@ -0,0 +1,8 @@ +global function NSCustomModSettings + +void function NSCustomModSettings() +{ + ModSettings_AddModTitle( "Northstar Custom" , 2 ) + ModSettings_AddModCategory( "Event Models" ) + ModSettings_AddEnumSetting( "ns_show_event_models", "Show Event Models", [ "#SETTING_OFF", "#SETTING_ON" ], 2 ) +} diff --git a/Northstar.Custom/paks/bt.rpak b/Northstar.Custom/paks/bt.rpak new file mode 100644 index 000000000..7a4b9e31a Binary files /dev/null and b/Northstar.Custom/paks/bt.rpak differ diff --git a/Northstar.Custom/paks/bt.starpak b/Northstar.Custom/paks/bt.starpak new file mode 100644 index 000000000..70549d51b Binary files /dev/null and b/Northstar.Custom/paks/bt.starpak differ diff --git a/Northstar.Custom/paks/giftwrap.rpak b/Northstar.Custom/paks/giftwrap.rpak new file mode 100644 index 000000000..7b9200b30 Binary files /dev/null and b/Northstar.Custom/paks/giftwrap.rpak differ diff --git a/Northstar.Custom/paks/giftwrap.starpak b/Northstar.Custom/paks/giftwrap.starpak new file mode 100644 index 000000000..46ea6d8d2 Binary files /dev/null and b/Northstar.Custom/paks/giftwrap.starpak differ diff --git a/Northstar.Custom/paks/leaves.rpak b/Northstar.Custom/paks/leaves.rpak new file mode 100644 index 000000000..b17346dd7 Binary files /dev/null and b/Northstar.Custom/paks/leaves.rpak differ diff --git a/Northstar.Custom/paks/leaves.starpak b/Northstar.Custom/paks/leaves.starpak new file mode 100644 index 000000000..b37aa5230 Binary files /dev/null and b/Northstar.Custom/paks/leaves.starpak differ diff --git a/Northstar.Custom/paks/rpak.json b/Northstar.Custom/paks/rpak.json index 743468b4f..522c558ba 100644 --- a/Northstar.Custom/paks/rpak.json +++ b/Northstar.Custom/paks/rpak.json @@ -1,5 +1,10 @@ { "Postload": { - "mp_weapon_shotgun_doublebarrel.rpak": "common.rpak" + "mp_weapon_shotgun_doublebarrel.rpak": "common.rpak", + "leaves.rpak": "common.rpak", + "tree_stump.rpak": "common.rpak", + "bt.rpak": "common.rpak", + "giftwrap.rpak": "common.rpak", + "snow.rpak": "common.rpak" } -} \ No newline at end of file +} diff --git a/Northstar.Custom/paks/snow.rpak b/Northstar.Custom/paks/snow.rpak new file mode 100644 index 000000000..4756b6c7f Binary files /dev/null and b/Northstar.Custom/paks/snow.rpak differ diff --git a/Northstar.Custom/paks/snow.starpak b/Northstar.Custom/paks/snow.starpak new file mode 100644 index 000000000..7f3dbf19b Binary files /dev/null and b/Northstar.Custom/paks/snow.starpak differ diff --git a/Northstar.Custom/paks/tree_stump.rpak b/Northstar.Custom/paks/tree_stump.rpak new file mode 100644 index 000000000..3cdf18662 Binary files /dev/null and b/Northstar.Custom/paks/tree_stump.rpak differ diff --git a/Northstar.Custom/paks/tree_stump.starpak b/Northstar.Custom/paks/tree_stump.starpak new file mode 100644 index 000000000..b233176eb Binary files /dev/null and b/Northstar.Custom/paks/tree_stump.starpak differ diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut index 76cb4ac44..63756fdc8 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut @@ -193,6 +193,10 @@ bool function ClientCommandCallback_SwapSecondaryAndWeapon3PersistentLoadoutData // get loadout int index = args[0].tointeger() + + if ( !IsValidPilotLoadoutIndex(index) ) + return false + PilotLoadoutDef loadout = GetPilotLoadoutFromPersistentData( player, index ) // swap loadouts diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index df7577aa0..be20982df 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut @@ -28,6 +28,10 @@ void function InitPlayerForScoreEvents( entity player ) player.s.currentKillstreak <- 0 player.s.lastKillTime <- 0.0 player.s.currentTimedKillstreak <- 0 + player.s.lastKillTime_Mayhem <- 0.0 + player.s.currentTimedKillstreak_Mayhem <- 0 + player.s.lastKillTime_Onslaught <- 0.0 + player.s.currentTimedKillstreak_Onslaught <- 0 } void function AddPlayerScore( entity targetPlayer, string scoreEventName, entity associatedEnt = null, string noideawhatthisis = "", int pointValueOverride = -1 ) @@ -93,6 +97,7 @@ void function ScoreEvent_PlayerKilled( entity victim, entity attacker, var damag victim.s.currentTimedKillstreak = 0 victim.p.numberOfDeathsSinceLastKill++ // this is reset on kill + victim.p.lastKiller = attacker // have to do this early before we reset victim's player killstreaks // nemesis when you kill a player that is dominating you @@ -131,12 +136,20 @@ void function ScoreEvent_PlayerKilled( entity victim, entity attacker, var damag attacker.p.numberOfDeathsSinceLastKill = 0 } + // revenge + quick revenge + if ( attacker.p.lastKiller == victim ) + { + if ( Time() - GetPlayerLastRespawnTime( attacker ) < QUICK_REVENGE_TIME_LIMIT ) + AddPlayerScore( attacker, "QuickRevenge" ) + else + AddPlayerScore( attacker, "Revenge" ) + } // untimed killstreaks attacker.s.currentKillstreak++ - if ( attacker.s.currentKillstreak == 3 ) + if ( attacker.s.currentKillstreak == KILLINGSPREE_KILL_REQUIREMENT ) AddPlayerScore( attacker, "KillingSpree" ) - else if ( attacker.s.currentKillstreak == 5 ) + else if ( attacker.s.currentKillstreak == RAMPAGE_KILL_REQUIREMENT ) AddPlayerScore( attacker, "Rampage" ) // increment untimed killstreaks against specific players @@ -234,6 +247,39 @@ void function ScoreEvent_NPCKilled( entity victim, entity attacker, var damageIn AddPlayerScore( attacker, ScoreEventForNPCKilled( victim, damageInfo ), victim ) } catch ( ex ) {} + + if ( !attacker.IsPlayer() ) + return + + // mayhem/onslaught (timed killstreaks vs AI) + + // reset before checking + if ( Time() - attacker.s.lastKillTime_Mayhem > MAYHEM_REQUIREMENT_TIME ) + { + attacker.s.currentTimedKillstreak_Mayhem = 0 + attacker.s.lastKillTime_Mayhem = Time() + } + if ( Time() - attacker.s.lastKillTime_Mayhem <= MAYHEM_REQUIREMENT_TIME ) + { + attacker.s.currentTimedKillstreak_Mayhem++ + + if ( attacker.s.currentTimedKillstreak_Mayhem == MAYHEM_REQUIREMENT_KILLS ) + AddPlayerScore( attacker, "Mayhem" ) + } + + // reset before checking + if ( Time() - attacker.s.lastKillTime_Onslaught > ONSLAUGHT_REQUIREMENT_TIME ) + { + attacker.s.currentTimedKillstreak_Onslaught = 0 + attacker.s.lastKillTime_Onslaught = Time() + } + if ( Time() - attacker.s.lastKillTime_Onslaught <= ONSLAUGHT_REQUIREMENT_TIME ) + { + attacker.s.currentTimedKillstreak_Onslaught++ + + if ( attacker.s.currentTimedKillstreak_Onslaught == ONSLAUGHT_REQUIREMENT_KILLS ) + AddPlayerScore( attacker, "Onslaught" ) + } } void function ScoreEvent_MatchComplete( int winningTeam ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut index 496e8b42d..2dc88d0d4 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut @@ -38,6 +38,7 @@ void function Progression_Init() #if SERVER AddCallback_OnClientDisconnected( OnClientDisconnected ) AddClientCommandCallback( "ns_progression", ClientCommand_SetProgression ) + AddClientCommandCallback( "ns_resettitanaegis", ClientCommand_ResetTitanAegis ) AddCallback_GameStateEnter( eGameState.Playing, OnPlaying ) #elseif CLIENT AddCallback_OnClientScriptInit( OnClientScriptInit ) @@ -84,6 +85,28 @@ bool function ClientCommand_SetProgression( entity player, array args ) return true } + +/// Resets a specific Titan's Aegis rank back to `0` +/// * `player` - The player entity to perform the action on +/// * `args` - The arguments passed from the client command. `args[0]` should be an integer corresponding to the index of the Titan to reset. +/// +/// Returns `true` on success and `false` on missing args. +bool function ClientCommand_ResetTitanAegis( entity player, array args ) +{ + if ( !args.len() ) + return false + + int suitIndex = args[0].tointeger() + player.SetPersistentVar( "titanFDUnlockPoints[" + suitIndex + "]", 0 ) + player.SetPersistentVar( "previousFDUnlockPoints[" + suitIndex + "]", 0 ) + player.SetPersistentVar( "fdTitanXP[" + suitIndex + "]", 0 ) + player.SetPersistentVar( "fdPreviousTitanXP[" + suitIndex + "]", 0 ) + + // Refresh Highest Aegis Titan since we might get all of them back to 1 if players wants + RecalculateHighestTitanFDLevel( player ) + + return true +} #endif #if CLIENT diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut index 9e7629858..8751a2507 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut @@ -348,6 +348,14 @@ string function GetMapDisplayDesc( string mapname ) return "#" + mapname + "_CLASSIC_DESC" } +/// Sends a string message to player +/// * `baseString` - The input string to search through +/// * `searchString` - Find this substring... +/// * `replaceString` - ...and replace with this substring +/// * `replaceAll` - Whether to replace all occurences or just the first +/// * `caseInsensitive` - Whether to consider casing (upper/lower) +/// +/// Returns the updated string string function StringReplace( string baseString, string searchString, string replaceString, bool replaceAll = false, bool caseInsensitive = false ) { bool loopedOnce = false @@ -1532,6 +1540,22 @@ array function GetAvailableTitanRefs( entity player ) return availableTitanRefs } +/// Gets the highest Titan FD level and stores it in the corresponding persistent var. +/// * `player` - The player entity to perform the action on +void function RecalculateHighestTitanFDLevel( entity player ) +{ + int enumCount = PersistenceGetEnumCount( "titanClasses" ) + int highestAegis = 0 + for ( int i = 0; i < enumCount; i++ ) + { + string enumName = PersistenceGetEnumItemNameForIndex( "titanClasses", i ) + int aegisLevel = FD_TitanGetLevelForXP( enumName, FD_TitanGetXP( player, enumName ) ) + if ( highestAegis < aegisLevel ) + highestAegis = aegisLevel + } + player.SetPersistentVar( "fdStats.highestTitanFDLevel", highestAegis ) +} + #if MP string function GetTitanRefForLoadoutIndex( entity player, int loadoutIndex ) { diff --git a/README.md b/README.md index 5a180df9c..7b6dfaf02 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # NorthstarMods + +Translation status + [Squirrel](http://www.squirrel-lang.org/squirreldoc/reference/index.html) scripts used to recreate server-side gamelogic and add [custom content](https://r2northstar.gitbook.io/r2northstar-wiki/using-northstar/gamemodes) to the game. @@ -9,3 +12,11 @@ Issues in this repository should be created if they are related to these domains - `Northstar.Coop` - Soon™. - `Northstar.Custom` - Northstar custom content. - `Northstar.CustomServer` - Server config files and scripts necessary for multiplayer. + +### Translating + +Translations can be submitted via [weblate](https://translate.harmony.tf/projects/northstar/client/). + + +Translation status +