diff --git a/.github/workflows/encoding.yml b/.github/workflows/encoding.yml index a88e3961a..5a730c203 100644 --- a/.github/workflows/encoding.yml +++ b/.github/workflows/encoding.yml @@ -3,7 +3,7 @@ on: [push, pull_request] jobs: check-loc-encoding: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout uses: actions/checkout@v3 @@ -12,7 +12,7 @@ jobs: files=$(ls Northstar.Client/mod/resource/northstar_client_localisation_*.txt) IFS=$'\n'; files=($files); unset IFS; ! file --mime "${files[@]}" | grep -v "charset=utf-16le" check-missing-translations: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout uses: actions/checkout@v3 diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut index 2b95d1a8c..97d993e65 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut @@ -16,7 +16,10 @@ void function SetupPlayerPreviousXPValues( entity player ) player.SetPersistentVar( "previousFactionXP[" + xpFaction + "]", FactionGetXP( player, xpFaction ) ) foreach ( string xpTitan in shTitanXP.titanClasses ) + { player.SetPersistentVar( "previousTitanXP[" + xpTitan + "]", TitanGetXP( player, xpTitan ) ) + player.SetPersistentVar( "fdPreviousTitanXP[" + xpTitan + "]", FD_TitanGetXP( player, xpTitan ) ) + } foreach ( string xpWeapon in shWeaponXP.weaponClassNames ) player.SetPersistentVar( GetItemPersistenceStruct( xpWeapon ) + ".previousWeaponXP", WeaponGetXP( player, xpWeapon ) ) @@ -35,6 +38,14 @@ void function HandleXPGainForScoreEvent( entity player, ScoreEvent event ) int weaponXp = ScoreEvent_GetXPValueWeapon( event ) int titanXp = ScoreEvent_GetXPValueTitan( event ) int factionXp = ScoreEvent_GetXPValueFaction( event ) + + if ( player.GetPlayerNetInt( "xpMultiplier" ) > 0 || GetCurrentPlaylistVarInt( "double_xp_enabled", 0 ) == 1 ) + { + xpValue *= 2 + weaponXp *= 2 + titanXp *= 2 + factionXp *= 2 + } entity weapon = player.GetActiveWeapon() if ( IsValid( weapon ) && ShouldTrackXPForWeapon( weapon.GetWeaponClassName() ) && weaponXp != 0 ) @@ -63,5 +74,10 @@ void function AddXP( entity player, int amount ) int newXp = player.GetPersistentVarAsInt( "xp" ) int newLevel = GetLevelForXP( newXp ) if ( newLevel != oldLevel ) + { Remote_CallFunction_NonReplay( player, "ServerCallback_PlayerLeveledUp", player.GetPersistentVarAsInt( "gen" ), newLevel ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForPlayerLevels( player, player.GetPersistentVarAsInt( "gen" ), newLevel ) + } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut index af074689c..760daef0b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut @@ -246,6 +246,9 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa SetTeamActiveObjective( evacTeam, "EG_DropshipExtract", Time() + arrivalTime, file.evacIcon ) SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtract", Time() + arrivalTime, file.evacIcon ) + foreach( entity player in GetPlayerArrayOfTeam( evacTeam ) ) //Show the Evac Match Goal for players of the team that lost the match + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 0 ) + // 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 @@ -280,6 +283,9 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa { SetTeamActiveObjective( evacTeam, "EG_DropshipExtractDropshipDestroyed" ) SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_DropshipExtractDropshipDestroyed" ) + + foreach( entity player in GetPlayerArrayOfTeam( evacTeam ) ) + SetPlayerChallengeEvacState( player, 0 ) } foreach ( entity player in dropship.s.evacSlots ) @@ -402,7 +408,10 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa if ( !PlayerInDropship( player, dropship ) ) { if ( player.GetTeam() == dropship.GetTeam() ) + { SetPlayerActiveObjective( player, "EG_DropshipExtractFailedEscape" ) + SetPlayerChallengeEvacState( player, 2 ) + } continue } @@ -417,6 +426,7 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa 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 ) + SetPlayerChallengeEvacState( player, 1 ) // display player [Evacuated] in killfeed foreach ( entity otherPlayer in GetPlayerArray() ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut index 6555c875b..5aee11044 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut @@ -4,10 +4,19 @@ void function AddFactionXP( entity player, int amount ) { string faction = GetFactionChoice( player ) int oldLevel = FactionGetLevel( player, faction ) + int FactionXPMatch = player.GetPersistentVarAsInt( "xp_match[" + XP_TYPE.FACTION_LEVELED + "]" ) + // increment xp player.SetPersistentVar( "factionXP[" + faction + "]", min( FactionGetXP( player, faction ) + amount, FactionGetMaxXP( faction ) ) ) // note: no notif for faction level up if ( FactionGetLevel( player, faction ) != oldLevel ) + { AddPlayerScore( player, "FactionLevelUp" ) + IncrementPlayerChallengeFactionLeveledUp( player ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.FACTION_LEVELED + "]", FactionXPMatch + 1 ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForFactionLevels( player, faction, oldLevel, FactionGetLevel( player, faction ) ) + } } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut index f47ee90f9..7d73c926f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut @@ -60,6 +60,7 @@ void function GamemodeAITdm_Init() } ScoreEvent_SetupEarnMeterValuesForMixedModes() + SetupGenericTDMChallenge() } // add settings diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut index 93a3aa168..9cf0021d7 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut @@ -178,6 +178,12 @@ void function AT_PlayerTitleThink( entity player ) { // Set player money count player.SetTitle( "$" + string( AT_GetPlayerBonusPoints( player ) ) ) + + if( AT_GetPlayerBonusPoints( player ) >= 600 && !HasPlayerCompletedMeritScore( player ) ) //Challenge is: "Earn $600." + { + AddPlayerScore( player, "ChallengeATAssault" ) + SetPlayerChallengeMeritScore( player ) + } } else if ( GetGameState() >= eGameState.WinnerDetermined ) { diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut index c5765300f..d8b0c9bdd 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut @@ -29,6 +29,8 @@ struct { array hardpoints array players + table playerAssaultPoints + table playerDefensePoints } file void function GamemodeCP_Init() @@ -112,11 +114,13 @@ void function GamemodeCP_OnPlayerKilled(entity victim, entity attacker, var dama { AddPlayerScore( attacker , "HardpointDefense", victim ) attacker.AddToPlayerGameStat(PGS_DEFENSE_SCORE,POINTVALUE_HARDPOINT_DEFENSE) + UpdatePlayerScoreForChallenge(attacker,0,POINTVALUE_HARDPOINT_DEFENSE) } else if((victimCP.hardpoint.GetTeam()==victim.GetTeam())||(GetHardpointCappingTeam(victimCP)==victim.GetTeam())) { AddPlayerScore( attacker, "HardpointAssault", victim ) attacker.AddToPlayerGameStat(PGS_ASSAULT_SCORE,POINTVALUE_HARDPOINT_ASSAULT) + UpdatePlayerScoreForChallenge(attacker,POINTVALUE_HARDPOINT_ASSAULT,0) } } } @@ -127,10 +131,12 @@ void function GamemodeCP_OnPlayerKilled(entity victim, entity attacker, var dama { AddPlayerScore( attacker , "HardpointSnipe", victim ) attacker.AddToPlayerGameStat(PGS_ASSAULT_SCORE,POINTVALUE_HARDPOINT_SNIPE) + UpdatePlayerScoreForChallenge(attacker,POINTVALUE_HARDPOINT_SNIPE,0) } else{ AddPlayerScore( attacker , "HardpointSiege", victim ) attacker.AddToPlayerGameStat(PGS_ASSAULT_SCORE,POINTVALUE_HARDPOINT_SIEGE) + UpdatePlayerScoreForChallenge(attacker,POINTVALUE_HARDPOINT_SIEGE,0) } } else if(attackerCP.hardpoint!=null)//Perimeter Defense @@ -138,6 +144,7 @@ void function GamemodeCP_OnPlayerKilled(entity victim, entity attacker, var dama if(attackerCP.hardpoint.GetTeam()==attacker.GetTeam()) AddPlayerScore( attacker , "HardpointPerimeterDefense", victim) attacker.AddToPlayerGameStat(PGS_DEFENSE_SCORE,POINTVALUE_HARDPOINT_PERIMETER_DEFENSE) + UpdatePlayerScoreForChallenge(attacker,0,POINTVALUE_HARDPOINT_PERIMETER_DEFENSE) } foreach(CP_PlayerStruct player in file.players) //Reset Victim Holdtime Counter @@ -308,6 +315,7 @@ void function CapturePointForTeam(HardpointStruct hardpoint, int Team) if(player.IsPlayer()){ AddPlayerScore(player,"ControlPointCapture") player.AddToPlayerGameStat(PGS_ASSAULT_SCORE,POINTVALUE_HARDPOINT_CAPTURE) + UpdatePlayerScoreForChallenge(player,POINTVALUE_HARDPOINT_CAPTURE,0) } } } @@ -319,12 +327,17 @@ void function GamemodeCP_InitPlayer(entity player) playerStruct.timeOnPoints = [0.0,0.0,0.0] playerStruct.isOnHardpoint = false file.players.append(playerStruct) + file.playerAssaultPoints[player] <- 0 + file.playerDefensePoints[player] <- 0 thread PlayerThink(playerStruct) } void function GamemodeCP_RemovePlayer(entity player) { - + if(player in file.playerAssaultPoints) + delete file.playerAssaultPoints[player] + if(player in file.playerDefensePoints) + delete file.playerDefensePoints[player] foreach(index,CP_PlayerStruct playerStruct in file.players) { if(playerStruct.player==player) @@ -376,11 +389,13 @@ void function PlayerThink(CP_PlayerStruct player) { AddPlayerScore(player.player,"ControlPointAmpedHold") player.player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, POINTVALUE_HARDPOINT_AMPED_HOLD ) + UpdatePlayerScoreForChallenge(player.player,0,POINTVALUE_HARDPOINT_AMPED_HOLD) } else { AddPlayerScore(player.player,"ControlPointHold") player.player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, POINTVALUE_HARDPOINT_HOLD ) + UpdatePlayerScoreForChallenge(player.player,0,POINTVALUE_HARDPOINT_HOLD) } } break @@ -574,6 +589,7 @@ void function HardpointThink( HardpointStruct hardpoint ) { AddPlayerScore(player,"ControlPointAmped") player.AddToPlayerGameStat(PGS_DEFENSE_SCORE,POINTVALUE_HARDPOINT_AMPED) + UpdatePlayerScoreForChallenge(player,0,POINTVALUE_HARDPOINT_AMPED) } } } @@ -714,3 +730,26 @@ string function GetHardpointGroup(entity hardpoint) //Hardpoint Entity B on Home return string(hardpoint.kv.hardpointGroup) } + +void function UpdatePlayerScoreForChallenge(entity player,int assaultpoints = 0,int defensepoints = 0) +{ + if(player in file.playerAssaultPoints) + { + file.playerAssaultPoints[player] += assaultpoints + if( file.playerAssaultPoints[player] >= 1000 && !HasPlayerCompletedMeritScore(player) ) + { + AddPlayerScore(player,"ChallengeCPAssault") + SetPlayerChallengeMeritScore(player) + } + } + + if(player in file.playerDefensePoints) + { + file.playerDefensePoints[player] += defensepoints + if( file.playerDefensePoints[player] >= 500 && !HasPlayerCompletedMeritScore(player) ) + { + AddPlayerScore(player,"ChallengeCPDefense") + SetPlayerChallengeMeritScore(player) + } + } +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 9b05c3d42..fefdbcddd 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -421,8 +421,15 @@ void function CaptureFlag( entity player, entity flag ) assistList = file.militiaCaptureAssistList foreach( entity assistPlayer in assistList ) + { if ( player != assistPlayer ) AddPlayerScore( assistPlayer, "FlagCaptureAssist", player ) + if( !HasPlayerCompletedMeritScore( assistPlayer ) ) + { + AddPlayerScore( assistPlayer, "ChallengeCTFCapAssist" ) + SetPlayerChallengeMeritScore( assistPlayer ) + } + } assistList.clear() @@ -430,6 +437,12 @@ void function CaptureFlag( entity player, entity flag ) MessageToPlayer( player, eEventNotifications.YouCapturedTheEnemyFlag ) EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_PlayerScore" ) + if( !HasPlayerCompletedMeritScore( player ) ) + { + AddPlayerScore( player, "ChallengeCTFRetAssist" ) + SetPlayerChallengeMeritScore( player ) + } + MessageToTeam( team, eEventNotifications.PlayerCapturedEnemyFlag, player, player ) EmitSoundOnEntityToTeamExceptPlayer( flag, "UI_CTF_3P_TeamScore", player.GetTeam(), player ) @@ -503,6 +516,12 @@ void function TryReturnFlag( entity player, entity flag ) AddPlayerScore( player, "FlagReturn", player ) player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, 1 ) + if( !HasPlayerCompletedMeritScore( player ) ) + { + AddPlayerScore( player, "ChallengeCTFRetAssist" ) + SetPlayerChallengeMeritScore( player ) + } + MessageToTeam( flag.GetTeam(), eEventNotifications.PlayerReturnedFriendlyFlag, null, player ) EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_TeamReturnsFlag", flag.GetTeam() ) PlayFactionDialogueToTeam( "ctf_flagReturnedFriendly", flag.GetTeam() ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fra.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fra.nut index 9d8f84b5c..6d0fd3c7b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fra.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fra.nut @@ -17,6 +17,7 @@ void function GamemodeFRA_Init() ScoreEvent_SetEarnMeterValues( "PilotBatteryPickup", 0.0, 0.34 ) EarnMeterMP_SetPassiveMeterGainEnabled( false ) PilotBattery_SetMaxCount( 3 ) + SetupGenericFFAChallenge() AddCallback_OnPlayerKilled( FRARemoveEarnMeter ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut index 31c85a573..8999231d3 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut @@ -8,6 +8,8 @@ struct { float lastDamageInfoTime bool shouldDoHighlights + + table< entity, int > pilotstreak } file void function GamemodeLts_Init() @@ -34,6 +36,37 @@ void function GamemodeLts_Init() ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() ) ClassicMP_ForceDisableEpilogue( true ) AddCallback_GameStateEnter( eGameState.Playing, WaitForThirtySecondsLeft ) + + AddCallback_OnClientConnected( SetupPlayerLTSChallenges ) //Just to make up the Match Goals tracking + AddCallback_OnClientDisconnected( RemovePlayerLTSChallenges ) //Safety removal of data to prevent crashes + AddCallback_OnPlayerKilled( LTSChallengeForPlayerKilled ) +} + +void function SetupPlayerLTSChallenges( entity player ) +{ + file.pilotstreak[ player ] <- 0 +} + +void function RemovePlayerLTSChallenges( entity player ) +{ + if( player in file.pilotstreak ) + delete file.pilotstreak[ player ] +} + +void function LTSChallengeForPlayerKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( victim == attacker || !attacker.IsPlayer() || GetGameState() != eGameState.Playing ) + return + + if ( victim.IsPlayer() && attacker in file.pilotstreak ) + { + file.pilotstreak[attacker]++ + if( file.pilotstreak[attacker] >= 2 && !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengeLTS" ) + SetPlayerChallengeMeritScore( attacker ) + } + } } void function WaitForThirtySecondsLeft() diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut index d36045a61..768bbde11 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut @@ -180,6 +180,12 @@ void function MarkPlayers( entity imcMark, entity militiaMark ) entity livingMark = GetMarked( GetOtherTeam( deadMark.GetTeam() ) ) livingMark.SetPlayerGameStat( PGS_DEFENSE_SCORE, livingMark.GetPlayerGameStat( PGS_DEFENSE_SCORE ) + 1 ) + if( !HasPlayerCompletedMeritScore( livingMark ) ) + { + AddPlayerScore( livingMark, "ChallengeMFD" ) + SetPlayerChallengeMeritScore( livingMark ) + } + // thread this so we don't kill our own thread thread AddTeamScore( livingMark.GetTeam(), 1 ) } @@ -195,8 +201,15 @@ void function UpdateMarksForKill( entity victim, entity attacker, var damageInfo MessageToAll( eEventNotifications.MarkedForDeathKill, null, victim, actualAttacker.GetEncodedEHandle() ) svGlobal.levelEnt.Signal( "MarkKilled", { mark = victim } ) - + if ( !isSuicide && attacker.IsPlayer() ) + { attacker.SetPlayerGameStat( PGS_ASSAULT_SCORE, attacker.GetPlayerGameStat( PGS_ASSAULT_SCORE ) + 1 ) + if( !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengeMFD" ) + SetPlayerChallengeMeritScore( attacker ) + } + } } } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut index 57355ad8b..c91c27d11 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut @@ -19,6 +19,7 @@ void function GamemodePs_Init() AddCallback_OnPlayerKilled( GiveScoreForPlayerKill ) ScoreEvent_SetupEarnMeterValuesForMixedModes() SetTimeoutWinnerDecisionFunc( CheckScoreForDraw ) + SetupGenericFFAChallenge() // spawnzone stuff SetShouldCreateMinimapSpawnZones( true ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut index cb277b004..4617476eb 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut @@ -18,6 +18,7 @@ void function GamemodeSpeedball_Init() Riff_ForceTitanAvailability( eTitanAvailability.Never ) Riff_ForceSetEliminationMode( eEliminationMode.Pilots ) ScoreEvent_SetupEarnMeterValuesForMixedModes() + SetupGenericFFAChallenge() AddSpawnCallbackEditorClass( "script_ref", "info_speedball_flag", CreateFlag ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut index 5c0e6feca..61ede2d44 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut @@ -6,6 +6,7 @@ void function GamemodeTdm_Init() AddCallback_OnPlayerKilled( GiveScoreForPlayerKill ) ScoreEvent_SetupEarnMeterValuesForMixedModes() SetTimeoutWinnerDecisionFunc( CheckScoreForDraw ) + SetupGenericTDMChallenge() } void function GiveScoreForPlayerKill( entity victim, entity attacker, var damageInfo ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut index 6b30a3990..3ba843945 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut @@ -2,6 +2,11 @@ global function GamemodeTTDM_Init const float TTDMIntroLength = 15.0 +struct +{ + table< entity, int > challengeCount +} file + void function GamemodeTTDM_Init() { Riff_ForceSetSpawnAsTitan( eSpawnAsTitan.Always ) @@ -14,6 +19,8 @@ void function GamemodeTTDM_Init() ClassicMP_ForceDisableEpilogue( true ) SetTimeoutWinnerDecisionFunc( CheckScoreForDraw ) + AddCallback_OnClientConnected( SetupPlayerTTDMChallenges ) //Just to make up the Match Goals tracking + AddCallback_OnClientDisconnected( RemovePlayerTTDMChallenges ) //Safety removal of data to prevent crashes AddCallback_OnPlayerKilled( AddTeamScoreForPlayerKilled ) // dont have to track autotitan kills since you cant leave your titan in this mode // probably needs scoreevent earnmeter values @@ -56,6 +63,17 @@ void function TTDMIntroShowIntermissionCam( entity player ) thread PlayerWatchesTTDMIntroIntermissionCam( player ) } +void function SetupPlayerTTDMChallenges( entity player ) +{ + file.challengeCount[ player ] <- 0 +} + +void function RemovePlayerTTDMChallenges( entity player ) +{ + if( player in file.challengeCount ) + delete file.challengeCount[ player ] +} + void function PlayerWatchesTTDMIntroIntermissionCam( entity player ) { player.EndSignal( "OnDestroy" ) @@ -79,6 +97,19 @@ void function AddTeamScoreForPlayerKilled( entity victim, entity attacker, var d if ( victim == attacker || !victim.IsPlayer() || !attacker.IsPlayer() && GetGameState() == eGameState.Playing ) return + if( victim in file.challengeCount ) + file.challengeCount[victim] = 0 + + if( attacker in file.challengeCount ) + { + file.challengeCount[attacker]++ + if( file.challengeCount[attacker] >= 2 && !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengeTTDM" ) + SetPlayerChallengeMeritScore( attacker ) + } + } + AddTeamScore( GetOtherTeam( victim.GetTeam() ), 1 ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut index 466a50425..4b866a40f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut @@ -1,6 +1,274 @@ global function InitChallenges +global function SetPlayerChallengeEvacState //Hooked in _evac.gnut +global function SetPlayerChallengeMatchWon //Hooked in _score.nut +global function SetPlayerChallengeMatchComplete //Hooked in _score.nut +global function SetPlayerChallengeMeritScore //Up to gamemodes to use this directly if needed +global function IncrementPlayerChallengeTitanLeveledUp //Hooked in titan_xp.gnut +global function IncrementPlayerChallengeWeaponLeveledUp //Hooked in weapon_xp.gnut +global function IncrementPlayerChallengeFactionLeveledUp //Hooked in faction_xp.gnut (invisible but necessary for post-summary menu) +global function RegisterChallenges_OnMatchEnd //Hooked in _gamestate_mp.gnut + +global function HasPlayerCompletedMeritScore //Check from gamemodes to not reapply SetPlayerChallengeMeritScore +global function SetupGenericTDMChallenge //Used by gamemodes which simply adopts the: "Kill 3 Pilots without dying." Challenge +global function SetupGenericFFAChallenge //Used by gamemodes which simply adopts the: "Kill 5 Pilots." Challenge + +struct +{ + table< entity, int > playerTotalMeritCount + table< entity, bool > playerChallenge + table< entity, int > pilotstreak + bool isHappyHourActive +} file + + + + + + +/*============================================================================================================= + __ __ _ _ ____ _ _ _ + | \/ | __ _ | |_ ___ | |__ / ___|| |__ __ _ | || | ___ _ __ __ _ ___ ___ + | |\/| | / _` || __|/ __|| '_ \ | | | '_ \ / _` || || | / _ \| '_ \ / _` | / _ \/ __| + | | | || (_| || |_| (__ | | | | | |___ | | | || (_| || || || __/| | | || (_| || __/\__ \ + |_| |_| \__,_| \__|\___||_| |_| \____||_| |_| \__,_||_||_| \___||_| |_| \__, | \___||___/ + |___/ +=============================================================================================================*/ void function InitChallenges() { +#if (UI && CLIENT) + + SCB_SetCompleteMeritState( 4 ) + SCB_SetEvacMeritState( 4 ) + SCB_SetMeritCount( 4 ) + SCB_SetScoreMeritState( 4 ) + SCB_SetWinMeritState( 4 ) + SCB_SetWeaponMeritCount( -1 ) + SCB_SetTitanMeritCount( -1 ) + +#elseif (SERVER && MP) + + AddCallback_OnClientConnected( SetupPlayerMenuChallenges ) + AddCallback_OnClientDisconnected( RemovePlayerFromChallengePool ) + +#endif +} + +void function SetupPlayerMenuChallenges( entity player ) +{ + file.playerTotalMeritCount[ player ] <- 0 + file.pilotstreak[ player ] <- 0 + file.playerChallenge[ player ] <- false + + thread SetupChallenges_Threaded( player ) +} +void function SetupChallenges_Threaded( entity player ) +{ + WaitFrame() + + Remote_CallFunction_UI( player, "SCB_SetCompleteMeritState", 0 ) + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 4 ) //4 tells RUI to hide it + Remote_CallFunction_UI( player, "SCB_SetMeritCount", 0 ) + Remote_CallFunction_UI( player, "SCB_SetScoreMeritState", 0 ) + Remote_CallFunction_UI( player, "SCB_SetWinMeritState", 0 ) + Remote_CallFunction_UI( player, "SCB_SetWeaponMeritCount", 0 ) + Remote_CallFunction_UI( player, "SCB_SetTitanMeritCount", 0 ) +} + +void function SetupGenericTDMChallenge() +{ + AddCallback_OnPlayerKilled( TDMChallenges_OnPlayerKilled ) +} + +void function SetupGenericFFAChallenge() +{ + AddCallback_OnPlayerKilled( FFAChallenges_OnPlayerKilled ) +} + +void function RemovePlayerFromChallengePool( entity player ) +{ + if( player in file.playerChallenge ) + delete file.playerChallenge[ player ] + if( player in file.playerTotalMeritCount ) + delete file.playerTotalMeritCount[ player ] + if( player in file.pilotstreak ) + delete file.pilotstreak[ player ] +} + +void function RegisterChallenges_OnMatchEnd() +{ + bool eliteWarpaintRNG = false + + if( RandomIntRange( 0, 100 ) <= 30 ) //30% Chance to trigger akin to vanilla, apply always since all players have paid cosmetics unlocked + eliteWarpaintRNG = true + + foreach( player in GetPlayerArray() ) + { + player.SetPersistentVar( "isPostGameScoreboardValid", true ) + player.SetPersistentVar( "isFDPostGameScoreboardValid", false ) //FD itself overrides this right after when match ends + SetUIVar( level, "showGameSummary", true ) + + if( eliteWarpaintRNG ) + SetPlayerChallengeSquadLeader( player ) + + if( ShouldAwardHappyHourBonus( player ) ) + { + AddPlayerScore( player, "HappyHourBonus" ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.HAPPY_HOUR + "]", 5 ) //The XP Given from Happy Hour Score is 5 merits + } + } +} + +void function TDMChallenges_OnPlayerKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( victim == attacker || !attacker.IsPlayer() || GetGameState() != eGameState.Playing ) + return + + if ( victim.IsPlayer() ) + { + if( victim in file.pilotstreak ) + file.pilotstreak[victim] = 0 + if( attacker in file.pilotstreak ) + { + file.pilotstreak[attacker]++ + if( file.pilotstreak[attacker] >= 3 && !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengeTDM" ) + SetPlayerChallengeMeritScore( attacker ) + } + } + } +} + +void function FFAChallenges_OnPlayerKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( victim == attacker || !attacker.IsPlayer() || GetGameState() != eGameState.Playing ) + return + + if ( victim.IsPlayer() && attacker in file.pilotstreak ) + { + file.pilotstreak[attacker]++ + if( file.pilotstreak[attacker] >= 5 && !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengePVPKillCount" ) + SetPlayerChallengeMeritScore( attacker ) + } + } +} + +bool function HasPlayerCompletedMeritScore( entity player ) +{ + Assert( player in file.playerChallenge, player + " is not registered in the challenge pool hooks." ) + return file.playerChallenge[ player ] +} + + + + + + + +/*============================================================================================================= + ____ _ _ _ _ + / ___| __ _ _ __ ___ ___ _ __ ___ ___ __| | ___ | | | | ___ ___ | | __ ___ + | | _ / _` || '_ ` _ \ / _ \| '_ ` _ \ / _ \ / _` | / _ \ | |_| | / _ \ / _ \ | |/ // __| + | |_| || (_| || | | | | || __/| | | | | || (_) || (_| || __/ | _ || (_) || (_) || < \__ \ + \____| \__,_||_| |_| |_| \___||_| |_| |_| \___/ \__,_| \___| |_| |_| \___/ \___/ |_|\_\|___/ + +=============================================================================================================*/ + +void function SetPlayerChallengeEvacState( entity player, int successEvac = 0 ) +{ + if( successEvac == 0 ) //Evac Ship destroyed + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 2 ) + + else if( successEvac == 1 ) //Player itself managed to evac + { + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 1 ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.EVAC + "]", 1 ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + } + + else if( successEvac == 2 ) //Team managed to evac + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 3 ) +} + +void function SetPlayerChallengeMatchWon( entity player, bool playerWon ) +{ + if( playerWon ) + { + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetWinMeritState", 1 ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.MATCH_VICTORY + "]", 1 ) + player.SetPersistentVar( "matchWin", true ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + } + else + Remote_CallFunction_UI( player, "SCB_SetWinMeritState", -1 ) +} + +void function SetPlayerChallengeMatchComplete( entity player ) +{ + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetCompleteMeritState", 1 ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.MATCH_COMPLETED + "]", 1 ) + player.SetPersistentVar( "matchComplete", true ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) +} + +void function SetPlayerChallengeSquadLeader( entity player ) +{ + if( !ProgressionEnabledForPlayer( player ) ) + return + + Remote_CallFunction_NonReplay( player, "ServerCallback_SquadLeaderDoubleXP" ) + Remote_CallFunction_NonReplay( player, "ServerCallback_SquadLeaderBonus", player.GetEncodedEHandle() ) + player.SetPersistentVar( "matchSquadBonus", true ) + Player_GiveDoubleXP( player, 1 ) + foreach( entity teamplayer in GetPlayerArrayOfTeam( player.GetTeam() ) ) + { + if( teamplayer == player ) + continue + + Remote_CallFunction_NonReplay( player, "ServerCallback_SquadLeaderBonus", teamplayer.GetEncodedEHandle() ) + } +} + +void function SetPlayerChallengeMeritScore( entity player ) +{ + if( !HasPlayerCompletedMeritScore( player ) ) + { + file.playerChallenge[ player ] = true + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetScoreMeritState", 1 ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.SCORE_MILESTONE + "]", 1 ) + player.SetPersistentVar( "matchScoreEvent", true ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + } +} + +void function IncrementPlayerChallengeTitanLeveledUp( entity player ) +{ + player.p.meritData.titanMerits++ + file.playerTotalMeritCount[ player ]++ + + Remote_CallFunction_UI( player, "SCB_SetTitanMeritCount", player.p.meritData.titanMerits++ ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) +} + +void function IncrementPlayerChallengeWeaponLeveledUp( entity player ) +{ + player.p.meritData.weaponMerits++ + file.playerTotalMeritCount[ player ]++ + + Remote_CallFunction_UI( player, "SCB_SetWeaponMeritCount", player.p.meritData.weaponMerits ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) +} + +void function IncrementPlayerChallengeFactionLeveledUp( entity player ) +{ + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) } \ 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 5cc096f29..5eba24acd 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -396,6 +396,7 @@ void function GameStateEnter_WinnerDetermined_Threaded() } else { + RegisterChallenges_OnMatchEnd() if ( ClassicMP_ShouldRunEpilogue() ) { ClassicMP_SetupEpilogue() @@ -834,11 +835,44 @@ void function SetWinner( int team, string winningReason = "", string losingReaso } SetGameState( eGameState.WinnerDetermined ) + ScoreEvent_RoundComplete( team ) } else + { SetGameState( eGameState.WinnerDetermined ) - - ScoreEvent_MatchComplete( team ) + ScoreEvent_MatchComplete( team ) + + array players = GetPlayerArray() + int functionref( entity, entity ) compareFunc = GameMode_GetScoreCompareFunc( GAMETYPE ) + if ( compareFunc != null ) + { + players.sort( compareFunc ) + int playerCount = players.len() + int currentPlace = 1 + for ( int i = 0; i < 3; i++ ) + { + if ( i >= playerCount ) + continue + + if ( i > 0 && compareFunc( players[i - 1], players[i] ) != 0 ) + currentPlace += 1 + + switch( currentPlace ) + { + case 1: + UpdatePlayerStat( players[i], "game_stats", "mvp" ) + UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) + break + case 2: + UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) + break + case 3: + UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) + break + } + } + } + } } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index aba1d5401..2a4c4282c 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut @@ -8,6 +8,7 @@ global function ScoreEvent_TitanDoomed global function ScoreEvent_TitanKilled global function ScoreEvent_NPCKilled global function ScoreEvent_MatchComplete +global function ScoreEvent_RoundComplete global function ScoreEvent_SetEarnMeterValues global function ScoreEvent_SetupEarnMeterValuesForMixedModes @@ -287,8 +288,24 @@ void function ScoreEvent_MatchComplete( int winningTeam ) foreach( entity player in GetPlayerArray() ) { AddPlayerScore( player, "MatchComplete" ) + SetPlayerChallengeMatchComplete( player ) if ( player.GetTeam() == winningTeam ) + { AddPlayerScore( player, "MatchVictory" ) + SetPlayerChallengeMatchWon( player, true ) + } + else + SetPlayerChallengeMatchWon( player, false ) + } +} + +void function ScoreEvent_RoundComplete( int winningTeam ) +{ + foreach( entity player in GetPlayerArray() ) + { + AddPlayerScore( player, "RoundComplete" ) + if ( player.GetTeam() == winningTeam ) + AddPlayerScore( player, "RoundVictory" ) } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut index 0436a393c..847881b58 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut @@ -1,17 +1,39 @@ global function AddTitanXP +global function AddFDTitanXP void function AddTitanXP( entity player, int amount ) { string titan = GetActiveTitanLoadout( player ).titanClass int oldLevel = TitanGetLevel( player, titan ) + int TitanXPMatch = player.GetPersistentVarAsInt( "xp_match[" + XP_TYPE.TITAN_LEVELED + "]" ) // increment xp player.SetPersistentVar( "titanXP[" + titan + "]", min( TitanGetXP( player, titan ) + amount, TitanGetMaxXP( titan ) ) ) + Remote_CallFunction_NonReplay( player, "ServerCallback_TitanXPAdded", shTitanXP.titanClasses.find( titan ), TitanGetXP( player, titan ), amount ) // level up notif if ( TitanGetLevel( player, titan ) != oldLevel ) { Remote_CallFunction_NonReplay( player, "ServerCallback_TitanLeveledUp", shTitanXP.titanClasses.find( titan ), TitanGetGen( player, titan ), TitanGetLevel( player, titan ) ) AddPlayerScore( player, "TitanLevelUp" ) + IncrementPlayerChallengeTitanLeveledUp( player ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.TITAN_LEVELED + "]", TitanXPMatch + 1 ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForTitanLevels( player, titan, oldLevel, TitanGetLevel( player, titan ) ) } +} + +void function AddFDTitanXP( entity player, int fdXPamount ) +{ + string titanRef = GetActiveTitanLoadout( player ).titanClass + + player.SetPersistentVar( "fdTitanXP[" + titanRef + "]", FD_TitanGetPreviousXP( player, titanRef ) + fdXPamount ) + int startingLevel = FD_TitanGetLevelForXP( titanRef, FD_TitanGetPreviousXP( player, titanRef ) ) + int endingLevel = FD_TitanGetLevelForXP( titanRef, FD_TitanGetXP( player, titanRef ) ) + + Player_GiveFDUnlockPoints( player, endingLevel - startingLevel ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForFDTitanLevels( player, titanRef, startingLevel, endingLevel ) } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut index 4e25e3019..0b0084b3c 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut @@ -6,15 +6,22 @@ void function AddWeaponXP( entity player, int amount ) entity activeWeapon = player.GetActiveWeapon() string weaponClassname = activeWeapon.GetWeaponClassName() int oldLevel = WeaponGetLevel( player, weaponClassname ) + int WeaponXPMatch = player.GetPersistentVarAsInt( "xp_match[" + XP_TYPE.WEAPON_LEVELED + "]" ) // increment xp player.SetPersistentVar( GetItemPersistenceStruct( weaponClassname ) + ".weaponXP", min( WeaponGetXP( player, weaponClassname ) + amount, WeaponGetMaxXP( weaponClassname ) ) ) + Remote_CallFunction_NonReplay( player, "ServerCallback_WeaponXPAdded", shWeaponXP.weaponClassNames.find( weaponClassname ), WeaponGetXP( player, weaponClassname ), amount ) // level up notif if ( WeaponGetLevel( player, weaponClassname ) != oldLevel ) { Remote_CallFunction_NonReplay( player, "ServerCallback_WeaponLeveledUp", shWeaponXP.weaponClassNames.find( weaponClassname ), WeaponGetGen( player, weaponClassname ), WeaponGetLevel( player, weaponClassname ) ) AddPlayerScore( player, "WeaponLevelUp" ) + IncrementPlayerChallengeWeaponLeveledUp( player ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.WEAPON_LEVELED + "]", WeaponXPMatch + 1 ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForWeaponLevels( player, weaponClassname, oldLevel, WeaponGetLevel( player, weaponClassname ) ) } // proscreen