{"TotalCount":198,"Files":[{"Ident":"wurstsoftware.koth","Path":"Assembly.cs","FileName":"Assembly.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"global using Sandbox;\r\nglobal using Sandbox.UI;\r\nglobal using System;\r\nglobal using System.Collections.Generic;\r\nglobal using System.Linq;\r\n"},{"Ident":"wurstsoftware.koth","Path":"Damage/DamageManager.cs","FileName":"DamageManager.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"using Sandbox;\r\nusing Sandbox.Diagnostics;\r\nusing Sandbox.Events;\r\nusing Sandbox.Utility;\r\nusing System.ComponentModel.DataAnnotations;\r\nusing static Sandbox.PhysicsContact;\r\n\r\nnamespace KOTH;\r\n\r\n// TODO : rename health manager\r\npublic sealed class DamageManager : SingletonComponent\u003CDamageManager\u003E,\r\n\tIGameEventHandler\u003CDamageRequestEvent\u003E,\r\n\tIGameEventHandler\u003CHealingRequestEvent\u003E\r\n{\r\n\t[Property] public SoundEvent HitSound { get; set; }\r\n\r\n\t// special bool zone\r\n\t[Property] public bool KnockbackOnly { get; private set; } = false;\r\n\t[Property] public bool IgnoreTeams { get; private set; } = false;\r\n\r\n\tconst float SelfDamageMultiplyer = 0.25f;\r\n\r\n\t/////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n\tpublic void OnGameEvent(HealingRequestEvent EventArgs)\r\n\t{\r\n\t\tvar HealingRequest = EventArgs.HealingRequest;\r\n\t\tif (!HealingRequest.IsValid())\r\n\t\t{\r\n\t\t\tLog.Warning($\u0022tried to parse HealingRequestEvent that is not valid {EventArgs} {this}\u0022);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tServerInflictHealing(HealingRequest);\r\n\t}\r\n\r\n\tpublic void OnGameEvent(DamageRequestEvent EventArgs)\r\n\t{\r\n\t\tvar DamageRequest = EventArgs.DamageRequest;\r\n\t\tif (!DamageRequest.IsValid())\r\n\t\t{\r\n\t\t\tLog.Warning($\u0022tried to parse DamageRequestEvent that is not valid {EventArgs} {this}\u0022);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// tell server to do damage from request\r\n\t\tServerInflictDamageToPlayer(DamageRequest);\r\n\t}\r\n\r\n\t/////////////////////////////////////////////////////////////////////////////////////////////\r\n\t// host only broadcasts\r\n\t/////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n\t[Rpc.Host]\r\n\tprivate void ServerInflictDamageToPlayer(FDamageRequest DamageRequest)\r\n\t{\r\n\t\tAssert.True(Networking.IsHost);\r\n\r\n\t\tvar DamageOrigin = DamageRequest.DamageOrigin;\r\n\t\tvar TargetDamageComponent = DamageRequest.TargetDamageComponent;\r\n\t\tvar AttackerPlayerPawn = DamageRequest.AttackerPlayerPawn;\r\n\t\tvar Damage = DamageRequest.BaseDamage;\r\n\r\n\t\tif (!TargetDamageComponent.IsValid() || TargetDamageComponent.Health \u003C= 0)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar TargetPlayerPawn = DamageRequest.TargetDamageComponent.GetComponent\u003CPlayerPawn\u003E();\r\n\r\n\t\t// we\u0027ve taken damage without an attacker pawn, apply \u0026 return early ///////////////////\r\n\t\tif (!AttackerPlayerPawn.IsValid())\r\n\t\t{\r\n\t\t\tFDamageTaken EnvDamageTaken = new()\r\n\t\t\t{\r\n\t\t\t\tVictimGameObject = TargetDamageComponent.GameObject,\r\n\t\t\t\tAssumedVictimPlayerPawn = TargetPlayerPawn,\r\n\t\t\t\tVictimPlayerState = GameUtils.GetPlayerState(TargetPlayerPawn?.Id),\r\n\r\n\t\t\t\tDamage = Damage,\r\n\t\t\t\tDamageLocation = DamageOrigin,\r\n\t\t\t\tDamageType = DamageRequest.DamageType,\r\n\t\t\t\tIsDummyDamage = TargetPlayerPawn.IsValid() \u0026\u0026 TargetPlayerPawn.IsDummy,\r\n\t\t\t};\r\n\r\n\t\t\tTargetDamageComponent.TakeDamage(EnvDamageTaken);\r\n\t\t\treturn; // NOTE : early return\r\n\t\t}\r\n\r\n\t\t// team check //////////////////////////////////////////////////////////////////////////////////////\r\n\t\tif (!IgnoreTeams)\r\n\t\t{\r\n\t\t\tif (TargetDamageComponent.Team == AttackerPlayerPawn.Team \u0026\u0026 TargetPlayerPawn != AttackerPlayerPawn)\r\n\t\t\t{\r\n\t\t\t\treturn; // NOTE : early return\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar TargetCenter = DamageRequest.TargetOrigin;\r\n\r\n\t\t// calculate damage ///////////////////////////////////////////\r\n\t\tif (DamageRequest.DamageFalloffType != EDamageFalloffType.None)\r\n\t\t{\r\n\t\t\tvar TargetToImpactDistance = TargetCenter.Distance(DamageOrigin);\r\n\t\t\tvar TargetToAttackerDistance = TargetCenter.Distance(AttackerPlayerPawn.CenterPosition);\r\n\r\n\t\t\tfloat MaxDamage = Damage;\r\n\t\t\tif (DamageRequest.DamageType == EDamageType.Projectile \u0026\u0026 !DamageRequest.DirectImpact)\r\n\t\t\t{\r\n\t\t\t\tvar DamageDistanceLerp = TargetToImpactDistance / DamageRequest.MaxDamageImpactDistance;\r\n\t\t\t\tMaxDamage = MathX.Lerp(MaxDamage, MaxDamage * 0.5f, DamageDistanceLerp);\r\n\t\t\t}\r\n\r\n\t\t\tfloat MinDamage = MaxDamage * 0.33f;\r\n\t\t\tfloat DamageLerp = TargetToAttackerDistance / 1600f;\r\n\r\n\t\t\tif (DamageRequest.DamageFalloffType == EDamageFalloffType.Falloff)\r\n\t\t\t{\r\n\t\t\t\tDamage = MathX.Lerp(MaxDamage, MinDamage, DamageLerp).FloorToInt();\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tDamage = MathX.Lerp(MinDamage, MaxDamage, DamageLerp).FloorToInt();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\t\t// knockback ////////////////\r\n\t\tvar Knockback = Vector3.Zero; \r\n\t\tif (TargetPlayerPawn.IsValid())\r\n\t\t{\r\n\t\t\tvar DirectionVec = (TargetCenter - DamageOrigin).Normal;\r\n\t\t\tvar CrouchFactor = TargetPlayerPawn.IsCrouching ? 62 : 82;\r\n\t\t\tvar KBStrength = DamageRequest.BaseKnockbackStrength;\r\n\t\t\tif (!TargetPlayerPawn.IsGrounded \u0026\u0026 TargetPlayerPawn == AttackerPlayerPawn)\r\n\t\t\t{\r\n\t\t\t\tKBStrength *= 1.33f;\r\n\t\t\t}\r\n\r\n\t\t\tvar KnockbackFactor = Damage * (KBStrength / CrouchFactor);\r\n\r\n\t\t\tKnockback = DirectionVec * KnockbackFactor * TargetPlayerPawn.WeightFactor;\r\n\t\t\tTargetPlayerPawn.DoKnockback(Knockback);\r\n\t\t}\r\n\r\n\t\tif (KnockbackOnly)\r\n\t\t{\r\n\t\t\treturn; // !\r\n\t\t}\r\n\r\n\t\t// deal the damage /////////////////////////////////////////\r\n\t\tbool WasSelfDamage = TargetPlayerPawn == AttackerPlayerPawn;\r\n\t\tif (WasSelfDamage \u0026\u0026 DamageRequest.DoesLessSelfDamage)\r\n\t\t{\r\n\t\t\tDamage = (Damage * SelfDamageMultiplyer).FloorToInt();\r\n\t\t}\r\n\r\n\t\tFDamageTaken DamageTaken = new()\r\n\t\t{\r\n\t\t\tVictimGameObject = TargetDamageComponent.GameObject,\r\n\r\n\t\t\tAssumedAttackerPlayerPawn = AttackerPlayerPawn,\r\n\t\t\tAssumedVictimPlayerPawn = TargetPlayerPawn,\r\n\t\t\tAttackerPlayerState = GameUtils.GetPlayerState(AttackerPlayerPawn?.Id),\r\n\t\t\tVictimPlayerState = GameUtils.GetPlayerState(TargetPlayerPawn?.Id),\r\n\r\n\t\t\tDamage = Damage,\r\n\t\t\tDamageLocation = DamageOrigin,\r\n\t\t\tDamageType = DamageRequest.DamageType,\r\n\t\t\tIsDummyDamage = TargetPlayerPawn.IsValid() \u0026\u0026 TargetPlayerPawn.IsDummy,\r\n\t\t};\r\n\r\n\t\tTargetDamageComponent.TakeDamage(DamageTaken);\r\n\r\n\t\tLog.Info($\u0022{Damage}:{Knockback.Length:0.0} damage:kb has been taken {AttackerPlayerPawn.DisplayName}:{AttackerPlayerPawn.Health}\u0022 \u002B\r\n\t\t\t$\u0022 -\u003E {TargetPlayerPawn?.DisplayName}:{TargetDamageComponent.Health}\u0022);\r\n\t}\r\n\r\n\t[Rpc.Host]\r\n\tprivate void ServerInflictHealing(FHealingRequest HealingRequest)\r\n\t{\r\n\t\tAssert.True(Networking.IsHost);\r\n\r\n\t\tif (!HealingRequest.TargetDamageComponent.IsValid())\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// we do it the other way round to the damage here :)\r\n\t\tHealingRequest.TargetDamageComponent.Heal(HealingRequest);\r\n\t}\r\n\r\n\t[Rpc.Broadcast(NetFlags.HostOnly)]\r\n\tprivate void ClientDidDamage(PlayerState PlayerState, PlayerPawn PlayerPawn, float Damage, bool WasSelfDamage)\r\n\t{\r\n\t\tif (!WasSelfDamage)\r\n\t\t{\r\n\t\t\tvar HitSound = Sound.Play(this.HitSound, PlayerPawn.WorldPosition);\r\n\t\t\tif (!HitSound.IsValid()) return;\r\n\r\n\t\t\tHitSound.Volume = 0.5f;\r\n\t\t\tHitSound.Pitch = MathX.Lerp(1.2f, 0.7f, Damage * .02f);\r\n\t\t\tHitSound.ListenLocal = true;\r\n\t\t}\r\n\t}\r\n}\r\n"},{"Ident":"wurstsoftware.koth","Path":"ui/playerhud/components/stickyoverlay.razor.scss","FileName":"stickyoverlay.razor.scss","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"@import \u0022/UI/Styles/Theme.scss\u0022;\r\n\r\nStickyOverlay {\r\n    * {\r\n        position: absolute;\r\n    }\r\n\r\n    .charge {\r\n        position: absolute;\r\n        top: 80%;\r\n        left: 50%;\r\n        width: 200px;\r\n        height: 8px;\r\n        background-color: rgba(0, 0, 0, 0.6);\r\n\r\n        .charge-fill {\r\n            height: 100%;\r\n            background-color: whitesmoke;\r\n        }\r\n\r\n        transform: translateX(-48px);\r\n    }\r\n\r\n    .stickies {\r\n        position: absolute;\r\n        top: 75%;\r\n        left: 70%;\r\n        color: white;\r\n        font-size: 36px;\r\n    }\r\n}"},{"Ident":"wurstsoftware.koth","Path":"GameEvent.cs","FileName":"GameEvent.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"using System;\r\nusing System.Collections.Generic;\r\nusing System.Collections.Immutable;\r\nusing System.Linq;\r\n\r\nnamespace Sandbox.Events;\r\n\r\n/// \u003Csummary\u003E\r\n/// Interface for event payloads that can be listened for by \u003Csee cref=\u0022IGameEventHandler{T}\u0022/\u003Es.\r\n/// \u003C/summary\u003E\r\npublic interface IGameEvent { }\r\n\r\n/// \u003Csummary\u003E\r\n/// Interface for components that handle game events with a payload of type \u003Csee cref=\u0022T\u0022/\u003E.\r\n/// \u003C/summary\u003E\r\n/// \u003Ctypeparam name=\u0022T\u0022\u003EEvent payload type.\u003C/typeparam\u003E\r\npublic interface IGameEventHandler\u003Cin T\u003E\r\n\twhere T : IGameEvent\r\n{\r\n\t/// \u003Csummary\u003E\r\n\t/// Called when an event with payload of type \u003Csee cref=\u0022T\u0022/\u003E is dispatched on a \u003Csee cref=\u0022GameObject\u0022/\u003E\r\n\t/// that contains this component, including on a descendant.\r\n\t/// \u003C/summary\u003E\r\n\t/// \u003Cparam name=\u0022eventArgs\u0022\u003EEvent payload.\u003C/param\u003E\r\n\tvoid OnGameEvent( T eventArgs );\r\n}\r\n\r\n/// \u003Csummary\u003E\r\n/// Helper for dispatching game events in a scene.\r\n/// \u003C/summary\u003E\r\npublic static class GameEvent\r\n{\r\n\tprivate static Dictionary\u003CType, IReadOnlyDictionary\u003CType, int\u003E\u003E HandlerOrderingCache { get; } = new();\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Notifies all \u003Csee cref=\u0022IGameEventHandler{T}\u0022/\u003E components that are within \u003Cparamref name=\u0022root\u0022/\u003E,\r\n\t/// with a payload of type \u003Ctypeparamref name=\u0022T\u0022/\u003E.\r\n\t/// \u003C/summary\u003E\r\n\tpublic static void Dispatch\u003CT\u003E( this GameObject root, T eventArgs )\r\n\t\twhere T : IGameEvent\r\n\t{\r\n\t\tvar handlers = (root is Scene scene\r\n\t\t\t? scene.GetAllComponents\u003CIGameEventHandler\u003CT\u003E\u003E() // I think this is more efficient?\r\n\t\t\t: root.Components.GetAll\u003CIGameEventHandler\u003CT\u003E\u003E())\r\n\t\t\t.ToArray();\r\n\r\n\t\tif ( !HandlerOrderingCache.TryGetValue( typeof(T), out var ordering ) || handlers.Any( x =\u003E !ordering.ContainsKey( x.GetType() ) ) )\r\n\t\t{\r\n\t\t\tordering = HandlerOrderingCache[typeof(T)] = GetHandlerOrdering\u003CT\u003E();\r\n\t\t}\r\n\r\n\t\tList\u003CException\u003E? exceptions = null;\r\n\r\n\t\tforeach ( var handler in handlers.OrderBy( x =\u003E ordering[x.GetType()] ) )\r\n\t\t{\r\n\t\t\ttry\r\n\t\t\t{\r\n\t\t\t\thandler.OnGameEvent( eventArgs );\r\n\t\t\t}\r\n\t\t\tcatch ( Exception e )\r\n\t\t\t{\r\n\t\t\t\texceptions ??= new();\r\n\t\t\t\texceptions.Add( e );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tswitch ( exceptions?.Count )\r\n\t\t{\r\n\t\t\tcase 1:\r\n\t\t\t\tLog.Error( exceptions[0] );\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase \u003E 1:\r\n\t\t\t\tLog.Error( new AggregateException( exceptions ) );\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static bool IsImplementingMethodName( string methodName )\r\n\t{\r\n\t\tif ( methodName == nameof(IGameEventHandler\u003CIGameEvent\u003E.OnGameEvent) )\r\n\t\t{\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn methodName.StartsWith( \u0022Sandbox.Events.IGameEventHandler\u003C\u0022 ) \u0026\u0026 methodName.EndsWith( \u0022\u003E.OnGameEvent\u0022 );\r\n\t}\r\n\r\n\tprivate static MethodDescription? GetImplementation\u003CT\u003E( TypeDescription type )\r\n\t{\r\n\t\tforeach ( var method in type.Methods )\r\n\t\t{\r\n\t\t\tif ( method.IsStatic ) continue;\r\n\t\t\tif ( method.Parameters.Length != 1 ) continue;\r\n\t\t\tif ( method.Parameters[0].ParameterType != typeof( T ) ) continue;\r\n\r\n\t\t\tif ( !IsImplementingMethodName( method.Name ) ) continue;\r\n\r\n\t\t\treturn method;\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static IReadOnlyDictionary\u003CType, int\u003E GetHandlerOrdering\u003CT\u003E()\r\n\t\twhere T : IGameEvent\r\n\t{\r\n\t\tvar types = TypeLibrary.GetTypes\u003CIGameEventHandler\u003CT\u003E\u003E().ToArray();\r\n\t\tvar helper = new SortingHelper( types.Length );\r\n\r\n\t\tfor ( var i = 0; i \u003C types.Length; \u002B\u002Bi )\r\n\t\t{\r\n\t\t\tvar type = types[i];\r\n\t\t\tvar method = GetImplementation\u003CT\u003E( type );\r\n\r\n\t\t\tif ( method is null )\r\n\t\t\t{\r\n\t\t\t\tLog.Warning( $\u0022Can\u0027t find {nameof( IGameEventHandler\u003CT\u003E )}\u003C{typeof( T ).Name}\u003E implementation in {type.Name}!\u0022 );\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tforeach ( var attrib in method.Attributes )\r\n\t\t\t{\r\n\t\t\t\tswitch ( attrib )\r\n\t\t\t\t{\r\n\t\t\t\t\tcase EarlyAttribute:\r\n\t\t\t\t\t\thelper.AddFirst( i );\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase LateAttribute:\r\n\t\t\t\t\t\thelper.AddLast( i );\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase IBeforeAttribute before:\r\n\t\t\t\t\t\tfor ( var j = 0; j \u003C types.Length; \u002B\u002Bj )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tif ( i == j ) continue;\r\n\r\n\t\t\t\t\t\t\tvar other = types[j];\r\n\r\n\t\t\t\t\t\t\tif ( before.Type.IsAssignableFrom( other.TargetType ) )\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\thelper.AddConstraint( i, j );\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase IAfterAttribute after:\r\n\t\t\t\t\t\tfor ( var j = 0; j \u003C types.Length; \u002B\u002Bj )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tif ( i == j ) continue;\r\n\r\n\t\t\t\t\t\t\tvar other = types[j];\r\n\r\n\t\t\t\t\t\t\tif ( after.Type.IsAssignableFrom( other.TargetType ) )\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\thelper.AddConstraint( j, i );\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar ordering = new List\u003Cint\u003E();\r\n\r\n\t\tif ( !helper.Sort( ordering, out var invalid ) )\r\n\t\t{\r\n\t\t\tLog.Error( $\u0022Invalid event ordering constraint between {types[invalid.EarlierIndex].Name} and {types[invalid.LaterIndex].Name}!\u0022 );\r\n\t\t\treturn ImmutableDictionary\u003CType, int\u003E.Empty;\r\n\t\t}\r\n\r\n\t\treturn Enumerable.Range( 0, ordering.Count )\r\n\t\t\t.ToImmutableDictionary( i =\u003E types[ordering[i]].TargetType, i =\u003E i );\r\n\t}\r\n}\r\n\r\npublic delegate void GameEventAction\u003Cin T\u003E( T eventArgs )\r\n\twhere T : IGameEvent;\r\n\r\n/// \u003Csummary\u003E\r\n/// Base class for components that expose game events to Action Graph.\r\n/// \u003C/summary\u003E\r\npublic abstract class GameEventComponent\u003CT\u003E : Component, IGameEventHandler\u003CT\u003E\r\n\twhere T : IGameEvent\r\n{\r\n\t/// \u003Csummary\u003E\r\n\t/// Action invoked when the \u003Ctypeparamref name=\u0022T\u0022/\u003E event is dispatched.\r\n\t/// \u003C/summary\u003E\r\n\t[Property]\r\n\tpublic GameEventAction\u003CT\u003E? OnEvent { get; set; }\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// If this component is within a state machine, optional state to transition\r\n\t/// to when this event is dispatched.\r\n\t/// \u003C/summary\u003E\r\n\t[Property]\r\n\tpublic StateComponent? NextState { get; set; }\r\n\r\n\tvoid IGameEventHandler\u003CT\u003E.OnGameEvent( T eventArgs )\r\n\t{\r\n\t\tOnEvent?.Invoke( eventArgs );\r\n\r\n\t\tif ( NextState is not null )\r\n\t\t{\r\n\t\t\tComponents.GetInAncestorsOrSelf\u003CStateMachineComponent\u003E()?.Transition( NextState );\r\n\t\t}\r\n\t}\r\n}\r\n"},{"Ident":"wurstsoftware.koth","Path":"GameMode/AudioComponent.cs","FileName":"AudioComponent.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"using System.Threading.Tasks;\r\n\r\nnamespace KOTH;\r\n\r\n/// \u003Csummary\u003E\r\n/// Manages sound playback within the game, including playing sounds globally or for specific teams,\r\n/// updating sound states, and handling active sound instances.\r\n/// \u003C/summary\u003E\r\n/// \u003Cremarks\u003E\r\n/// This component is responsible for managing the lifecycle of sounds,\r\n/// including their initiation, positional updates, and cleanup. It provides\r\n/// methods for playing sounds either globally or targeted to specific teams\r\n/// and maintains references to active sound handles.\r\n/// \u003C/remarks\u003E\r\npublic sealed class AudioComponent : SingletonComponent\u003CAudioComponent\u003E\r\n{\r\n\t/// \u003Csummary\u003E\r\n\t/// A collection of sound events that have been stopped during the audio handling process.\r\n\t/// This list is managed internally and is primarily used to track and clean up finished or stopped sounds,\r\n\t/// ensuring efficient audio management within the system.\r\n\t/// \u003C/summary\u003E\r\n\t[Property]\r\n\tprivate List\u003CFSound\u003E StoppedSounds { get; set; }\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// A mapping between sound events and their corresponding sound handles used during audio processing.\r\n\t/// This dictionary is utilized to associate each active sound event with its control and state information,\r\n\t/// enabling management of sound playback, updates, and cleanup within the system.\r\n\t/// \u003C/summary\u003E\r\n\t[Property]\r\n\tprivate Dictionary\u003CFSound, SoundHandle\u003E SoundHandles { get; set; }\r\n\r\n\tprotected override void OnAwake()\r\n\t{\r\n\t\tbase.OnAwake();\r\n\t\tSoundHandles = new Dictionary\u003CFSound, SoundHandle\u003E();\r\n\t\tStoppedSounds = new List\u003CFSound\u003E();\r\n\t}\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Plays a specified sound for all players on the given team.\r\n\t/// \u003C/summary\u003E\r\n\t/// \u003Cparam name=\u0022soundEvent\u0022\u003EThe sound event to be played.\u003C/param\u003E\r\n\t/// \u003Cparam name=\u0022team\u0022\u003EThe team for which the sound will be played.\u003C/param\u003E\r\n\tpublic void PlaySoundForTeam(FSound soundEvent, Team team)\r\n\t{\r\n\t\tusing (Rpc.FilterInclude(GameUtils.GetPlayers(team).Select(x =\u003E x.Connection)))\r\n\t\t{\r\n\t\t\tPlaySound(soundEvent);\r\n\t\t}\r\n\t}\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Plays a specified sound globally for all players in the game.\r\n\t/// \u003C/summary\u003E\r\n\t/// \u003Cparam name=\u0022soundEvent\u0022\u003EThe sound event to be played.\u003C/param\u003E\r\n\t[Rpc.Broadcast]\r\n\tpublic void PlaySound(FSound soundEvent)\r\n\t{\r\n\t\tvar alreadyPlaying = Instance.SoundHandles.Any(x =\u003E x.Key.Owner.Id == soundEvent.Owner.Id || x.Key.SoundId == soundEvent.SoundId);\r\n\t\tif (alreadyPlaying) return;\r\n\t\tLog.Info(\u0022Playing sound \u0022 \u002B soundEvent.SoundId);\r\n\t\tvar handle = Sound.Play(soundEvent.SoundEvent, soundEvent.Position);\r\n\t\tInstance.SoundHandles.Add(soundEvent, handle);\r\n\t}\r\n\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Stops the playback of a specified sound in the game.\r\n\t/// \u003C/summary\u003E\r\n\t/// \u003Cparam name=\u0022soundEvent\u0022\u003EThe sound event to be stopped.\u003C/param\u003E\r\n\t[Rpc.Broadcast]\r\n\tpublic void StopSound(FSound soundEvent)\r\n\t{\r\n\t\tvar soundHandle = Instance.SoundHandles.FirstOrDefault(x =\u003E x.Key.SoundId == soundEvent.SoundId);\r\n\t\tvar alreadyRemoving = Instance.StoppedSounds.Any(x =\u003E x.SoundId == soundEvent.SoundId);\r\n\t\tif(soundHandle.Value == null || alreadyRemoving) return;\r\n\t\tsoundHandle.Value.Stop();\r\n\t\tInstance.StoppedSounds.Add(soundHandle.Key);\r\n\t}\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Determines whether the specified sound event is currently playing.\r\n\t/// \u003C/summary\u003E\r\n\t/// \u003Cparam name=\u0022soundEvent\u0022\u003EThe sound event to check.\u003C/param\u003E\r\n\t/// \u003Creturns\u003ETrue if the sound event is currently playing; otherwise, false.\u003C/returns\u003E\r\n\tpublic Boolean IsPlayingSound(FSound soundEvent)\r\n\t{\r\n\t\treturn Instance.SoundHandles.Any(x =\u003E x.Key.SoundId == soundEvent.SoundId);\r\n\t}\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Updates the positions of active sounds and removes references to completed or invalid ones.\r\n\t/// \u003C/summary\u003E\r\n\t/// \u003Cremarks\u003E\r\n\t/// This method iterates through all active sound handles. If a sound should update its position,\r\n\t/// its position is recalculated. Stopped, finished, or invalid sound handles are marked for cleanup\r\n\t/// and later removed.\r\n\t/// \u003C/remarks\u003E\r\n\tpublic void SoundTick()\r\n\t{\r\n\t\tforeach (var soundHandle in Instance.SoundHandles)\r\n\t\t{\r\n\t\t\tif (!soundHandle.Key.Owner.IsValid())\r\n\t\t\t{\r\n\t\t\t\tsoundHandle.Value.Stop();\r\n\t\t\t\tInstance.StoppedSounds.Add(soundHandle.Key);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (soundHandle is { Value: not null, Value.Finished: false, Key.UpdatePosition: true, }\r\n\t\t\t\t\u0026\u0026 soundHandle.Value.Position != soundHandle.Key.Owner.WorldPosition\r\n\t\t\t\t)\r\n\t\t\t{\r\n\t\t\t\tsoundHandle.Value.Position = soundHandle.Key.Owner.WorldPosition;\r\n\t\t\t}\r\n\r\n\t\t\tif (!soundHandle.Value.IsValid() || soundHandle.Value.Finished || soundHandle.Value.IsStopped)\r\n\t\t\t{\r\n\t\t\t\tInstance.StoppedSounds.Add(soundHandle.Key);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tCleanUpStoppedSounds();\r\n\t}\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Cleans up the references to sounds that have been stopped, finished, or are no longer valid.\r\n\t/// \u003C/summary\u003E\r\n\t/// \u003Cremarks\u003E\r\n\t/// This method iterates through the list of stopped sounds, attempting to remove their corresponding entries\r\n\t/// from the active sound handles dictionary. Logs errors or successful removals as appropriate, then clears\r\n\t/// the list of stopped sounds.\r\n\t/// \u003C/remarks\u003E\r\n\tprivate void CleanUpStoppedSounds()\r\n\t{\r\n\t\tforeach (var soundHandle in Instance.StoppedSounds)\r\n\t\t{\r\n\t\t\tInstance.SoundHandles.Remove(soundHandle);\r\n\t\t}\r\n\r\n\t\tInstance.StoppedSounds.Clear();\r\n\t}\r\n}\r\n\r\n/// \u003Csummary\u003E\r\n/// Represents a sound event within the game.\r\n/// This struct is used to encapsulate data necessary to play a sound, including its location,\r\n/// the associated sound event, and the owning component triggering the sound.\r\n/// \u003C/summary\u003E\r\npublic struct FSound : IEquatable\u003CFSound\u003E\r\n{\r\n\t/// \u003Csummary\u003E\r\n\t/// Represents the underlying data or identity of a playable sound within the audio system.\r\n\t/// \u003C/summary\u003E\r\n\tpublic SoundEvent SoundEvent { get; init; }\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Represents the 3D position in the game world where the sound event should occur.\r\n\t/// \u003C/summary\u003E\r\n\tpublic Vector3 Position { get; init; }\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// A unique identifier for a specific sound event within the game.\r\n\t/// This identifier is automatically generated upon the creation of a sound event and is used\r\n\t/// to distinguish and manage individual sound instances effectively.\r\n\t/// \u003C/summary\u003E\r\n\tpublic Guid SoundId { get; init; }\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// The component responsible for triggering the sound event in the game.\r\n\t/// \u003C/summary\u003E\r\n\tpublic Component Owner { get; init; }\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Indicates whether the position of the sound should be updated dynamically.\r\n\t/// \u003C/summary\u003E\r\n\t/// \u003Cremarks\u003E\r\n\t/// If set to true, the sound\u0027s position is recalculated during the sound management process\r\n\t/// to match the world position of its owning component. This is particularly useful for\r\n\t/// sounds tied to moving objects or entities within the game world. If false, the sound\r\n\t/// remains static at its initial position.\r\n\t/// \u003C/remarks\u003E\r\n\tpublic bool UpdatePosition { get; init; } = false;\r\n\r\n\tpublic FSound(SoundEvent soundEvent, Vector3 position, Component owner, bool updatePosition = false)\r\n\t{\r\n\t\tSoundEvent = soundEvent;\r\n\t\tPosition = position;\r\n\t\tOwner = owner;\r\n\t\tUpdatePosition = updatePosition;\r\n\t\tSoundId = Guid.NewGuid();\r\n\t}\r\n\r\n\tpublic bool Equals(FSound other)\r\n\t{\r\n\t\treturn other.SoundId == SoundId;\r\n\t}\r\n\r\n\tpublic override bool Equals(object obj)\r\n\t{\r\n\t\treturn obj is FSound other \u0026\u0026 Equals(other);\r\n\t}\r\n\r\n\tpublic override int GetHashCode()\r\n\t{\r\n\t\treturn HashCode.Combine(SoundEvent, UpdatePosition, SoundId);\r\n\t}\r\n}\r\n"},{"Ident":"wurstsoftware.koth","Path":"GameMode/ClassList.cs","FileName":"ClassList.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"using Sandbox;\r\n\r\nnamespace KOTH;\r\n\r\npublic sealed class ClassList : Component\r\n{\r\n\t[Property] public List\u003CCharacterDefinition\u003E ClassDefinitions { get; private set; }\r\n}\r\n"},{"Ident":"wurstsoftware.koth","Path":"GameMode/Rules/Koth/HillController.cs","FileName":"HillController.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"using Sandbox;\r\nusing Sandbox.Events;\r\n\r\nnamespace KOTH;\r\n\r\npublic sealed class HillController : Component, IGameEventHandler\u003CEnterStateEvent\u003E\r\n{\r\n\t[Property] public bool HillEnabled { get; set; } = false;\r\n\t[Sync(SyncFlags.FromHost)] public Hill ActiveHill { get; private set; }\r\n\r\n\tvoid IGameEventHandler\u003CEnterStateEvent\u003E.OnGameEvent(EnterStateEvent eventArgs)\r\n\t{\r\n\t\tGetActiveHill()?.SetHillActive(HillEnabled);\r\n\t}\r\n\r\n\tpublic Hill GetActiveHill()\r\n\t{\r\n\t\tif (ActiveHill.IsValid())\r\n\t\t{\r\n\t\t\treturn ActiveHill;\r\n\t\t}\r\n\r\n\t\tforeach (var GameObject in Scene.GetAllObjects(true))\r\n\t\t{\r\n\t\t\tvar Hill = GameObject.Components.Get\u003CHill\u003E();\r\n\t\t\tif (Hill.IsValid())\r\n\t\t\t{\r\n\t\t\t\tActiveHill = Hill;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn ActiveHill;\r\n\t}\r\n}\r\n"},{"Ident":"wurstsoftware.koth","Path":"Player/PlayerPawn.Zones.cs","FileName":"PlayerPawn.Zones.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"\r\nnamespace KOTH;\r\n\r\n// tony: Not a huge fan of this, can\u0027t we be reacting to trigger events instead of tracing against spheres for every player every update?\r\n// or just do this on the local player, and tell the host about what zones they\u0027re in?\r\n// travis : I AGREE\r\npartial class PlayerPawn\r\n{\r\n\tprivate readonly List\u003CZone\u003E _zones = new();\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Which \u003Csee cref=\u0022Zone\u0022/\u003Es is the player currently standing in.\r\n\t/// \u003C/summary\u003E\r\n\tpublic IEnumerable\u003CZone\u003E Zones =\u003E _zones;\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Update which \u003Csee cref=\u0022Zone\u0022/\u003Es the player is standing in.\r\n\t/// \u003C/summary\u003E\r\n\tprivate void UpdateZones()\r\n\t{\r\n\t\t_zones.Clear();\r\n\t\t_zones.AddRange(Zone.GetAt(WorldPosition));\r\n\t}\r\n\r\n\tpublic T GetZone\u003CT\u003E()\r\n\t{\r\n\t\treturn Zones.Select(x =\u003E x.Components.Get\u003CT\u003E()).FirstOrDefault(x =\u003E x is not null);\r\n\t}\r\n}\r\n"},{"Ident":"wurstsoftware.koth","Path":"Player/State/PlayerState.Helpers.cs","FileName":"PlayerState.Helpers.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"using KOTH.UI;\r\nusing Sandbox;\r\nusing Sandbox.Diagnostics;\r\nusing Sandbox.Events;\r\nusing System.Collections.Generic;\r\n\r\nnamespace KOTH;\r\n\r\npublic partial class PlayerState\r\n{\r\n\t// TODO : create connection -\u003E player state map?\r\n\tpublic static PlayerState Local { get; private set; }\r\n\tpublic static bool IsPaused { get; set; }\r\n\r\n\tprotected override void OnUpdate()\r\n\t{\r\n\t\tbase.OnUpdate();\r\n\r\n\t\tCameraUtils.LocalTick();\r\n\r\n\t\tif (Input.EscapePressed)\r\n\t\t{\r\n\t\t\tInput.EscapePressed = false;\r\n\t\t\tIsPaused = !IsPaused;\r\n\t\t}\r\n\t}\r\n}\r\n"},{"Ident":"wurstsoftware.koth","Path":"Player/State/PlayerState.Spawning.cs","FileName":"PlayerState.Spawning.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"using KOTH.UI;\r\nusing Sandbox;\r\nusing Sandbox.Diagnostics;\r\nusing Sandbox.Events;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Xml.Linq;\r\n\r\nnamespace KOTH;\r\n\r\npublic struct FPlayerPawnDefinition\r\n{\r\n\tpublic FPlayerPawnDefinition()\r\n\t{\r\n\t}\r\n\r\n\tpublic CharacterDefinition CharacterDefinition { get; init; }\r\n\t// public PlayerState OwnerPlayerState { get; init; }\r\n\r\n\tpublic string Name { get; init; } = \u0022UNINITALIZED\u0022;\r\n\tpublic Team Team { get; init; } = Team.Unassigned;\r\n\tpublic bool IsDummy { get; init; } = false;\r\n\r\n\tpublic readonly bool IsValid()\r\n\t{\r\n\t\treturn CharacterDefinition.IsValid();\r\n\t}\r\n}\r\n\r\n//////////////////////////////////////////////////////////////////////////////////\r\n\r\n/*\r\n * State of the player pawn\r\n * menu when displaying a menu (true when first joining a lobby)\r\n * waitingforspawn when in a game \u0026 requestedcharacterdefinition is not null\r\n * alive when playing in game\r\n */\r\npublic enum EPlayerStateSpawningState\r\n{\r\n\tMainMenu,\r\n\tWaitingForSpawn,\r\n\tInstantSpawn,\r\n\tAlive,\r\n\tSpectating,\r\n}\r\n\r\n//////////////////////////////////////////////////////////////////////////////////\r\n\r\npublic partial class PlayerState\r\n{\r\n\t[Sync(SyncFlags.FromHost)/*, Change(nameof(OnPlayerStateSpawningStateChanged))*/] public EPlayerStateSpawningState PlayerStateSpawningState { get; private set; } = EPlayerStateSpawningState.MainMenu;\r\n\r\n\t//////////////////////////////////////////////////////////////////////////////////\r\n\r\n\t[Sync(SyncFlags.FromHost)] public float TimeTilAttemptedSpawn { get; private set; } = -1;\r\n\r\n\tpublic void SetTimeTilAttemptedSpawn(float TimeTilSpawn)\r\n\t{\r\n\t\tAssert.True(Networking.IsHost);\r\n\r\n\t\tTimeTilAttemptedSpawn = TimeTilSpawn;\r\n\t}\r\n\r\n\t//////////////////////////////////////////////////////////////////////////////////\r\n\r\n\t/*\r\n\t * NOTE : Sync will only care about the vaule given by an object\u0027s host, so bc this player state is owned \r\n\t * by the server the requested character def will never sync! this is the workaround for now..\r\n\t */\r\n\tpublic CharacterDefinition RequestedCharacterDefinition { get; private set; } = null;\r\n\r\n\tpublic void RequestCharacterDefinition(CharacterDefinition CharacterDefintionIn)\r\n\t{\r\n\t\tLog.Info($\u0022Requested Character {CharacterDefintionIn}\u0022);\r\n\r\n\t\tRequestedCharacterDefinition = CharacterDefintionIn;\r\n\r\n\t\t// TODO : actaully send a request\r\n\t\tHostSetCharacterDefinition(CharacterDefintionIn);\r\n\t}\r\n\r\n\t[Rpc.Host]\r\n\tprivate void HostSetCharacterDefinition(CharacterDefinition CharacterDefinition)\r\n\t{\r\n\t\tif (!CharacterDefinition.IsValid())\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tRequestedCharacterDefinition = CharacterDefinition;\r\n\r\n\t\t// if we come from the main menu we want to spawn instantly\r\n\t\tif (PlayerStateSpawningState == EPlayerStateSpawningState.MainMenu)\r\n\t\t{\r\n\t\t\tPlayerStateSpawningState = EPlayerStateSpawningState.InstantSpawn;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tPlayerStateSpawningState = EPlayerStateSpawningState.WaitingForSpawn;\r\n\t}\r\n\r\n\t//////////////////////////////////////////////////////////////////////////////////\r\n\r\n\t[Sync(SyncFlags.FromHost)] public Team Team { get; set; }\r\n\r\n\t//////////////////////////////////////////////////////////////////////////////////\r\n\r\n\tpublic void SpawnPlayerPawn(TeamSpawnPoint SpawnPoint)\r\n\t{\r\n\t\tAssert.True(Networking.IsHost);\r\n\r\n\t\tif (PlayerPawn.IsValid())\r\n\t\t{\r\n\t\t\tPlayerPawn.GameObject.Root.Destroy();\r\n\t\t\tPlayerPawn = null;\r\n\t\t\tLocalOnPlayerDeath();\r\n\r\n\t\t\tGameMode.Instance?.DestroySpawnZoneBlockers();\r\n\t\t}\r\n\r\n\t\tif (!SpawnPoint.IsValid())\r\n\t\t{\r\n\t\t\tLog.Warning($\u0022trying to spawn player {this} with invalid spawn point\u0022);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tSpawnPlayerPawn(Connection, SteamName, RequestedCharacterDefinition, SpawnPoint);\r\n\t}\r\n\r\n\r\n\t[Property] public GameObject DefaultPlayerPawnPrefab { get; private set; }\r\n\r\n\tprivate void OnPlayerPawnSpawn()\r\n\t{\r\n\t\tAssert.True(Networking.IsHost);\r\n\t\tAssert.True(PlayerPawn.IsValid());\r\n\r\n\t\tPlayerPawn.OnDeath \u002B= OnPlayerPawnDeath;\r\n\t\tPlayerStateSpawningState = EPlayerStateSpawningState.Alive;\r\n\r\n\t\tBroadcastPlayerSpawn(PlayerPawn);\r\n\t\t\r\n\t\tusing (Rpc.FilterInclude(Connection))\r\n\t\t{\r\n\t\t\tLocalPlayerSpawn(PlayerPawn);\r\n\t\t}\r\n\t}\r\n\t\r\n\t[Rpc.Host]\r\n\tprivate void SpawnPlayerPawn(Connection OwningConnection, string Name, CharacterDefinition CharacterDefinition, TeamSpawnPoint SpawnPoint)\r\n\t{\r\n\t\tAssert.True(Networking.IsHost);\r\n\t\tAssert.IsValid(SpawnPoint);\r\n\r\n\t\tLog.Info($\u0022attempting to spawn player {RequestedCharacterDefinition} for {OwningConnection}\u0022);\r\n\r\n\t\tvar SpawnPlayerPawnPrefab = DefaultPlayerPawnPrefab.Clone(SpawnPoint.GameObject.WorldTransform, null, true);\r\n\t\tSpawnPlayerPawnPrefab.Network.SetOrphanedMode(NetworkOrphaned.Destroy);\r\n\r\n\t\tvar SpawnPlayerPawnComponent = SpawnPlayerPawnPrefab.Components.Get\u003CPlayerPawn\u003E();\r\n\t\tAssert.NotNull(SpawnPlayerPawnComponent);\r\n\r\n\t\tvar TeamIn = Team; // :P\r\n\t\tFPlayerPawnDefinition PlayerPawnDefinition = new()\r\n\t\t{\r\n\t\t\tCharacterDefinition = RequestedCharacterDefinition,\r\n\t\t\tName = Name,\r\n\t\t\tTeam = TeamIn,\r\n\t\t};\r\n\r\n\t\tSpawnPlayerPawnComponent.SetPlayerPawnDefinition(PlayerPawnDefinition);\r\n\r\n\t\tif (!SpawnPlayerPawnPrefab.NetworkSpawn(OwningConnection))\r\n\t\t{\r\n\t\t\tSpawnPlayerPawnPrefab.Destroy();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tPlayerPawn = SpawnPlayerPawnComponent;\r\n\t\tOnPlayerPawnSpawn();\r\n\t}\r\n\r\n\tvoid OnPlayerPawnDeath()\r\n\t{\r\n\t\tAssert.True(Networking.IsHost);\r\n\r\n\t\tPlayerStateSpawningState = EPlayerStateSpawningState.WaitingForSpawn;\r\n\r\n\t\tusing (Rpc.FilterInclude(Connection))\r\n\t\t{\r\n\t\t\tLocalOnPlayerDeath();\r\n\t\t}\r\n\t}\r\n\r\n\t//////////////////////////////////////////////////////////////////////////////////\r\n\r\n\t[Rpc.Broadcast]\r\n\tprivate void BroadcastPlayerSpawn(PlayerPawn PlayerPawn)\r\n\t{\r\n\t\tScene.Dispatch(new PlayerSpawnedEvent(PlayerPawn));\r\n\t}\r\n\r\n\t[Rpc.Broadcast] // broadcast filter\r\n\tprivate void LocalPlayerSpawn(PlayerPawn PlayerPawn)\r\n\t{\r\n\t\tScene.Dispatch(new LocalPlayerSpawnedEvent(PlayerPawn));\r\n\t}\r\n\r\n\t[Rpc.Broadcast] // broadcast filter\r\n\tpublic void LocalOnPlayerDeath()\r\n\t{\r\n\t\tScene.Dispatch(new LocalPlayerDiedEvent());\r\n\t}\r\n}\r\n"},{"Ident":"wurstsoftware.koth","Path":"UI/PlayerDeath/PlayerDeathHUD.razor","FileName":"PlayerDeathHUD.razor","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"@namespace KOTH.UI\r\n@using KOTH.Notification\r\n@using Sandbox.Events\r\n@inherits PanelComponent\r\n\r\n@if (!DeathCameraData.IsValid())\r\n{\r\n\treturn;\r\n}\r\n\r\n\u003Croot\u003E\r\n\t\u003Cdiv class=\u0022dead\u0022\u003E\r\n\t\tkilled by:\r\n\t\u003C/div\u003E\r\n\t\u003Cdiv class=\u0022name\u0022\u003E\r\n\t\t@DeathCameraData.KillerName\r\n\t\u003C/div\u003E\r\n\r\n\t\u003Cdiv class=\u0022hp\u0022\u003E\r\n\t\t@DeathCameraData.KillerHealth HP\r\n\t\u003C/div\u003E\r\n\u003C/root\u003E\r\n\r\n@code\r\n{\r\n\tpublic static PlayerDeathHUD Instance { get; set; }\r\n\r\n\tpublic PlayerDeathHUD()\r\n\t{\r\n\t\tInstance = this;\r\n\t}\r\n\r\n\tpublic FDeathCameraData DeathCameraData { get; set; }\r\n\r\n\tpublic void SetData(FDeathCameraData Data)\r\n\t{\r\n\t\tDeathCameraData = Data;\r\n\t}\r\n\r\n\tprotected override void OnEnabled()\r\n\t{\r\n\t\tbase.OnEnabled();\r\n\t}\r\n\r\n\tprotected override void OnUpdate()\r\n\t{\r\n\t\tbase.OnUpdate();\r\n\t}\r\n\r\n\tprotected override int BuildHash()\r\n\t{\r\n\t\treturn HashCode.Combine(Time.Now);\r\n\t}\r\n}"},{"Ident":"wurstsoftware.koth","Path":"UI/PlayerHud/Components/EngieOverlay.razor","FileName":"EngieOverlay.razor","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"@* @namespace KOTH.UI\r\n@inherits Panel\r\n@attribute [StyleSheet]\r\n\r\n@if (!Player.IsValid() || !EngiePlayer.IsValid() || EngiePlayer.ActiveTurretComponent == null)\r\n{\r\n    return;\r\n}\r\n\r\n\u003Croot\u003E\r\n    \u003Clabel class=\u0022building\u0022\u003E@(EngiePlayer.ActiveTurretComponent.DamageComponent.Health)/@(EngiePlayer.ActiveTurretComponent.DamageComponent.MaxBaseHealth)\u003C/label\u003E\r\n\u003C/root\u003E\r\n\r\n@code\r\n{\r\n    public PlayerPawn Player =\u003E PlayerState.Local.PlayerPawn;\r\n    public EngiePlayer EngiePlayer =\u003E Player.GameObject.GetComponent\u003CEngiePlayer\u003E();\r\n\r\n    protected override int BuildHash()\r\n    {\r\n        if (!Player.IsValid())\r\n            return 0;\r\n\r\n        return HashCode.Combine(Time.Now);\r\n    }\r\n}\r\n *@"},{"Ident":"wurstsoftware.koth","Path":"UI/PlayerHud/Components/Voices.razor","FileName":"Voices.razor","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"@namespace KOTH.UI\r\n@attribute [StyleSheet]\r\n@inherits Panel\r\n\r\n\u003Croot class=\u0022\u0022\u003E\r\n\t@* @foreach (var voice in VoiceList.Where(x =\u003E CanDisplay(x)))\r\n\t{\r\n\t\t\u003Cdiv class=\u0022row\u0022\u003E\r\n\t\t\t\u003Cdiv class=\u0022item-row with-background\u0022\u003E\r\n\t\t\t\t@{\r\n\t\t\t\t\tvar player = GetPlayer(voice);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t\u003CIcon class=\u0022square rounded shrink-0\u0022 File=\u0022/ui/chat/radio.png\u0022 size=\u002224\u0022 style=\u0022transform: scale( @GetAmplitudeScale( voice ) )\u0022 /\u003E\r\n\t\t\t\t\u003Cimg class=\u0022avatar\u0022 src=\u0022avatar:@player.SteamId\u0022 /\u003E\r\n\t\t\t\t\u003CPlayerPanel PlayerState=@player /\u003E\r\n\t\t\t\u003C/div\u003E\r\n\t\t\u003C/div\u003E\r\n\t} *@\r\n\r\n\u003C/root\u003E\r\n\r\n@code\r\n{\r\n\tpublic IEnumerable\u003CPlayerVoiceComponent\u003E VoiceList =\u003E Scene.GetAllComponents\u003CPlayerVoiceComponent\u003E().Where(x =\u003E x.PlayerState.IsConnected);\r\n\r\n\tprivate PlayerState GetPlayer(Voice voice)\r\n\t{\r\n\t\treturn voice.Components.Get\u003CPlayerState\u003E();\r\n\t}\r\n\r\n\tprivate bool CanDisplay(Voice voice)\r\n\t{\r\n\t\treturn voice.LastPlayed \u003C 0.25f;\r\n\t}\r\n\r\n\tprivate string GetAmplitudeScale(Voice voice)\r\n\t{\r\n\t\tvar scale = 0.5f \u002B (voice.Amplitude * 2.365f);\r\n\t\treturn (1f \u002B scale).ToString(\u00220.#\u0022);\r\n\t}\r\n\r\n\tprotected override int BuildHash()\r\n\t{\r\n\t\treturn HashCode.Combine(Time.Now);\r\n\t}\r\n}"},{"Ident":"wurstsoftware.koth","Path":"UI/PlayerHud/Components/XHair.razor","FileName":"XHair.razor","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"@namespace KOTH.UI\r\n@inherits Panel\r\n@attribute [StyleSheet]\r\n\r\n@if ( !Player.IsValid() )\r\n    return;\r\n\r\n\u003Croot\u003E\r\n    \u003Cdiv class=\u0022circle\u0022\u003E\u003C/div\u003E\r\n\u003C/root\u003E\r\n\r\n@code\r\n{\r\n    /// The player\r\n    public PlayerPawn Player =\u003E PlayerState.Local.PlayerPawn;\r\n\r\n    protected override int BuildHash()\r\n    {\r\n        if ( !Player.IsValid() || !Player.CurrentEquipment.IsValid() )\r\n            return 0;\r\n\r\n        return HashCode.Combine(Player, Player.CurrentEquipment);\r\n    }\r\n}\r\n"},{"Ident":"wurstsoftware.koth","Path":"Weapons/Components/ProjectileWeaponComponent.cs","FileName":"ProjectileWeaponComponent.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"using KOTH.UI;\r\nusing Sandbox;\r\nusing Sandbox.Events;\r\nusing System.Net.Http;\r\nusing System;\r\nusing System.Text;\r\nusing Sandbox.Diagnostics;\r\nusing System.Data.Common;\r\n\r\nnamespace KOTH;\r\n\r\n// TODO : this piece of shit needs a proper refactor\r\n\r\n[Title(\u0022Projectile Shooter\u0022), Group(\u0022Weapon Components\u0022)]\r\npublic class ProjectileWeaponComponent : InputWeaponComponent\r\n{\r\n\t[Property, Group(\u0022Projectile\u0022)] public GameObject ProjectilePrefab { get; set; }\r\n\t[Property, Group(\u0022Projectile\u0022)] public float ProjectileHorizontalSpeed { get; set; } = 600.0f;\r\n\t[Property, Group(\u0022Projectile\u0022)] public float ProjectileVerticalSpeed { get; set; } = 0f;\r\n\r\n\t[Property, Group(\u0022VFX\u0022)] public SoundEvent ShootSound { get; set; }\r\n\r\n\t////////////////////////////////////////////////////////////////////////\r\n\r\n\t// TODO : sticky only, look into doing a better way\r\n\tpublic bool IsStickyLauncher { get =\u003E StickyTrackerComponent.IsValid(); }\r\n\tpublic int ActiveStickies { get =\u003E StickyTrackerComponent.IsValid() ? StickyTrackerComponent.StickyCount : 0; }\r\n\tprotected StickyTrackerComponent StickyTrackerComponent { get; set; }\r\n\r\n\t////////////////////////////////////////////////////////////////////////\r\n\r\n\tprotected override void OnAwake()\r\n\t{\r\n\t\tbase.OnAwake();\r\n\r\n\t\t// TODO : revisit, sticky only\r\n\t\tStickyTrackerComponent = Components.Get\u003CStickyTrackerComponent\u003E();\r\n\t}\r\n\r\n\tprotected override void OnInputUpdate()\r\n\t{\r\n\t\tif (!Equipment.Owner.IsValid())\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!Equipment.Owner.IsLocallyControlled)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tbool IsShooting = IsDown() \u0026\u0026 CanShoot();\r\n\t\tif (IsShooting)\r\n\t\t{\r\n\t\t\tif (IsReloading \u0026\u0026 Ammo \u003E 0)\r\n\t\t\t{\r\n\t\t\t\tCancelReload();\r\n\t\t\t}\r\n\t\t\tEquipment.Owner.VFXOnShoot();\r\n\t\t\tShoot();\r\n\t\t}\r\n\t}\r\n\r\n\tprotected virtual GameObject Shoot() // TODO : revisit the return\r\n\t{\r\n\t\tvar PlayerPawn = Equipment.Owner;\r\n\t\tif (!PlayerPawn.IsValid())\r\n\t\t{\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tTimeSinceShot = 0;\r\n\t\tAmmo--;\r\n\t\tWorldShotVFX();\r\n\r\n\t\tvar AimForward = PlayerPawn.AimRay.Forward;\r\n\r\n\t\t// create projectile object from prefab\r\n\t\tvar ProjectilePosition = PlayerPawn.AimRay.Position \u002B (Vector3.Down * 3.33f); // magic\r\n\t\tvar ProjectileRotation = Rotation.LookAt(AimForward);\r\n\t\tvar Projectile = ProjectilePrefab.Clone(ProjectilePosition, ProjectileRotation);\r\n\r\n\t\t// give it the player\r\n\t\tvar ProjectileComponent = Projectile.Components.Get\u003CProjectile\u003E();\r\n\t\tProjectileComponent.OwnerPlayerPawn = PlayerPawn;\r\n\r\n\t\tif (IsStickyLauncher)\r\n\t\t{\r\n\t\t\tStickyTrackerComponent.AddSticky(Projectile.Components.Get\u003CSticky\u003E());\r\n\t\t}\r\n\r\n\t\tvar Rigidbody = Projectile.Components.Get\u003CRigidbody\u003E();\r\n\t\tSetProjectileVelocity(Rigidbody, AimForward);\r\n\r\n\t\tProjectile.Root.Tags.Add(\u0022self\u0022);\r\n\t\tProjectile.NetworkSpawn();\r\n\t\treturn Projectile;\r\n\t}\r\n\r\n\t[Rpc.Broadcast]\r\n\tpublic void WorldShotVFX()\r\n\t{\r\n\t\tif (ShootSound.IsValid())\r\n\t\t{\r\n\t\t\tif (Sound.Play(ShootSound, Equipment.WorldPosition) is { } SoundHandel)\r\n\t\t\t{\r\n\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprotected virtual void SetProjectileVelocity(Rigidbody ProjectileRigidbody, Vector3 AimForward)\r\n\t{\r\n\t\tProjectileRigidbody.Velocity = AimForward * ProjectileHorizontalSpeed;\r\n\t\tProjectileRigidbody.Velocity \u002B= Vector3.Up * ProjectileVerticalSpeed;\r\n\t}\r\n\r\n\tprotected TimeSince TimeSinceShot = new();\r\n\tprotected virtual bool CanShoot()\r\n\t{\r\n\t\t// these 2 should be ensures?\r\n\t\tif (!Equipment.IsValid()) return false;\r\n\t\tif (!Equipment.Owner.IsValid()) return false;\r\n\r\n\t\tif (Equipment.Owner.IsFrozen)\r\n\t\t\treturn false;\r\n\r\n\t\tif (Equipment.Tags.Has(\u0022equipping\u0022))\r\n\t\t\treturn false;\r\n\r\n\t\tif (TimeSinceShot \u003C FireRate)\r\n\t\t\treturn false;\r\n\r\n\t\tif (!HasAmmo)\r\n\t\t\treturn false;\r\n\r\n\t\treturn true;\r\n\t}\r\n}\r\n\r\n////////////////////////////////////////////////////////////////////////\r\n\r\n// NOTE : i think this should now just be a \u0027mode\u0027 within the base projectile comp\r\n// TODO : please god fix this\r\n\r\n[Title(\u0022Sticky Shooter\u0022), Group(\u0022Weapon Components\u0022)]\r\npublic class StickyWeaponComponent : ProjectileWeaponComponent\r\n{\r\n\t[Property, Category(\u0022Sticky\u0022)] public float MaxChargeTime { get; private set; } = 1.6f;\r\n\r\n\t// TODO : THIS IS QUICKLY BECOMING A MESS!\r\n\r\n\tpublic TimeSince TimeSinceInputFirstDown { get; private set; } = new();\r\n\tpublic bool WasInputDownLastTick { get; private set; } = false;\r\n\tprotected override void OnInputUpdate() // TODO : OnInput()?\r\n\t{\r\n\t\tif (!Equipment.Owner.IsValid())\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!Equipment.Owner.IsLocallyControlled)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tbool KeyDown = IsDown();\r\n\r\n\t\tif (WasInputDownLastTick)\r\n\t\t{\r\n\t\t\tif (!KeyDown \u0026\u0026 CanShoot())\r\n\t\t\t{\r\n\t\t\t\tif (IsReloading \u0026\u0026 Ammo \u003E 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tCancelReload();\r\n\t\t\t\t}\r\n\t\t\t\tGameObject Projectile = Shoot();\r\n\t\t\t\tif (Projectile.Components.Get\u003CSticky\u003E() is Sticky Sticky)\r\n\t\t\t\t{\r\n\t\t\t\t\tEquipment.Owner.OnDeath \u002B= Sticky.Destroy;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tif (KeyDown)\r\n\t\t\t{\r\n\t\t\t\tTimeSinceInputFirstDown = 0;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tWasInputDownLastTick = KeyDown;\r\n\t}\r\n\r\n\tprotected override void SetProjectileVelocity(Rigidbody ProjectileRigidbody, Vector3 AimForward)\r\n\t{\r\n\t\tconst float Factor = .66f;\r\n\t\tvar SpeedFactor = 1 \u002B (Math.Min(TimeSinceInputFirstDown, MaxChargeTime) * Factor);\r\n\t\tProjectileRigidbody.Velocity = AimForward * ProjectileHorizontalSpeed * SpeedFactor;\r\n\t\tProjectileRigidbody.Velocity \u002B= Vector3.Up * ProjectileVerticalSpeed;\r\n\t}\r\n\r\n\tprotected override void OnUpdate()\r\n\t{\r\n\t\tbase.OnUpdate();\r\n\r\n\t\tbool IsAltFire = Input.Down(\u0022attack2\u0022);\r\n\t\tif (IsAltFire \u0026\u0026 StickyTrackerComponent.IsValid())\r\n\t\t{\r\n\t\t\tStickyTrackerComponent.Detonate();\r\n\t\t}\r\n\t}\r\n}\r\n"},{"Ident":"wurstsoftware.koth","Path":"Damage/HealingEvent.cs","FileName":"HealingEvent.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"using Sandbox.Events;\r\n\r\nnamespace KOTH;\r\n\r\npublic record HealingRequestEvent(FHealingRequest HealingRequest) : IGameEvent;\r\npublic record HealingBroadcastEvent(FHealingReceived HealingRequest) : IGameEvent;\r\n\r\npublic record FHealingRequest\r\n{\r\n\tpublic DamageComponent TargetDamageComponent { get; init; }\r\n\tpublic PlayerPawn TargetPlayerPawn { get; init; }\r\n\tpublic PlayerPawn HealerPlayerPawn { get; init; }\r\n\tpublic int BaseHealing { get; init; } = 0;\r\n\tpublic bool AllowOverheal { get; init; } = false;\r\n\r\n\tpublic EHealingType HealingType { get; init; } = EHealingType.Continuous;\r\n\tpublic Vector3 HealingOrigin { get; init; } = Vector3.Zero;\r\n\r\n\tpublic RealTimeSince TimeSinceEvent { get; init; } = 0;\r\n\r\n\tpublic bool IsValid()\r\n\t{\r\n\t\treturn TargetPlayerPawn.IsValid();\r\n\t}\r\n}\r\n\r\npublic record FHealingReceived\r\n{\r\n\tpublic PlayerPawn TargetPlayerPawn { get; init; }\r\n\tpublic PlayerPawn HealerPlayerPawn { get; init; }\r\n\tpublic PlayerState TargetPlayerState { get; init; }\r\n\tpublic PlayerState HealerPlayerState { get; init; }\r\n\tpublic int Heals { get; init; } = 0;\r\n\tpublic EHealingType HealingType { get; init; } = EHealingType.Continuous;\r\n}\r\n\r\npublic enum EHealingType\r\n{\r\n\tContinuous = 0,\r\n\tOneOff,\r\n}\r\n"},{"Ident":"wurstsoftware.koth","Path":"GameMode/MapDefinition.cs","FileName":"MapDefinition.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"namespace KOTH;\r\n\r\n[GameResource(\u0022koth/Map Definition\u0022, \u0022map\u0022, \u0022A map definition\u0022)]\r\npublic partial class MapDefinition : GameResource\r\n{\r\n\t[Property] public string Title { get; set; }\r\n\t[Property] public string Description { get; set; }\r\n\t[Property] public SceneFile SceneFile { get; set; }\r\n\t[Property, ImageAssetPath] public string Background { get; set; }\r\n}\r\n"},{"Ident":"wurstsoftware.koth","Path":"GameMode/Notification/NotificationManager.cs","FileName":"NotificationManager.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"namespace KOTH.Notification;\r\n\r\n/// \u003Csummary\u003E\r\n/// Manages the queue and display of notifications in the game.\r\n/// NOTE - only one Notification will show at a time, even if its in different zones\r\n/// \u003C/summary\u003E\r\npublic class NotificationManager: SingletonComponent\u003CNotificationManager\u003E\r\n{\r\n\t// Queue of notifications\r\n\tpublic Queue\u003CFNotification\u003E NotificationQueue { get; set; } = new();\r\n\r\n\t// Notification - Time Display Ends\r\n\tpublic KeyValuePair\u003CFNotification, DateTime\u003E? CurrentNotifications { get; set; } = null;\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Adds a new notification to the notification queue.\r\n\t/// \u003C/summary\u003E\r\n\t/// \u003Cparam name=\u0022Notification\u0022\u003EThe notification to be added to the queue.\u003C/param\u003E\r\n\tpublic void AddNotification(FNotification Notification)\r\n\t{\r\n\t\tNotificationQueue.Enqueue(Notification);\r\n\t}\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Retrieves the currently active notification if one exists.\r\n\t/// \u003C/summary\u003E\r\n\t/// \u003Creturns\u003E\r\n\t/// The currently active notification or null if no notification is active.\r\n\t/// \u003C/returns\u003E\r\n\tpublic FNotification? GetNotification()\r\n\t{\r\n\t\tif (CurrentNotifications == null) return null;\r\n\r\n\t\treturn CurrentNotifications.Value.Key;\r\n\t}\r\n\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Updates the state of the notification manager, including processing the notification queue\r\n\t/// and managing the display timing of the current notification.\r\n\t/// \u003C/summary\u003E\r\n\tprotected override void OnUpdate()\r\n\t{\r\n        if (CurrentNotifications != null \u0026\u0026 CurrentNotifications.Value.Value \u003C= DateTime.Now)\r\n\t\t{\r\n\t\t\tCurrentNotifications = null;\r\n\t\t}\r\n\r\n\t\tif (CurrentNotifications == null \u0026\u0026 NotificationQueue.Count \u003E 0)\r\n\t\t{\r\n\t\t\tvar notification = NotificationQueue.Dequeue();\r\n\t\t\tCurrentNotifications = new KeyValuePair\u003CFNotification, DateTime\u003E(notification, DateTime.Now.AddSeconds(notification.Duration));\r\n\t\t}\r\n\t}\r\n}\r\n"},{"Ident":"wurstsoftware.koth","Path":"GameMode/Rules/Koth/Events.cs","FileName":"Events.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"using Sandbox.Events;\r\n\r\nnamespace KOTH;\r\n\r\npublic record HillCapturedEvent(List\u003CPlayerPawn\u003E PlayerPawns, Team Team, Hill Hill) : IGameEvent;\r\npublic record HillWinEvent(Team Team, Hill Hill) : IGameEvent;\r\npublic record HillCappingEvent(Team Team, float CaptureDelta, Hill Hill) : IGameEvent;\r\npublic record HillDecayCapEvent(float CaptureDelta, Hill Hill) : IGameEvent;\r\n\r\n[Title(\u0022Hill Captured Event\u0022)]\r\npublic class HillCapturedEventComponent : GameEventComponent\u003CHillCapturedEvent\u003E { }\r\n\r\n[Title(\u0022Hill Won Event\u0022)]\r\npublic class HillWinEventComponent : GameEventComponent\u003CHillWinEvent\u003E { }\r\n\r\n[Title(\u0022Hill Capping Event\u0022)]\r\npublic class HillCappingEventComponent : GameEventComponent\u003CHillCappingEvent\u003E { }\r\n\r\n[Title(\u0022Hill Decay Event\u0022)]\r\npublic class HillDecayCapEventComponent : GameEventComponent\u003CHillDecayCapEvent\u003E { }\r\n"},{"Ident":"wurstsoftware.koth","Path":"GameMode/Rules/Koth/KothWinCondition.cs","FileName":"KothWinCondition.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":393654,"Code":"using Sandbox;\r\nusing Sandbox.Events;\r\nusing Sandbox.Utility;\r\n\r\nnamespace KOTH;\r\n\r\npublic sealed class KothWinCondition : Component,\r\n\tIGameEventHandler\u003CHillWinEvent\u003E\r\n{\r\n\t[Property, Sync(SyncFlags.FromHost)]\r\n\tpublic int TargetScore { get; set; } = 3;\r\n\r\n\t[Sync(SyncFlags.FromHost)]\r\n\tpublic NetDictionary\u003CTeam, int\u003E Scores { get; private set; } = new();\r\n\r\n\t[Property]\r\n\tpublic StateComponent RoundWinState { get; set; }\r\n\r\n\t[Property]\r\n\tpublic StateComponent TGameWinState { get; set; }\r\n\r\n\t[Property]\r\n\tpublic StateComponent CTGameWinState { get; set; }\r\n\r\n\t///////////////////////////////////////////////////////////////////////////\r\n\r\n\tprotected override void OnAwake()\r\n\t{\r\n\t\tbase.OnAwake();\r\n\r\n\t\tif (Networking.IsHost)\r\n\t\t{\r\n\t\t\t//if (Scores != null)\r\n\t\t\t//{\r\n\t\t\tScores = new()\r\n\t\t\t\t{\r\n\t\t\t\t// TODO : will need to add any extra teams here as well! not pragmatic!\r\n\t\t\t\t{ Team.CounterTerrorist, 0 }, { Team.Terrorist, 0 }, { Team.Unassigned, 0 },\r\n\t\t\t\t};\r\n\t\t\t//}\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tpublic void OnGameEvent(HillWinEvent EventArgs)\r\n\t{\r\n\t\tLog.Info($\u0022all : scores {Scores[Team.CounterTerrorist]} : {Scores[Team.Terrorist]}\u0022);\r\n\r\n\t\tif (!Networking.IsHost)\r\n\t\t\treturn;\r\n\r\n\t\tvar Hill = EventArgs.Hill;\r\n\t\tif (!Hill.IsValid())\r\n\t\t{\r\n\t\t\tLog.Error(\u0022Invalid hill captured!\u0022);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tTeam WinningTeam = EventArgs.Team;\r\n\t\tvar TeamScore = \u002B\u002BScores[WinningTeam];\r\n\r\n\t\tif (TeamScore \u003E= TargetScore)\r\n\t\t{\r\n\t\t\tvar NextState = WinningTeam == Team.CounterTerrorist ? CTGameWinState : TGameWinState;\r\n\t\t\tGameMode.Instance.StateMachine.Transition(NextState);\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tGameMode.Instance.StateMachine.Transition(RoundWinState);\r\n\t\t}\r\n\r\n\t\tLog.Info($\u0022host : scores {Scores[Team.CounterTerrorist]} : {Scores[Team.Terrorist]}\u0022);\r\n\t}\r\n}\r\n"}]}