global function GamemodeGG_Init void function GamemodeGG_Init() { SetSpawnpointGamemodeOverride( FFA ) SetShouldUseRoundWinningKillReplay( true ) ClassicMP_ForceDisableEpilogue( true ) SetLoadoutGracePeriodEnabled( false ) // prevent modifying loadouts with grace period SetWeaponDropsEnabled( false ) Riff_ForceTitanAvailability( eTitanAvailability.Never ) Riff_ForceBoostAvailability( eBoostAvailability.Disabled ) AddCallback_OnPlayerRespawned( OnPlayerRespawned ) AddCallback_OnPlayerKilled( OnPlayerKilled ) AddCallback_OnClientDisconnected( OnPlayerDisconnected ) AddCallback_GameStateEnter( eGameState.WinnerDetermined, OnWinnerDetermined ) AddCallback_GGEarnMeterFull( OnGGEarnMeterFilled ) } void function OnPlayerDisconnected(entity player) { // resetting a player's score when they leave prevents a new player to join the leaver's team and having the previous player's points AddTeamScore( player.GetTeam(), -GameRules_GetTeamScore( player.GetTeam() ) ) } void function OnPlayerRespawned( entity player ) { UpdateLoadout( player ) thread OnPlayerRespawned_Threaded( player ) } void function OnPlayerRespawned_Threaded( entity player ) { // bit of a hack, need to rework earnmeter code to have better support for completely disabling it // rn though this just waits for earnmeter code to set the mode before we set it back WaitFrame() if ( IsValid( player ) ) PlayerEarnMeter_SetMode( player, eEarnMeterMode.DISABLED ) } void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) { if ( !victim.IsPlayer() || !attacker.IsPlayer() || GetGameState() != eGameState.Playing ) return if ( attacker == victim ) // suicide { string message = victim.GetPlayerName() + " committed suicide." foreach ( entity player in GetPlayerArray() ) SendHudMessage( player, message, -1, 0.4, 255, 0, 0, 0, 0, 3, 0.15 ) DeRank( victim ) } else { if ( DamageInfo_GetDamageSourceIdentifier( damageInfo ) != eDamageSourceId.melee_pilot_emptyhanded ) { float percentageReward = GetCurrentPlaylistVarFloat( "gg_kill_reward", 1.0 ) string scoreEvent = "KillPilot" if ( DamageInfo_GetDamageSourceIdentifier( damageInfo ) == eDamageSourceId.human_execution ) { string message = victim.GetPlayerName() + " got executed." foreach ( entity player in GetPlayerArray() ) SendHudMessage( player, message, -1, 0.4, 255, 0, 0, 0, 0, 3, 0.15 ) DeRank( victim ) percentageReward = GetCurrentPlaylistVarFloat( "gg_execution_reward", 1.0 ) scoreEvent = "Execution" } Reward( attacker, victim, scoreEvent, percentageReward ) } } table alreadyAssisted foreach( DamageHistoryStruct attackerInfo in victim.e.recentDamageHistory ) { if ( !IsValid( attackerInfo.attacker ) || !attackerInfo.attacker.IsPlayer() || attackerInfo.attacker == victim ) continue if ( attackerInfo.attacker != attacker && !( attackerInfo.attacker.GetEncodedEHandle() in alreadyAssisted ) ) { if ( attackerInfo.damageSourceId != eDamageSourceId.melee_pilot_emptyhanded ) { alreadyAssisted[attackerInfo.attacker.GetEncodedEHandle()] <- true Reward( attackerInfo.attacker, victim, "PilotAssist", GetCurrentPlaylistVarFloat( "gg_assist_reward", 0.0 ) ) } } } } void function Reward( entity player, entity victim, string scoreEvent, float percentageReward ) { percentageReward = clamp(percentageReward, 0.0, 1.0) Sv_GGEarnMeter_AddPercentage( player, percentageReward ) Remote_CallFunction_NonReplay( player, "ServerCallback_ScoreEvent", GetScoreEvent(scoreEvent).eventId, 0, eEventDisplayType.MEDAL, victim.GetEncodedEHandle(), 0.0, percentageReward) } void function DeRank( entity player ) { Sv_GGEarnMeter_SetPercentage( player, 0.0 ) if ( GameRules_GetTeamScore( player.GetTeam() ) != 0 ) { AddTeamScore( player.GetTeam(), -1 ) // get absolutely fucking destroyed lol player.AddToPlayerGameStat( PGS_ASSAULT_SCORE, -1 ) UpdateLoadout( player ) } } bool function OnGGEarnMeterFilled( entity player ) { AddTeamScore( player.GetTeam(), 1 ) player.AddToPlayerGameStat( PGS_ASSAULT_SCORE, 1 ) UpdateLoadout( player ) int currentScore = GameRules_GetTeamScore( player.GetTeam() ) int maxScore = GetGunGameWeapons().len() return currentScore >= maxScore } void function UpdateLoadout( entity player ) { // todo: honestly, this should be reworked to use PilotLoadoutDefs instead of directly modifying weapons and shit int currentWeaponIndex = GameRules_GetTeamScore( player.GetTeam() ) array weapons = GetGunGameWeapons() if ( currentWeaponIndex >= weapons.len() ) currentWeaponIndex = weapons.len() - 1 if ( currentWeaponIndex > weapons.len() - 3 ) // play end of game music for special or last few weapons PlayMusicToAll( eMusicPieceID.LEVEL_LAST_MINUTE ) // this *shouldn't* overlap if done multiple times GunGameWeapon weapon = weapons[ currentWeaponIndex ] foreach ( entity weapon in player.GetMainWeapons() ) player.TakeWeaponNow( weapon.GetWeaponClassName() ) foreach ( entity weapon in player.GetOffhandWeapons() ) player.TakeWeaponNow( weapon.GetWeaponClassName() ) if ( weapon.offhandSlot != -1 ) { player.GiveOffhandWeapon( weapon.weapon, weapon.offhandSlot, weapon.mods ) player.GiveOffhandWeapon( "melee_pilot_emptyhanded", OFFHAND_MELEE, [ "allow_as_primary" ] ) player.SetActiveWeaponByName( "melee_pilot_emptyhanded" ) // Let the player use the melee in the primary slot, and then force equip it. Effectively gives them an empty hand. } else { player.GiveWeapon( weapon.weapon, weapon.mods ) player.GiveOffhandWeapon( "melee_pilot_emptyhanded", OFFHAND_MELEE ) } } void function OnWinnerDetermined() { SetRespawnsEnabled( false ) SetKillcamsEnabled( false ) }