GameModeManager.cs

Manager component for game modes, handles King of the Hill scoring and a Sudden Death state. It awards periodic points to the player standing in the zone, detects trigger enter/exit to track the zone owner, checks arena shrinker to enable sudden death, and exposes a force multiplier while sudden death is active.

NetworkingFile Access
using Sandbox;
using System;
using System.Linq;

public sealed class GameModeManager : Component, Component.ITriggerListener
{
	public static GameModeManager Instance { get; private set; }

	[Property] public bool EnableKingOfTheHill { get; set; } = true;
	[Property] public int PointsPerSecond { get; set; } = 2;
	[Property] public float ZoneCheckInterval { get; set; } = 1.0f;

	[Property] public bool EnableSuddenDeath { get; set; } = true;
	[Property] public float SuddenDeathThresholdTime { get; set; } = 20f;
	[Property] public float SuddenDeathForceMultiplier { get; set; } = 2.5f;

	public bool IsSuddenDeathActive { get; private set; } = false;

	private TimeSince _timeSinceZoneTick;
	private GameObject _currentZoneOwner;

	protected override void OnStart()
	{
		Instance = this;
	}

	protected override void OnUpdate()
	{
		if ( EnableSuddenDeath && !IsSuddenDeathActive )
		{
			CheckSuddenDeathCondition();
		}

		if ( EnableKingOfTheHill && _timeSinceZoneTick >= ZoneCheckInterval )
		{
			_timeSinceZoneTick = 0;
			AwardHillPoints();
		}
	}

	private void CheckSuddenDeathCondition()
	{
		var shrinker = Scene.GetAllComponents<ArenaShrinker>().FirstOrDefault();
		if ( shrinker.IsValid() && shrinker.TimeRemaining <= SuddenDeathThresholdTime && shrinker.TimeRemaining > 0f )
		{
			TriggerSuddenDeath();
		}
	}

	public void TriggerSuddenDeath()
	{
		IsSuddenDeathActive = true;

		CameraJuice.Instance?.Shake( 25f );

		if ( Killfeed.Instance != null )
		{
			Killfeed.Instance.AddEntry( "СИСТЕМА", "ВСЕ ИГРОКИ", "ВНЕЗАПНАЯ СМЕРТЬ!" );
		}

		Log.Info( "[GameModeManager] Активирован режим SUDDEN DEATH!" );
	}

	public void OnTriggerEnter( Collider other )
	{
		var root = other.GameObject.Root;
		if ( root.Components.Get<PlayerHealth>().IsValid() )
		{
			_currentZoneOwner = root;
		}
	}

	public void OnTriggerExit( Collider other )
	{
		var root = other.GameObject.Root;
		if ( _currentZoneOwner == root )
		{
			_currentZoneOwner = null;
		}
	}

	private void AwardHillPoints()
	{
		if ( _currentZoneOwner.IsValid() )
		{
			var health = _currentZoneOwner.Components.Get<PlayerHealth>();
			if ( health.IsValid() && !health.IsDead )
			{
				if ( !_currentZoneOwner.IsProxy && ScoreManager.Instance != null )
				{
					ScoreManager.Instance.AddScore( PointsPerSecond );
				}
			}
		}
	}

	public float GetForceMultiplier()
	{
		return IsSuddenDeathActive ? SuddenDeathForceMultiplier : 1.0f;
	}
}