This commit is contained in:
code002lover 2025-06-05 01:12:55 +02:00
parent 17c654d889
commit 96596e9c08
39 changed files with 1157 additions and 1350 deletions

View File

@ -1,32 +1,32 @@
using System.Collections; using LabApi.Events.Arguments.PlayerEvents;
using LabApi.Features;
using LabApi.Loader.Features.Plugins;
using LabApi.Events.Arguments.PlayerEvents;
using LabApi.Events.Handlers; using LabApi.Events.Handlers;
using LabApi.Features;
using LabApi.Features.Wrappers; using LabApi.Features.Wrappers;
using PlayerRoles; using LabApi.Loader.Features.Plugins;
using Logger = LabApi.Features.Console.Logger;
using Version = System.Version;
using MEC; using MEC;
using PlayerRoles;
using UnityEngine; using UnityEngine;
using Logger = LabApi.Features.Console.Logger;
using Random = UnityEngine.Random;
using Version = System.Version;
namespace AfkSwap; namespace AfkSwap;
public class AfkSwap : Plugin public class AfkSwap : Plugin
{ {
private const float AfkTimeLimit = 60; // 1 minute in seconds
private readonly Dictionary<Player, DateTime> _afkPlayers = new();
private readonly object _lock = new();
private readonly Dictionary<Player, Vector3> _playerPositions = new();
private readonly Dictionary<Player, DateTime> _playerSpawnTimes = new();
public override string Name => "AfkSwap"; public override string Name => "AfkSwap";
public override string Author => "Code002Lover"; public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0); public override Version Version { get; } = new(1, 0, 0);
public override string Description => "Swaps AFK players with spectators after one minute."; public override string Description => "Swaps AFK players with spectators after one minute.";
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
private readonly Dictionary<Player, DateTime> _playerSpawnTimes = new();
private readonly Dictionary<Player, Vector3> _playerPositions = new();
private readonly Dictionary<Player, DateTime> _afkPlayers = new();
private const float AfkTimeLimit = 60; // 1 minute in seconds
private readonly object _lock = new();
public override void Enable() public override void Enable()
{ {
PlayerEvents.Spawned += OnPlayerSpawned; PlayerEvents.Spawned += OnPlayerSpawned;
@ -60,7 +60,6 @@ public class AfkSwap : Plugin
Logger.Debug($"Player {player.DisplayName} spawned"); Logger.Debug($"Player {player.DisplayName} spawned");
}); });
} }
private IEnumerator<float> CheckAfkPlayers() private IEnumerator<float> CheckAfkPlayers()
@ -70,14 +69,17 @@ public class AfkSwap : Plugin
{ {
lock (_lock) lock (_lock)
{ {
foreach (var playerTime in _playerSpawnTimes.ToList().Where(playerTime => (DateTime.Now - playerTime.Value).TotalSeconds >= AfkTimeLimit)) foreach (var playerTime in _playerSpawnTimes.ToList().Where(playerTime =>
(DateTime.Now - playerTime.Value).TotalSeconds >= AfkTimeLimit))
{ {
if (playerTime.Key.Role is RoleTypeId.Spectator or RoleTypeId.Destroyed or RoleTypeId.Overwatch or RoleTypeId.Tutorial) if (playerTime.Key.Role is RoleTypeId.Spectator or RoleTypeId.Destroyed or RoleTypeId.Overwatch
or RoleTypeId.Tutorial)
{ {
_playerSpawnTimes.Remove(playerTime.Key); _playerSpawnTimes.Remove(playerTime.Key);
_playerPositions.Remove(playerTime.Key); _playerPositions.Remove(playerTime.Key);
continue; continue;
} }
if (!_playerPositions[playerTime.Key].Equals(playerTime.Key.Position)) if (!_playerPositions[playerTime.Key].Equals(playerTime.Key.Position))
{ {
_playerSpawnTimes.Remove(playerTime.Key); _playerSpawnTimes.Remove(playerTime.Key);
@ -97,13 +99,15 @@ public class AfkSwap : Plugin
private void SwapWithSpectator(Player afkPlayer) private void SwapWithSpectator(Player afkPlayer)
{ {
var spectators = Player.ReadyList.Where(p => p.Role == RoleTypeId.Spectator && (DateTime.Now - _afkPlayers[p]).TotalSeconds > 10).ToList(); var spectators = Player.ReadyList
.Where(p => p.Role == RoleTypeId.Spectator && (DateTime.Now - _afkPlayers[p]).TotalSeconds > 10).ToList();
if (!spectators.Any()) if (!spectators.Any())
{ {
Logger.Warn("No spectators to swap to"); Logger.Warn("No spectators to swap to");
return; return;
} }
var randomSpectator = spectators[UnityEngine.Random.Range(0, spectators.Count)];
var randomSpectator = spectators[Random.Range(0, spectators.Count)];
Logger.Debug($"Swapping {afkPlayer.DisplayName} with {randomSpectator.DisplayName}"); Logger.Debug($"Swapping {afkPlayer.DisplayName} with {randomSpectator.DisplayName}");
// Store the AFK player's position and role // Store the AFK player's position and role

View File

@ -24,13 +24,7 @@
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath> <HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="Assembly-CSharp-firstpass"> <Reference Include="Assembly-CSharp-firstpass">
<HintPath>..\dependencies\Assembly-CSharp-firstpass.dll</HintPath> <HintPath>..\dependencies\Assembly-CSharp-firstpass.dll</HintPath>
</Reference>
<Reference Include="Mirror">
<HintPath>..\dependencies\Mirror.dll</HintPath>
</Reference>
<Reference Include="Pooling">
<HintPath>..\dependencies\Pooling.dll</HintPath>
</Reference> </Reference>
<Reference Include="UnityEngine.CoreModule"> <Reference Include="UnityEngine.CoreModule">
<HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath> <HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath>
@ -38,6 +32,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -20,21 +20,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Assembly-CSharp"> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
</Reference>
<Reference Include="Mirror">
<HintPath>..\dependencies\Mirror.dll</HintPath>
</Reference>
<Reference Include="Pooling">
<HintPath>..\dependencies\Pooling.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,5 +1,4 @@
using CustomPlayerEffects; using LabApi.Events.Arguments.PlayerEvents;
using LabApi.Events.Arguments.PlayerEvents;
using LabApi.Events.Handlers; using LabApi.Events.Handlers;
using LabApi.Features; using LabApi.Features;
using LabApi.Features.Console; using LabApi.Features.Console;
@ -7,8 +6,6 @@ using LabApi.Features.Wrappers;
using LabApi.Loader.Features.Plugins; using LabApi.Loader.Features.Plugins;
using Mirror; using Mirror;
using PlayerRoles; using PlayerRoles;
using PlayerRoles.PlayableScps.Scp3114;
using PlayerRoles.Ragdolls;
namespace CuffedFrenemies; namespace CuffedFrenemies;
@ -18,7 +15,7 @@ public class CuffedFrenemies : Plugin
public override string Author => "Code002Lover"; public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0); public override Version Version { get; } = new(1, 0, 0);
public override string Description => "Cuff your enemies"; public override string Description => "Cuff your enemies";
public override Version RequiredApiVersion { get; } = new (LabApiProperties.CompiledVersion); public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
public override void Enable() public override void Enable()
{ {
@ -33,10 +30,7 @@ public class CuffedFrenemies : Plugin
private static void OnCuff(PlayerCuffedEventArgs ev) private static void OnCuff(PlayerCuffedEventArgs ev)
{ {
if (ev.Target.Team is Team.ClassD or Team.Scientists) if (ev.Target.Team is Team.ClassD or Team.Scientists) return;
{
return;
}
if (ev.Target.Team == ev.Player.Team) if (ev.Target.Team == ev.Player.Team)
{ {
@ -44,10 +38,7 @@ public class CuffedFrenemies : Plugin
return; return;
} }
if (ev.Target.Team is Team.SCPs or Team.Dead) if (ev.Target.Team is Team.SCPs or Team.Dead) return;
{
return;
}
var newRole = ev.Target.Team == Team.ChaosInsurgency ? RoleTypeId.NtfPrivate : RoleTypeId.ChaosConscript; var newRole = ev.Target.Team == Team.ChaosInsurgency ? RoleTypeId.NtfPrivate : RoleTypeId.ChaosConscript;
Logger.Debug($"Setting role to {newRole}"); Logger.Debug($"Setting role to {newRole}");
@ -62,12 +53,8 @@ public class CuffedFrenemies : Plugin
ev.Target.SetRole(newRole); ev.Target.SetRole(newRole);
ev.Target.ClearItems(); ev.Target.ClearItems();
foreach (var newItem in newItems) foreach (var newItem in newItems) ev.Target.Inventory.UserInventory.Items.Add(newItem.Serial, newItem.Base);
{
ev.Target.Inventory.UserInventory.Items.Add(newItem.Serial,newItem.Base);
}
ev.Target.Position = newPos; ev.Target.Position = newPos;
} }
} }

View File

@ -26,15 +26,12 @@
<Reference Include="Mirror"> <Reference Include="Mirror">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll</HintPath>
</Reference> </Reference>
<Reference Include="Pooling">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Pooling.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule"> <Reference Include="UnityEngine.CoreModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,23 +1,24 @@
using System.Drawing; using Interactables.Interobjects.DoorUtils;
using CommandSystem.Commands.RemoteAdmin.Inventory;
using Interactables.Interobjects.DoorUtils;
using InventorySystem.Items; using InventorySystem.Items;
using LabApi.Events.Arguments.PlayerEvents; using LabApi.Events.Arguments.PlayerEvents;
using LabApi.Events.Arguments.ServerEvents; using LabApi.Events.Arguments.ServerEvents;
using LabApi.Events.Handlers; using LabApi.Events.Handlers;
using LabApi.Features; using LabApi.Features;
using LabApi.Features.Console;
using LabApi.Loader.Features.Plugins;
using PlayerRoles;
using LabApi.Features.Wrappers; using LabApi.Features.Wrappers;
using LabApi.Loader.Features.Plugins;
using MapGeneration; using MapGeneration;
using Vector3 = UnityEngine.Vector3;
using MEC; using MEC;
using PlayerRoles;
using UnityEngine;
using Logger = LabApi.Features.Console.Logger;
using Random = System.Random;
using Vector3 = UnityEngine.Vector3;
namespace CustomClasses; namespace CustomClasses;
public class CustomClasses : Plugin public class CustomClasses : Plugin
{ {
private readonly CustomClassManager _classManager = new();
public override string Name => "CustomClasses"; public override string Name => "CustomClasses";
public override string Author => "Code002Lover"; public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0); public override Version Version { get; } = new(1, 0, 0);
@ -28,8 +29,6 @@ public class CustomClasses : Plugin
public ResearchSubjectConfig ResearchSubjectConfig { get; set; } = new(); public ResearchSubjectConfig ResearchSubjectConfig { get; set; } = new();
public HeadGuardConfig HeadGuardConfig { get; set; } = new(); public HeadGuardConfig HeadGuardConfig { get; set; } = new();
private readonly CustomClassManager _classManager = new();
public override void Enable() public override void Enable()
{ {
PlayerEvents.Spawned += OnPlayerSpawned; PlayerEvents.Spawned += OnPlayerSpawned;
@ -49,18 +48,18 @@ public class CustomClasses : Plugin
private void OnPlayerSpawned(PlayerSpawnedEventArgs ev) private void OnPlayerSpawned(PlayerSpawnedEventArgs ev)
{ {
if(_classManager.TryHandleSpawn(ev.Player, JanitorConfig, typeof(JanitorConfig))) return; if (_classManager.TryHandleSpawn(ev.Player, JanitorConfig, typeof(JanitorConfig))) return;
if(_classManager.TryHandleSpawn(ev.Player, ResearchSubjectConfig, typeof(ResearchSubjectConfig))) return; if (_classManager.TryHandleSpawn(ev.Player, ResearchSubjectConfig, typeof(ResearchSubjectConfig))) return;
if(_classManager.TryHandleSpawn(ev.Player, HeadGuardConfig, typeof(HeadGuardConfig))) return; if (_classManager.TryHandleSpawn(ev.Player, HeadGuardConfig, typeof(HeadGuardConfig))) return;
} }
} }
public class CustomClassManager public class CustomClassManager
{ {
private readonly Dictionary<Type, ICustomClassHandler> _handlers = new();
private readonly object _lock = new(); private readonly object _lock = new();
private readonly Random _random = new(); private readonly Random _random = new();
private readonly Dictionary<Type, SpawnState> _spawnStates = new(); private readonly Dictionary<Type, SpawnState> _spawnStates = new();
private readonly Dictionary<Type, ICustomClassHandler> _handlers = new();
public CustomClassManager() public CustomClassManager()
{ {
@ -72,7 +71,7 @@ public class CustomClassManager
public void TeleportPlayerToAround(Player player, Vector3 position) public void TeleportPlayerToAround(Player player, Vector3 position)
{ {
player.Position = position + new Vector3(0,1,0) + new Vector3((float)(_random.NextDouble() * 2), 0, player.Position = position + new Vector3(0, 1, 0) + new Vector3((float)(_random.NextDouble() * 2), 0,
(float)(_random.NextDouble() * 2)); (float)(_random.NextDouble() * 2));
} }
@ -90,10 +89,7 @@ public class CustomClassManager
{ {
lock (_lock) lock (_lock)
{ {
foreach (var key in _spawnStates.Keys.ToList()) foreach (var key in _spawnStates.Keys.ToList()) _spawnStates[key] = new SpawnState();
{
_spawnStates[key] = new SpawnState();
}
} }
} }
@ -121,10 +117,7 @@ public class CustomClassManager
Logger.Debug($"Player spawning {configType} - {player.Nickname} - {state.Spawns} / {config.MaxSpawns}"); Logger.Debug($"Player spawning {configType} - {player.Nickname} - {state.Spawns} / {config.MaxSpawns}");
if (_handlers.TryGetValue(configType, out var handler)) if (_handlers.TryGetValue(configType, out var handler)) return handler.HandleSpawn(player, config, _random);
{
return handler.HandleSpawn(player, config, _random);
}
} }
return false; return false;
@ -150,6 +143,7 @@ public class JanitorHandler(CustomClassManager manager) : ICustomClassHandler
player.AddItem(spawnItem, ItemAddReason.StartingItem); player.AddItem(spawnItem, ItemAddReason.StartingItem);
Logger.Debug($"Gave player {player.Nickname} spawn item {spawnItem}"); Logger.Debug($"Gave player {player.Nickname} spawn item {spawnItem}");
} }
player.SendBroadcast("You're a <color=#A0A0A0>Janitor</color>!", 3); player.SendBroadcast("You're a <color=#A0A0A0>Janitor</color>!", 3);
}); });
@ -171,6 +165,7 @@ public class ResearchSubjectHandler(CustomClassManager manager) : ICustomClassHa
player.AddItem(spawnItem, ItemAddReason.StartingItem); player.AddItem(spawnItem, ItemAddReason.StartingItem);
Logger.Debug($"Gave player {player.Nickname} spawn item {spawnItem}"); Logger.Debug($"Gave player {player.Nickname} spawn item {spawnItem}");
} }
player.SendBroadcast("You're a <color=#944710>Research Subject</color>!", 3); player.SendBroadcast("You're a <color=#944710>Research Subject</color>!", 3);
}); });
@ -186,7 +181,8 @@ public class HeadGuardHandler(CustomClassManager manager) : ICustomClassHandler
{ {
player.RemoveItem(ItemType.KeycardGuard); player.RemoveItem(ItemType.KeycardGuard);
KeycardItem.CreateCustomKeycardTaskForce(player, "Head Guard Keycard", $"HG. {player.Nickname}", new KeycardLevels(1,1,2),UnityEngine.Color.blue,UnityEngine.Color.cyan, "1", 0); KeycardItem.CreateCustomKeycardTaskForce(player, "Head Guard Keycard", $"HG. {player.Nickname}",
new KeycardLevels(1, 1, 2), Color.blue, Color.cyan, "1", 0);
player.AddItem(ItemType.Adrenaline, ItemAddReason.StartingItem); player.AddItem(ItemType.Adrenaline, ItemAddReason.StartingItem);

View File

@ -30,10 +30,7 @@
<HintPath>..\dependencies\Mirror.dll</HintPath> <HintPath>..\dependencies\Mirror.dll</HintPath>
</Reference> </Reference>
<Reference Include="NorthwoodLib"> <Reference Include="NorthwoodLib">
<HintPath>..\dependencies\NorthwoodLib.dll</HintPath> <HintPath>..\dependencies\NorthwoodLib.dll</HintPath>
</Reference>
<Reference Include="Pooling">
<HintPath>..\dependencies\Pooling.dll</HintPath>
</Reference> </Reference>
<Reference Include="UnityEngine.CoreModule"> <Reference Include="UnityEngine.CoreModule">
<HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath> <HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath>
@ -41,6 +38,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -11,14 +11,13 @@ namespace CustomItemSpawn;
public class CustomItemSpawn : Plugin<ItemConfig> public class CustomItemSpawn : Plugin<ItemConfig>
{ {
private static CustomItemSpawn _singleton;
public override string Name => "CustomItemSpawn"; public override string Name => "CustomItemSpawn";
public override string Author => "Code002Lover"; public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0); public override Version Version { get; } = new(1, 0, 0);
public override string Description => "Spawns items in a custom location."; public override string Description => "Spawns items in a custom location.";
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
private static CustomItemSpawn _singleton;
public override void Enable() public override void Enable()
{ {
_singleton = this; _singleton = this;
@ -33,7 +32,7 @@ public class CustomItemSpawn : Plugin<ItemConfig>
private static void OnRoundStart() private static void OnRoundStart()
{ {
Timing.CallDelayed(10,SpawnItems); Timing.CallDelayed(10, SpawnItems);
} }
private static void SpawnItems() private static void SpawnItems()

View File

@ -24,20 +24,17 @@
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath> <HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="Assembly-CSharp-firstpass"> <Reference Include="Assembly-CSharp-firstpass">
<HintPath>..\dependencies\Assembly-CSharp-firstpass.dll</HintPath> <HintPath>..\dependencies\Assembly-CSharp-firstpass.dll</HintPath>
</Reference> </Reference>
<Reference Include="Mirror"> <Reference Include="Mirror">
<HintPath>..\dependencies\Mirror.dll</HintPath> <HintPath>..\dependencies\Mirror.dll</HintPath>
</Reference> </Reference>
<Reference Include="Pooling">
<HintPath>..\dependencies\Pooling.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule"> <Reference Include="UnityEngine.CoreModule">
<HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath> <HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -3,46 +3,43 @@ using LabApi.Features;
using LabApi.Features.Console; using LabApi.Features.Console;
using LabApi.Loader; using LabApi.Loader;
namespace GamblingCoin namespace GamblingCoin;
public class Plugin : LabApi.Loader.Features.Plugins.Plugin
{ {
public class Plugin : LabApi.Loader.Features.Plugins.Plugin public static Plugin Singleton;
private GamblingCoinEventHandler _eventHandler;
public GamblingCoinChancesConfig ConfigChances;
public GamblingCoinGameplayConfig ConfigGameplay;
public GamblingCoinMessages ConfigMessages;
public override string Name => "GamblingCoin";
public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0);
public override string Description => "Gamble your life away";
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
public override void LoadConfigs()
{ {
public override string Name => "GamblingCoin"; base.LoadConfigs();
public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0);
public override string Description => "Gamble your life away";
public override Version RequiredApiVersion { get; } = new (LabApiProperties.CompiledVersion);
public GamblingCoinGameplayConfig ConfigGameplay; ConfigGameplay = this.LoadConfig<GamblingCoinGameplayConfig>("gameplay.yml");
public GamblingCoinMessages ConfigMessages; ConfigMessages = this.LoadConfig<GamblingCoinMessages>("messages.yml");
public GamblingCoinChancesConfig ConfigChances; ConfigChances = this.LoadConfig<GamblingCoinChancesConfig>("chances.yml");
}
public override void LoadConfigs() public override void Enable()
{
base.LoadConfigs();
ConfigGameplay = this.LoadConfig< GamblingCoinGameplayConfig > ("gameplay.yml");
ConfigMessages = this.LoadConfig< GamblingCoinMessages > ("messages.yml");
ConfigChances = this.LoadConfig< GamblingCoinChancesConfig > ("chances.yml");
}
public static Plugin Singleton;
private GamblingCoinEventHandler _eventHandler;
public override void Enable()
{ {
Logger.Debug("starting..."); Logger.Debug("starting...");
Singleton = this; Singleton = this;
_eventHandler = new GamblingCoinEventHandler(); _eventHandler = new GamblingCoinEventHandler();
PlayerEvents.FlippedCoin += _eventHandler.OnFlippedCoin; PlayerEvents.FlippedCoin += _eventHandler.OnFlippedCoin;
} }
public override void Disable() public override void Disable()
{ {
Logger.Debug("unloading..."); Logger.Debug("unloading...");
Singleton = null; Singleton = null;
PlayerEvents.FlippedCoin -= _eventHandler.OnFlippedCoin; PlayerEvents.FlippedCoin -= _eventHandler.OnFlippedCoin;
}
} }
} }

View File

@ -1,37 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net48</TargetFramework> <TargetFramework>net48</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable> <Nullable>disable</Nullable>
<LangVersion>10</LangVersion> <LangVersion>10</LangVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<Optimize>true</Optimize> <Optimize>true</Optimize>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<DebugType>full</DebugType> <DebugType>full</DebugType>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<Optimize>true</Optimize> <Optimize>true</Optimize>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<DebugType>none</DebugType> <DebugType>none</DebugType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Assembly-CSharp"> <Reference Include="Assembly-CSharp">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Assembly-CSharp.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Assembly-CSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="Mirror"> <Reference Include="Mirror">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll</HintPath>
</Reference> </Reference>
<Reference Include="UnityEngine.CoreModule"> <Reference Include="UnityEngine.CoreModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,184 +1,190 @@
using CustomPlayerEffects; using CustomPlayerEffects;
namespace GamblingCoin namespace GamblingCoin;
public class GamblingCoinChancesConfig
{ {
public int NukeChance { get; set; } = 10;
public class GamblingCoinChancesConfig public int SpawnWaveChance { get; set; } = 150;
{ public int CommonItemChance { get; set; } = 600;
public int NukeChance { get; set; } = 10; public int UncommonItemChance { get; set; } = 400;
public int SpawnWaveChance { get; set; } = 150; public int RareItemChance { get; set; } = 250;
public int CommonItemChance { get; set; } = 600; public int EpicItemChance { get; set; } = 100;
public int UncommonItemChance { get; set; } = 400; public int LegendaryItemChance { get; set; } = 30;
public int RareItemChance { get; set; } = 250; public int RandomTeleportChance { get; set; } = 200;
public int EpicItemChance { get; set; } = 100; public int StealItemChance { get; set; } = 100;
public int LegendaryItemChance { get; set; } = 30; public int ExplosionChance { get; set; } = 40;
public int RandomTeleportChance { get; set; } = 200; public int AntiMicroChance { get; set; } = 10;
public int StealItemChance { get; set; } = 100; public int GrenadeChance { get; set; } = 50;
public int ExplosionChance { get; set; } = 40; public int PocketDimensionChance { get; set; } = 30;
public int AntiMicroChance { get; set; } = 10; public int SwitchInventoryChance { get; set; } = 150;
public int GrenadeChance { get; set; } = 50; public int PositiveEffectChance { get; set; } = 300;
public int PocketDimensionChance { get; set; } = 30; public int NegativeEffectChance { get; set; } = 350;
public int SwitchInventoryChance { get; set; } = 150; public int AdvancedPositiveEffectChance { get; set; } = 150;
public int PositiveEffectChance { get; set; } = 300; public int AdvancedNegativeEffectChance { get; set; } = 250;
public int NegativeEffectChance { get; set; } = 350; public int RemoveCoinChance { get; set; } = 300;
public int AdvancedPositiveEffectChance { get; set; } = 150; }
public int AdvancedNegativeEffectChance { get; set; } = 250;
public int RemoveCoinChance { get; set; } = 300; public class GamblingCoinMessages
} {
public string SpawnWaveMessage { get; set; } = "Did someone just enter the Site...?";
public class GamblingCoinMessages public string ItemSpawnMessage { get; set; } = "*plop*";
{ public string UncommonItemSpawnMessage { get; set; } = "*bump*";
public string SpawnWaveMessage { get; set; } = "Did someone just enter the Site...?"; public string RareItemSpawnMessage { get; set; } = "*badunk*";
public string ItemSpawnMessage { get; set; } = "*plop*"; public string EpicItemSpawnMessage { get; set; } = "*katong*";
public string UncommonItemSpawnMessage { get; set; } = "*bump*"; public string LegendaryItemSpawnMessage { get; set; } = "*sounds of monetary loss*";
public string RareItemSpawnMessage { get; set; } = "*badunk*"; public string RandomTeleportMessage { get; set; } = "Where did you go?";
public string EpicItemSpawnMessage { get; set; } = "*katong*"; public string StealItemMessage { get; set; } = "Be careful, the coin is slippery!";
public string LegendaryItemSpawnMessage { get; set; } = "*sounds of monetary loss*"; public string ExplosionMessage { get; set; } = "How did you even die '-'";
public string RandomTeleportMessage { get; set; } = "Where did you go?"; public string AntiMicroMessage { get; set; } = "Where did all the micros go...";
public string StealItemMessage { get; set; } = "Be careful, the coin is slippery!"; public string GrenadeMessage { get; set; } = "Watch out!";
public string ExplosionMessage { get; set; } = "How did you even die '-'"; public string PocketDimensionMessage { get; set; } = "I hear he likes to see people suffer...";
public string AntiMicroMessage { get; set; } = "Where did all the micros go..."; public string PositiveEffectMessage { get; set; } = "You feel slightly better";
public string GrenadeMessage { get; set; } = "Watch out!"; public string AdvancedPositiveEffectMessage { get; set; } = "You feel better";
public string PocketDimensionMessage { get; set; } = "I hear he likes to see people suffer..."; public string NegativeEffectMessage { get; set; } = "You feel worse";
public string PositiveEffectMessage { get; set; } = "You feel slightly better"; public string AdvancedNegativeEffectMessage { get; set; } = "You feel like you could die any second";
public string AdvancedPositiveEffectMessage { get; set; } = "You feel better"; public string SwitchInventoryMessage { get; set; } = "Whoops... looks like something happened to your items!";
public string NegativeEffectMessage { get; set; } = "You feel worse"; }
public string AdvancedNegativeEffectMessage { get; set; } = "You feel like you could die any second";
public string SwitchInventoryMessage { get; set; } = "Whoops... looks like something happened to your items!"; public class GamblingCoinGameplayConfig
} {
public float WarheadTimeIncrease { get; set; } = 20f;
public class GamblingCoinGameplayConfig public ushort BroadcastDuration { get; set; } = 3;
{ public float TeleportHeightOffset { get; set; } = 1f;
public float WarheadTimeIncrease { get; set; } = 20f; public int MaxMicrosToRemove { get; set; } = 8;
public ushort BroadcastDuration { get; set; } = 3;
public float TeleportHeightOffset { get; set; } = 1f; public ItemPoolConfig Items { get; set; } = new();
public int MaxMicrosToRemove { get; set; } = 8; public EffectConfig Effects { get; set; } = new();
}
public ItemPoolConfig Items { get; set; } = new();
public EffectConfig Effects { get; set; } = new(); public class ItemPoolConfig
} {
public ItemType[] CommonItems { get; set; } =
public class ItemPoolConfig {
{ ItemType.KeycardJanitor,
public ItemType[] CommonItems { get; set; } = { ItemType.KeycardScientist,
ItemType.KeycardJanitor, ItemType.Medkit,
ItemType.KeycardScientist, ItemType.Painkillers,
ItemType.Medkit, ItemType.Radio,
ItemType.Painkillers, ItemType.Flashlight
ItemType.Radio, };
ItemType.Flashlight
}; public ItemType[] UncommonItems { get; set; } =
{
public ItemType[] UncommonItems { get; set; } = { ItemType.KeycardZoneManager,
ItemType.KeycardZoneManager, ItemType.KeycardGuard,
ItemType.KeycardGuard, ItemType.KeycardResearchCoordinator,
ItemType.KeycardResearchCoordinator, ItemType.Adrenaline,
ItemType.Adrenaline, ItemType.ArmorLight,
ItemType.ArmorLight, ItemType.GrenadeFlash
ItemType.GrenadeFlash };
};
public ItemType[] RareItems { get; set; } =
public ItemType[] RareItems { get; set; } = { {
ItemType.KeycardMTFPrivate, ItemType.KeycardMTFPrivate,
ItemType.KeycardContainmentEngineer, ItemType.KeycardContainmentEngineer,
ItemType.KeycardMTFOperative, ItemType.KeycardMTFOperative,
ItemType.ArmorCombat, ItemType.ArmorCombat,
ItemType.ArmorHeavy, ItemType.ArmorHeavy,
ItemType.SCP330, ItemType.SCP330,
ItemType.Lantern, ItemType.Lantern,
ItemType.GrenadeHE ItemType.GrenadeHE
}; };
public ItemType[] EpicItems { get; set; } = { public ItemType[] EpicItems { get; set; } =
ItemType.KeycardFacilityManager, {
ItemType.KeycardChaosInsurgency, ItemType.KeycardFacilityManager,
ItemType.KeycardMTFCaptain, ItemType.KeycardChaosInsurgency,
ItemType.SCP500 ItemType.KeycardMTFCaptain,
}; ItemType.SCP500
};
public ItemType[] LegendaryItems { get; set; } = {
ItemType.KeycardO5, public ItemType[] LegendaryItems { get; set; } =
ItemType.MicroHID, {
ItemType.Jailbird, ItemType.KeycardO5,
ItemType.GunCom45, ItemType.MicroHID,
ItemType.Coin ItemType.Jailbird,
}; ItemType.GunCom45,
} ItemType.Coin
};
public class EffectConfig }
{
public AdvancedEffectSettings AdvancedPositive { get; set; } = new() public class EffectConfig
{ {
Effects = new[] { nameof(Invisible), nameof(DamageReduction), nameof(MovementBoost) }, public AdvancedEffectSettings AdvancedPositive { get; set; } = new()
Settings = new Dictionary<string, EffectSettings> {
{ Effects = new[] { nameof(Invisible), nameof(DamageReduction), nameof(MovementBoost) },
{ nameof(Invisible), new EffectSettings(1, 5f, true) }, Settings = new Dictionary<string, EffectSettings>
{ nameof(DamageReduction), new EffectSettings(100, 8f, false) }, {
{ nameof(MovementBoost), new EffectSettings(40, 2f, false) } { nameof(Invisible), new EffectSettings(1, 5f, true) },
} { nameof(DamageReduction), new EffectSettings(100, 8f, false) },
}; { nameof(MovementBoost), new EffectSettings(40, 2f, false) }
}
public AdvancedEffectSettings Positive { get; set; } = new() };
{
Effects = new[] { nameof(Invigorated), nameof(RainbowTaste), nameof(Vitality), nameof(BodyshotReduction) }, public AdvancedEffectSettings Positive { get; set; } = new()
Settings = new Dictionary<string, EffectSettings> {
{ Effects = new[] { nameof(Invigorated), nameof(RainbowTaste), nameof(Vitality), nameof(BodyshotReduction) },
{ nameof(Invigorated), new EffectSettings(1, 5f, true) }, Settings = new Dictionary<string, EffectSettings>
{ nameof(RainbowTaste), new EffectSettings(2, 10f, true) }, {
{ nameof(Vitality), new EffectSettings(1, 10f, true) }, { nameof(Invigorated), new EffectSettings(1, 5f, true) },
{ nameof(BodyshotReduction), new EffectSettings(4, 5f, true) } { nameof(RainbowTaste), new EffectSettings(2, 10f, true) },
} { nameof(Vitality), new EffectSettings(1, 10f, true) },
}; { nameof(BodyshotReduction), new EffectSettings(4, 5f, true) }
}
public AdvancedEffectSettings Negative { get; set; } = new() };
{
Effects = new[] { nameof(Asphyxiated), nameof(AmnesiaVision), nameof(Bleeding), nameof(Blurred), public AdvancedEffectSettings Negative { get; set; } = new()
nameof(Concussed), nameof(Deafened), nameof(Disabled) }, {
Settings = new Dictionary<string, EffectSettings> Effects = new[]
{ {
{ nameof(Asphyxiated), new EffectSettings(1, 10f, true) }, nameof(Asphyxiated), nameof(AmnesiaVision), nameof(Bleeding), nameof(Blurred),
{ nameof(AmnesiaVision), new EffectSettings(1, 5f, true) }, nameof(Concussed), nameof(Deafened), nameof(Disabled)
{ nameof(Bleeding), new EffectSettings(1, 5f, true) }, },
{ nameof(Blurred), new EffectSettings(1, 5f, true) }, Settings = new Dictionary<string, EffectSettings>
{ nameof(Concussed), new EffectSettings(1, 5f, true) }, {
{ nameof(Deafened), new EffectSettings(1, 5f, true) }, { nameof(Asphyxiated), new EffectSettings(1, 10f, true) },
{ nameof(Disabled), new EffectSettings(1, 5f, true) } { nameof(AmnesiaVision), new EffectSettings(1, 5f, true) },
} { nameof(Bleeding), new EffectSettings(1, 5f, true) },
}; { nameof(Blurred), new EffectSettings(1, 5f, true) },
{ nameof(Concussed), new EffectSettings(1, 5f, true) },
public AdvancedEffectSettings AdvancedNegative { get; set; } = new() { nameof(Deafened), new EffectSettings(1, 5f, true) },
{ { nameof(Disabled), new EffectSettings(1, 5f, true) }
Effects = new[] { nameof(InsufficientLighting), nameof(AmnesiaVision), nameof(Burned) }, }
Settings = new Dictionary<string, EffectSettings> };
{
{ nameof(InsufficientLighting), new EffectSettings(1, 30f, true) }, public AdvancedEffectSettings AdvancedNegative { get; set; } = new()
{ nameof(AmnesiaVision), new EffectSettings(3, 30f, true) }, {
{ nameof(Burned), new EffectSettings(3, 60f, true) }, Effects = new[] { nameof(InsufficientLighting), nameof(AmnesiaVision), nameof(Burned) },
} Settings = new Dictionary<string, EffectSettings>
}; {
} { nameof(InsufficientLighting), new EffectSettings(1, 30f, true) },
{ nameof(AmnesiaVision), new EffectSettings(3, 30f, true) },
public class AdvancedEffectSettings { nameof(Burned), new EffectSettings(3, 60f, true) }
{ }
public string[] Effects { get; set; } };
public Dictionary<string, EffectSettings> Settings { get; set; } }
public AdvancedEffectSettings(){} public class AdvancedEffectSettings
} {
public string[] Effects { get; set; }
public class EffectSettings public Dictionary<string, EffectSettings> Settings { get; set; }
{ }
public byte Intensity { get; set; }
public float Duration { get; set; } public class EffectSettings
public bool AddDuration { get; set; } {
public EffectSettings(byte intensity, float duration, bool addDuration)
public EffectSettings(byte intensity, float duration, bool addDuration) {
{ Intensity = intensity;
Intensity = intensity; Duration = duration;
Duration = duration; AddDuration = addDuration;
AddDuration = addDuration; }
}
public EffectSettings()
public EffectSettings(){} {
} }
public byte Intensity { get; set; }
public float Duration { get; set; }
public bool AddDuration { get; set; }
} }

View File

@ -1,240 +1,227 @@
using System.Diagnostics;
using System.Numerics;
using CustomPlayerEffects;
using InventorySystem.Items;
using LabApi.Events.Arguments.PlayerEvents; using LabApi.Events.Arguments.PlayerEvents;
using LabApi.Features.Wrappers; using LabApi.Features.Wrappers;
using MapGeneration; using MapGeneration;
using Mirror; using Mirror;
using PlayerRoles; using PlayerRoles;
using Respawning.Waves; using Respawning;
using Utils; using UnityEngine;
using Logger = LabApi.Features.Console.Logger;
using MicroHIDItem = InventorySystem.Items.MicroHID.MicroHIDItem; using MicroHIDItem = InventorySystem.Items.MicroHID.MicroHIDItem;
using Random = UnityEngine.Random; using Random = UnityEngine.Random;
namespace GamblingCoin namespace GamblingCoin;
public class GamblingCoinEventHandler
{ {
public class GamblingCoinEventHandler private readonly WeightedRandomExecutor<PlayerFlippedCoinEventArgs> _executor;
public GamblingCoinEventHandler()
{ {
private readonly WeightedRandomExecutor<PlayerFlippedCoinEventArgs> _executor; var configMessages = Plugin.Singleton.ConfigMessages;
var configGameplay = Plugin.Singleton.ConfigGameplay;
var configChances = Plugin.Singleton.ConfigChances;
public GamblingCoinEventHandler() _executor = new WeightedRandomExecutor<PlayerFlippedCoinEventArgs>();
{
var configMessages = Plugin.Singleton.ConfigMessages;
var configGameplay = Plugin.Singleton.ConfigGameplay;
var configChances = Plugin.Singleton.ConfigChances;
_executor = new WeightedRandomExecutor<PlayerFlippedCoinEventArgs>(); _executor
.AddAction(_ =>
_executor
.AddAction(_ =>
{
Warhead.DetonationTime += configGameplay.WarheadTimeIncrease;
Warhead.Start(suppressSubtitles: true);
}, configChances.NukeChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.SpawnWaveMessage, configGameplay.BroadcastDuration);
if(GetPlayers().Any(player=>player.Role == RoleTypeId.Spectator)) {
Respawning.WaveManager.InitiateRespawn(Respawning.WaveManager.Waves[Random.Range(0, Respawning.WaveManager.Waves.Count)]);
}
}, configChances.SpawnWaveChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.ItemSpawnMessage, configGameplay.BroadcastDuration);
SpawnRandomItemAtPlayer(x.Player, configGameplay.Items.CommonItems);
}, configChances.CommonItemChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.UncommonItemSpawnMessage, configGameplay.BroadcastDuration);
SpawnRandomItemAtPlayer(x.Player, configGameplay.Items.UncommonItems);
}, configChances.UncommonItemChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.RareItemSpawnMessage, configGameplay.BroadcastDuration);
SpawnRandomItemAtPlayer(x.Player, configGameplay.Items.RareItems);
}, configChances.RareItemChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.EpicItemSpawnMessage, configGameplay.BroadcastDuration);
SpawnRandomItemAtPlayer(x.Player, configGameplay.Items.EpicItems);
}, configChances.EpicItemChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.LegendaryItemSpawnMessage, configGameplay.BroadcastDuration);
var player = x.Player;
var items = configGameplay.Items.LegendaryItems;
var itemIndex = Random.Range(0, items.Length);
var item = items[itemIndex];
var pickup = Pickup.Create(item, player.Position + new UnityEngine.Vector3(0,1,0));
if (pickup == null) return;
if (item is ItemType.MicroHID)
{
var host = Player.List.First(player1 => player1.IsHost);
var micro = host.AddItem(pickup)!.Base;
var microItem = (MicroHIDItem)micro;
microItem.EnergyManager.ServerSetEnergy(microItem.ItemId.SerialNumber, 100);
var newPickup = host.DropItem(micro);
newPickup.Position = player.Position + new UnityEngine.Vector3(0, 1, 0);
return;
}
pickup.Spawn();
}, configChances.LegendaryItemChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.RandomTeleportMessage, configGameplay.BroadcastDuration);
var randomRoom = Map.GetRandomRoom();
if(randomRoom == null) return;
var isInOtherZone = randomRoom is { Zone: FacilityZone.Other };
var isDetonated = Warhead.IsDetonated;
var isDecontaminating = Decontamination.IsDecontaminating;
var isInDetonatedZone = isDetonated && randomRoom.Zone is FacilityZone.HeavyContainment
or FacilityZone.LightContainment or FacilityZone.Entrance;
var isInDecontaminatedZone = isDecontaminating && randomRoom.Zone is FacilityZone.LightContainment;
while (isInOtherZone || isInDetonatedZone || isInDecontaminatedZone)
{
randomRoom = Map.GetRandomRoom();
if(randomRoom == null) return;
isInOtherZone = randomRoom is { Zone: FacilityZone.Other };
isInDetonatedZone = isDetonated && randomRoom.Zone is FacilityZone.HeavyContainment
or FacilityZone.LightContainment or FacilityZone.Entrance;
isInDecontaminatedZone = isDecontaminating && randomRoom.Zone is FacilityZone.LightContainment;
}
var newPos = randomRoom.Position;
x.Player.Position = newPos + new UnityEngine.Vector3(0, configGameplay.TeleportHeightOffset, 0);;
}, configChances.RandomTeleportChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.StealItemMessage, configGameplay.BroadcastDuration);
if (x.Player.CurrentItem != null) x.Player.DropItem(x.Player.CurrentItem);
}, configChances.StealItemChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.ExplosionMessage, configGameplay.BroadcastDuration);
x.Player.ClearInventory();
TimedGrenadeProjectile.SpawnActive(x.Player.Position, ItemType.GrenadeHE, x.Player);
}, configChances.ExplosionChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.AntiMicroMessage, configGameplay.BroadcastDuration);
GetPlayers().ForEach(p => { p.RemoveItem(ItemType.MicroHID, configGameplay.MaxMicrosToRemove); });
//TODO: remove *all* micros
}, configChances.AntiMicroChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.GrenadeMessage, configGameplay.BroadcastDuration);
TimedGrenadeProjectile.SpawnActive(x.Player.Position, ItemType.GrenadeHE, x.Player, 2);
}, configChances.GrenadeChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.PocketDimensionMessage, configGameplay.BroadcastDuration);
PocketDimension.ForceInside(x.Player);
},
configChances.PocketDimensionChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.AdvancedPositiveEffectMessage, configGameplay.BroadcastDuration);
ApplyRandomEffect(x.Player, configGameplay.Effects.AdvancedPositive);
}, configChances.AdvancedPositiveEffectChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.PositiveEffectMessage, configGameplay.BroadcastDuration);
ApplyRandomEffect(x.Player, configGameplay.Effects.Positive);
}, configChances.PositiveEffectChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.NegativeEffectMessage, configGameplay.BroadcastDuration);
ApplyRandomEffect(x.Player, configGameplay.Effects.Negative);
}, configChances.NegativeEffectChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.AdvancedNegativeEffectMessage, configGameplay.BroadcastDuration);
ApplyRandomEffect(x.Player, configGameplay.Effects.AdvancedNegative);
}, configChances.AdvancedNegativeEffectChance)
.AddAction(x =>
{
var players = GetPlayers();
var randomPlayer = players[Random.Range(0,GetPlayers().Length)];
while(randomPlayer.RoleBase.Team is Team.Dead or Team.SCPs) randomPlayer = players[Random.Range(0,GetPlayers().Length)];
x.Player.SendBroadcast(configMessages.SwitchInventoryMessage, configGameplay.BroadcastDuration);
randomPlayer.SendBroadcast(configMessages.SwitchInventoryMessage, configGameplay.BroadcastDuration);
var randomPlayerItems = new List<Item>();
randomPlayer.Items.CopyTo(randomPlayerItems);
var items = x.Player.Items;
randomPlayer.ClearInventory();
foreach (var itemBase in items)
{
randomPlayer.AddItem(itemBase.Type);
}
x.Player.ClearInventory();
foreach (var randomPlayerItem in randomPlayerItems)
{
x.Player.AddItem(randomPlayerItem.Type);
}
}, configChances.SwitchInventoryChance)
.AddAction(x =>
{
x.Player.CurrentItem?.DropItem().Destroy();
}, configChances.RemoveCoinChance);
return;
void ApplyRandomEffect(Player player, AdvancedEffectSettings settings)
{ {
var effectChosen = settings.Effects[Random.Range(0, settings.Effects.Length)]; Warhead.DetonationTime += configGameplay.WarheadTimeIncrease;
var effectSettings = settings.Settings[effectChosen]; Warhead.Start(suppressSubtitles: true);
}, configChances.NukeChance)
player.ReferenceHub.playerEffectsController.ChangeState(effectChosen, effectSettings.Intensity, effectSettings.Duration, effectSettings.AddDuration); .AddAction(x =>
}
void SpawnItemAtPlayer(Player player, ItemType item)
{ {
var pickup = Pickup.Create(item, player.Position + new UnityEngine.Vector3(0,1,0)); x.Player.SendBroadcast(configMessages.SpawnWaveMessage, configGameplay.BroadcastDuration);
if (GetPlayers().Any(player => player.Role == RoleTypeId.Spectator))
WaveManager.InitiateRespawn(WaveManager.Waves[Random.Range(0, WaveManager.Waves.Count)]);
}, configChances.SpawnWaveChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.ItemSpawnMessage, configGameplay.BroadcastDuration);
SpawnRandomItemAtPlayer(x.Player, configGameplay.Items.CommonItems);
}, configChances.CommonItemChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.UncommonItemSpawnMessage, configGameplay.BroadcastDuration);
SpawnRandomItemAtPlayer(x.Player, configGameplay.Items.UncommonItems);
}, configChances.UncommonItemChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.RareItemSpawnMessage, configGameplay.BroadcastDuration);
SpawnRandomItemAtPlayer(x.Player, configGameplay.Items.RareItems);
}, configChances.RareItemChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.EpicItemSpawnMessage, configGameplay.BroadcastDuration);
SpawnRandomItemAtPlayer(x.Player, configGameplay.Items.EpicItems);
}, configChances.EpicItemChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.LegendaryItemSpawnMessage, configGameplay.BroadcastDuration);
var player = x.Player;
var items = configGameplay.Items.LegendaryItems;
var itemIndex = Random.Range(0, items.Length);
var item = items[itemIndex];
var pickup = Pickup.Create(item, player.Position + new Vector3(0, 1, 0));
if (pickup == null) return; if (pickup == null) return;
if (item is ItemType.MicroHID)
{
var host = Player.List.First(player1 => player1.IsHost);
var micro = host.AddItem(pickup)!.Base;
var microItem = (MicroHIDItem)micro;
microItem.EnergyManager.ServerSetEnergy(microItem.ItemId.SerialNumber, 100);
var newPickup = host.DropItem(micro);
newPickup.Position = player.Position + new Vector3(0, 1, 0);
return;
}
pickup.Spawn(); pickup.Spawn();
} }, configChances.LegendaryItemChance)
.AddAction(x =>
void SpawnRandomItemAtPlayer(Player player, ItemType[] items)
{ {
var itemIndex = Random.Range(0, items.Length); x.Player.SendBroadcast(configMessages.RandomTeleportMessage, configGameplay.BroadcastDuration);
SpawnItemAtPlayer(player, items[itemIndex]); var randomRoom = Map.GetRandomRoom();
} if (randomRoom == null) return;
Player[] GetPlayers() var isInOtherZone = randomRoom is { Zone: FacilityZone.Other };
var isDetonated = Warhead.IsDetonated;
var isDecontaminating = Decontamination.IsDecontaminating;
var isInDetonatedZone = isDetonated && randomRoom.Zone is FacilityZone.HeavyContainment
or FacilityZone.LightContainment or FacilityZone.Entrance;
var isInDecontaminatedZone = isDecontaminating && randomRoom.Zone is FacilityZone.LightContainment;
while (isInOtherZone || isInDetonatedZone || isInDecontaminatedZone)
{
randomRoom = Map.GetRandomRoom();
if (randomRoom == null) return;
isInOtherZone = randomRoom is { Zone: FacilityZone.Other };
isInDetonatedZone = isDetonated && randomRoom.Zone is FacilityZone.HeavyContainment
or FacilityZone.LightContainment or FacilityZone.Entrance;
isInDecontaminatedZone = isDecontaminating && randomRoom.Zone is FacilityZone.LightContainment;
}
var newPos = randomRoom.Position;
x.Player.Position = newPos + new Vector3(0, configGameplay.TeleportHeightOffset, 0);
;
}, configChances.RandomTeleportChance)
.AddAction(x =>
{ {
return Player.ReadyList.ToArray(); x.Player.SendBroadcast(configMessages.StealItemMessage, configGameplay.BroadcastDuration);
}
if (x.Player.CurrentItem != null) x.Player.DropItem(x.Player.CurrentItem);
}, configChances.StealItemChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.ExplosionMessage, configGameplay.BroadcastDuration);
x.Player.ClearInventory();
TimedGrenadeProjectile.SpawnActive(x.Player.Position, ItemType.GrenadeHE, x.Player);
}, configChances.ExplosionChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.AntiMicroMessage, configGameplay.BroadcastDuration);
GetPlayers().ForEach(p => { p.RemoveItem(ItemType.MicroHID, configGameplay.MaxMicrosToRemove); });
//TODO: remove *all* micros
}, configChances.AntiMicroChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.GrenadeMessage, configGameplay.BroadcastDuration);
TimedGrenadeProjectile.SpawnActive(x.Player.Position, ItemType.GrenadeHE, x.Player, 2);
}, configChances.GrenadeChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.PocketDimensionMessage, configGameplay.BroadcastDuration);
PocketDimension.ForceInside(x.Player);
},
configChances.PocketDimensionChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.AdvancedPositiveEffectMessage, configGameplay.BroadcastDuration);
ApplyRandomEffect(x.Player, configGameplay.Effects.AdvancedPositive);
}, configChances.AdvancedPositiveEffectChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.PositiveEffectMessage, configGameplay.BroadcastDuration);
ApplyRandomEffect(x.Player, configGameplay.Effects.Positive);
}, configChances.PositiveEffectChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.NegativeEffectMessage, configGameplay.BroadcastDuration);
ApplyRandomEffect(x.Player, configGameplay.Effects.Negative);
}, configChances.NegativeEffectChance)
.AddAction(x =>
{
x.Player.SendBroadcast(configMessages.AdvancedNegativeEffectMessage, configGameplay.BroadcastDuration);
ApplyRandomEffect(x.Player, configGameplay.Effects.AdvancedNegative);
}, configChances.AdvancedNegativeEffectChance)
.AddAction(x =>
{
var players = GetPlayers();
var randomPlayer = players[Random.Range(0, GetPlayers().Length)];
while (randomPlayer.RoleBase.Team is Team.Dead or Team.SCPs)
randomPlayer = players[Random.Range(0, GetPlayers().Length)];
x.Player.SendBroadcast(configMessages.SwitchInventoryMessage, configGameplay.BroadcastDuration);
randomPlayer.SendBroadcast(configMessages.SwitchInventoryMessage, configGameplay.BroadcastDuration);
var randomPlayerItems = new List<Item>();
randomPlayer.Items.CopyTo(randomPlayerItems);
var items = x.Player.Items;
randomPlayer.ClearInventory();
foreach (var itemBase in items) randomPlayer.AddItem(itemBase.Type);
x.Player.ClearInventory();
foreach (var randomPlayerItem in randomPlayerItems) x.Player.AddItem(randomPlayerItem.Type);
}, configChances.SwitchInventoryChance)
.AddAction(x => { x.Player.CurrentItem?.DropItem().Destroy(); }, configChances.RemoveCoinChance);
return;
void ApplyRandomEffect(Player player, AdvancedEffectSettings settings)
{
var effectChosen = settings.Effects[Random.Range(0, settings.Effects.Length)];
var effectSettings = settings.Settings[effectChosen];
player.ReferenceHub.playerEffectsController.ChangeState(effectChosen, effectSettings.Intensity,
effectSettings.Duration, effectSettings.AddDuration);
} }
public void OnFlippedCoin(PlayerFlippedCoinEventArgs ev) void SpawnItemAtPlayer(Player player, ItemType item)
{ {
_executor.Execute(ev); var pickup = Pickup.Create(item, player.Position + new Vector3(0, 1, 0));
if (pickup == null) return;
pickup.Spawn();
}
void SpawnRandomItemAtPlayer(Player player, ItemType[] items)
{
var itemIndex = Random.Range(0, items.Length);
SpawnItemAtPlayer(player, items[itemIndex]);
}
Player[] GetPlayers()
{
return Player.ReadyList.ToArray();
} }
} }
public void OnFlippedCoin(PlayerFlippedCoinEventArgs ev)
{
_executor.Execute(ev);
}
} }

View File

@ -2,30 +2,12 @@ namespace GamblingCoin;
public class WeightedRandomExecutor<TEvent> public class WeightedRandomExecutor<TEvent>
{ {
private class WeightedAction
{
public Action<TEvent> Action { get; }
public double Weight { get; }
public WeightedAction(Action<TEvent> action, double weight)
{
if (weight <= 0)
throw new ArgumentOutOfRangeException(
nameof(weight),
"Weight must be positive."
);
Action = action ?? throw new ArgumentNullException(nameof(action));
Weight = weight;
}
}
private readonly List<WeightedAction> _actions = new(); private readonly List<WeightedAction> _actions = new();
private readonly Random _random = new(); private readonly Random _random = new();
private double _totalWeight; private double _totalWeight;
/// <summary> /// <summary>
/// Adds a function to be potentially executed, along with its weight. /// Adds a function to be potentially executed, along with its weight.
/// </summary> /// </summary>
/// <param name="action">The function to add. It must accept an argument of type TEvent.</param> /// <param name="action">The function to add. It must accept an argument of type TEvent.</param>
/// <param name="weight">The positive weight for this function. Higher weights mean higher probability.</param> /// <param name="weight">The positive weight for this function. Higher weights mean higher probability.</param>
@ -39,26 +21,22 @@ public class WeightedRandomExecutor<TEvent>
} }
/// <summary> /// <summary>
/// Executes one of the added functions randomly based on their weights. /// Executes one of the added functions randomly based on their weights.
/// The chosen function will be called with the provided 'ev' argument. /// The chosen function will be called with the provided 'ev' argument.
/// </summary> /// </summary>
/// <param name="ev">The event argument to pass to the chosen function.</param> /// <param name="ev">The event argument to pass to the chosen function.</param>
/// <exception cref="InvalidOperationException">Thrown if no actions have been added.</exception> /// <exception cref="InvalidOperationException">Thrown if no actions have been added.</exception>
public void Execute(TEvent ev) public void Execute(TEvent ev)
{ {
if (_actions.Count == 0) if (_actions.Count == 0)
{
throw new InvalidOperationException( throw new InvalidOperationException(
"No actions have been added to execute." "No actions have been added to execute."
); );
}
if (_totalWeight <= 0) // Should not happen if AddAction validates weight > 0 if (_totalWeight <= 0) // Should not happen if AddAction validates weight > 0
{
throw new InvalidOperationException( throw new InvalidOperationException(
"Total weight is zero or negative, cannot execute." "Total weight is zero or negative, cannot execute."
); );
}
var randomNumber = _random.NextDouble() * _totalWeight; var randomNumber = _random.NextDouble() * _totalWeight;
double cumulativeWeight = 0; double cumulativeWeight = 0;
@ -74,9 +52,24 @@ public class WeightedRandomExecutor<TEvent>
// Fallback in case of floating point inaccuracies, // Fallback in case of floating point inaccuracies,
// or if somehow randomNumber was exactly _totalWeight (NextDouble is < 1.0) // or if somehow randomNumber was exactly _totalWeight (NextDouble is < 1.0)
// This should ideally pick the last item if all weights were summed up. // This should ideally pick the last item if all weights were summed up.
if (_actions.Any()) if (_actions.Any()) _actions.Last().Action(ev);
}
private class WeightedAction
{
public WeightedAction(Action<TEvent> action, double weight)
{ {
_actions.Last().Action(ev); if (weight <= 0)
throw new ArgumentOutOfRangeException(
nameof(weight),
"Weight must be positive."
);
Action = action ?? throw new ArgumentNullException(nameof(action));
Weight = weight;
} }
public Action<TEvent> Action { get; }
public double Weight { get; }
} }
} }

View File

@ -1,25 +1,24 @@
using CustomPlayerEffects; using CustomPlayerEffects;
using LabApi.Events.Arguments.Scp0492Events;
using LabApi.Events.Handlers;
using LabApi.Features;
using LabApi.Loader.Features.Plugins;
using InventorySystem.Items.Usables.Scp330; using InventorySystem.Items.Usables.Scp330;
using LabApi.Events.Arguments.PlayerEvents; using LabApi.Events.Arguments.PlayerEvents;
using LabApi.Events.Arguments.Scp0492Events;
using LabApi.Events.Arguments.ServerEvents; using LabApi.Events.Arguments.ServerEvents;
using LabApi.Events.Handlers;
using LabApi.Features;
using LabApi.Features.Wrappers; using LabApi.Features.Wrappers;
using LabApi.Loader.Features.Plugins;
namespace GrowingZombies; namespace GrowingZombies;
public class GrowingZombies : Plugin public class GrowingZombies : Plugin
{ {
private readonly Dictionary<Player, int> _zombieCorpseCount = new();
public override string Name => "GrowingZombies"; public override string Name => "GrowingZombies";
public override string Author => "Code002Lover"; public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0); public override Version Version { get; } = new(1, 0, 0);
public override string Description => "Makes zombies grow stronger as they eat more"; public override string Description => "Makes zombies grow stronger as they eat more";
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
private readonly Dictionary<Player, int> _zombieCorpseCount = new();
public override void Enable() public override void Enable()
{ {
Scp0492Events.ConsumedCorpse += OnZombieEat; Scp0492Events.ConsumedCorpse += OnZombieEat;
@ -65,9 +64,7 @@ public class GrowingZombies : Plugin
// Add damage resistance after eating multiple corpses // Add damage resistance after eating multiple corpses
var damageResistance = (byte)Math.Min(0.5 - corpsesEaten * 0.5f, 2f); var damageResistance = (byte)Math.Min(0.5 - corpsesEaten * 0.5f, 2f);
if (corpsesEaten >= 3) if (corpsesEaten >= 3)
{
ev.Player.ReferenceHub.playerEffectsController.ChangeState<DamageReduction>(damageResistance, 20); ev.Player.ReferenceHub.playerEffectsController.ChangeState<DamageReduction>(damageResistance, 20);
}
// Add regeneration effect after eating multiple corpses // Add regeneration effect after eating multiple corpses
if (corpsesEaten < 5) return; if (corpsesEaten < 5) return;

View File

@ -23,24 +23,18 @@
<Reference Include="Assembly-CSharp"> <Reference Include="Assembly-CSharp">
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath> <HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="Assembly-CSharp-firstpass">
<HintPath>..\dependencies\Assembly-CSharp-firstpass.dll</HintPath>
</Reference>
<Reference Include="Mirror"> <Reference Include="Mirror">
<HintPath>..\dependencies\Mirror.dll</HintPath> <HintPath>..\dependencies\Mirror.dll</HintPath>
</Reference> </Reference>
<Reference Include="NorthwoodLib"> <Reference Include="NorthwoodLib">
<HintPath>..\dependencies\NorthwoodLib.dll</HintPath> <HintPath>..\dependencies\NorthwoodLib.dll</HintPath>
</Reference> </Reference>
<Reference Include="Pooling">
<HintPath>..\dependencies\Pooling.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule"> <Reference Include="UnityEngine.CoreModule">
<HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath> <HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -12,7 +12,7 @@ public enum DoorType
public class DoorLockConfiguration public class DoorLockConfiguration
{ {
public Dictionary<DoorType, float> LockDurations { get; set; }= new() public Dictionary<DoorType, float> LockDurations { get; set; } = new()
{ {
{ DoorType.Normal, 5f }, { DoorType.Normal, 5f },
{ DoorType.Gate, 8f }, { DoorType.Gate, 8f },

View File

@ -1,5 +1,4 @@
using System.Collections; using System.Collections;
using Interactables.Interobjects;
using Interactables.Interobjects.DoorButtons; using Interactables.Interobjects.DoorButtons;
using Interactables.Interobjects.DoorUtils; using Interactables.Interobjects.DoorUtils;
using LabApi.Events.Arguments.PlayerEvents; using LabApi.Events.Arguments.PlayerEvents;
@ -10,224 +9,175 @@ using UnityEngine;
using KeycardItem = InventorySystem.Items.Keycards.KeycardItem; using KeycardItem = InventorySystem.Items.Keycards.KeycardItem;
using Logger = LabApi.Features.Console.Logger; using Logger = LabApi.Features.Console.Logger;
namespace KeycardButModern namespace KeycardButModern;
public class Plugin : LabApi.Loader.Features.Plugins.Plugin
{ {
public class Plugin: LabApi.Loader.Features.Plugins.Plugin public static Plugin Singleton;
public DoorLockConfiguration DoorLockConfiguration;
public override string Name => "KeycardButModern";
public override string Description => "Ever thought you wanted your keycard implanted in your body? No? Same.";
public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0);
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
public override void LoadConfigs()
{ {
public override string Name => "KeycardButModern"; base.LoadConfigs();
public override string Description => "Ever thought you wanted your keycard implanted in your body? No? Same.";
public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0);
public override Version RequiredApiVersion { get; } = new (LabApiProperties.CompiledVersion);
public DoorLockConfiguration DoorLockConfiguration; DoorLockConfiguration = this.LoadConfig<DoorLockConfiguration>("door_locks.yml");
public static Plugin Singleton; }
public override void LoadConfigs() private void OnInteractingDoor(PlayerInteractingDoorEventArgs ev)
{
if (ev.CanOpen) return;
if (ev.Door.IsLocked) return;
foreach (var playerItem in ev.Player.Items)
{ {
base.LoadConfigs(); //is keycard?
if (playerItem.Type is > ItemType.KeycardO5 and < ItemType.KeycardCustomTaskForce) continue;
if (playerItem.Base is not KeycardItem keycardItem) continue;
DoorLockConfiguration = this.LoadConfig< DoorLockConfiguration > ("door_locks.yml"); if (!ev.Door.Base.CheckPermissions(keycardItem, out _)) continue;
} ev.Door.IsOpened = !ev.Door.IsOpened;
private void OnInteractingDoor(PlayerInteractingDoorEventArgs ev) return;
{
if (ev.CanOpen)
{
return;
}
if (ev.Door.IsLocked)
{
return;
}
foreach (var playerItem in ev.Player.Items)
{
//is keycard?
if (playerItem.Type is > ItemType.KeycardO5 and < ItemType.KeycardCustomTaskForce) continue;
if (playerItem.Base is not KeycardItem keycardItem)
{
continue;
}
if (!ev.Door.Base.CheckPermissions(keycardItem, out _)) continue;
ev.Door.IsOpened = !ev.Door.IsOpened;
return;
}
}
private void OnInteractingGenerator(PlayerInteractingGeneratorEventArgs ev)
{
if (!ev.IsAllowed)
{
return;
}
if (ev.Player.CurrentItem?.Base is KeycardItem keycard)
{
if (ev.Generator.Base.CheckPermissions(keycard, out _))
{
ev.Generator.IsUnlocked = true;
return;
}
}
if (ev.Generator.IsUnlocked)
{
return;
}
foreach (var playerItem in ev.Player.Items)
{
//is keycard?
if (playerItem.Type is > ItemType.KeycardO5 and < ItemType.KeycardCustomTaskForce) continue;
if (playerItem.Base is not KeycardItem keycardItem)
{
continue;
}
if (!ev.Generator.Base.CheckPermissions(keycardItem, out _)) continue;
ev.Generator.IsOpen = !ev.Generator.IsOpen;
ev.Generator.IsUnlocked = true;
return;
}
}
private void OnInteractingLocker(PlayerInteractingLockerEventArgs ev)
{
if (!ev.IsAllowed)
{
return;
}
if (ev.Chamber.Base.RequiredPermissions == DoorPermissionFlags.None)
{
return;
}
if (ev.Player.CurrentItem?.Base is KeycardItem keycard)
{
if (ev.Chamber.Base.CheckPermissions(keycard, out _)) return;
}
foreach (var playerItem in ev.Player.Items)
{
//is keycard?
if (playerItem.Type is > ItemType.KeycardO5 and < ItemType.KeycardCustomTaskForce) continue;
if (playerItem.Base is not KeycardItem keycardItem)
{
continue;
}
if (!ev.Chamber.Base.CheckPermissions(keycardItem, out _)) continue;
ev.Chamber.IsOpen = !ev.Chamber.IsOpen;
return;
}
}
private void OnUnlockingWarhead(PlayerUnlockingWarheadButtonEventArgs ev)
{
if (ev.IsAllowed)
{
return;
}
foreach (var playerItem in ev.Player.Items)
{
//is keycard?
if (playerItem.Type is > ItemType.KeycardO5 and < ItemType.KeycardCustomTaskForce) continue;
if (playerItem.Base is not KeycardItem keycardItem)
{
continue;
}
if (!AlphaWarheadActivationPanel.Instance.CheckPermissions(keycardItem, out _)) continue;
ev.IsAllowed = true;
return;
}
}
private static void OnBulletHole(PlayerPlacedBulletHoleEventArgs ev)
{
var direction = (ev.HitPosition - ev.RaycastStart).normalized;
var distance = Vector3.Distance(ev.RaycastStart, ev.HitPosition);
var hits = Physics.RaycastAll(ev.RaycastStart, direction, distance);
foreach (var hit in hits)
{
ButtonVariant doorButton = hit.collider.GetComponent<LcdButton>();
if (!doorButton)
{
doorButton = hit.collider.GetComponent<CheckpointKeycardButton>();
}
if (!doorButton)
{
doorButton = hit.collider.GetComponent<KeycardButton>();
}
if (!doorButton)
{
doorButton = hit.collider.GetComponent<SimpleButton>();
}
if (!doorButton)
{
continue;
}
var doorVariant = DoorVariant.AllDoors.AsEnumerable()!.First(x => x.Buttons.Any(c=>c.GetInstanceID() == doorButton.GetInstanceID()));
doorVariant.ServerInteract(ev.Player.ReferenceHub, doorButton.ColliderId);
StartDoorLockCoroutine(doorVariant);
return;
}
}
public override void Enable()
{
Logger.Debug("starting...");
Singleton = this;
PlayerEvents.InteractingDoor += OnInteractingDoor;
PlayerEvents.InteractingGenerator += OnInteractingGenerator;
PlayerEvents.InteractingLocker += OnInteractingLocker;
PlayerEvents.UnlockingWarheadButton += OnUnlockingWarhead;
PlayerEvents.PlacedBulletHole += OnBulletHole;
}
private static void StartDoorLockCoroutine(DoorVariant door)
{
door.StartCoroutine(LockDoorCoroutine(door));
}
private static IEnumerator LockDoorCoroutine(DoorVariant door)
{
var doorType = DoorLockConfiguration.GetDoorType(door);
var lockDuration = Singleton.DoorLockConfiguration.LockDurations[doorType];
door.ServerChangeLock(DoorLockReason.SpecialDoorFeature, true);
yield return new WaitForSeconds(lockDuration);
door.ServerChangeLock(DoorLockReason.SpecialDoorFeature, false);
}
public override void Disable()
{
PlayerEvents.InteractingDoor -= OnInteractingDoor;
PlayerEvents.InteractingGenerator -= OnInteractingGenerator;
PlayerEvents.InteractingLocker -= OnInteractingLocker;
PlayerEvents.UnlockingWarheadButton -= OnUnlockingWarhead;
PlayerEvents.PlacedBulletHole -= OnBulletHole;
Logger.Debug("unloading...");
Singleton = null;
} }
} }
private void OnInteractingGenerator(PlayerInteractingGeneratorEventArgs ev)
{
if (!ev.IsAllowed) return;
if (ev.Player.CurrentItem?.Base is KeycardItem keycard)
if (ev.Generator.Base.CheckPermissions(keycard, out _))
{
ev.Generator.IsUnlocked = true;
return;
}
if (ev.Generator.IsUnlocked) return;
foreach (var playerItem in ev.Player.Items)
{
//is keycard?
if (playerItem.Type is > ItemType.KeycardO5 and < ItemType.KeycardCustomTaskForce) continue;
if (playerItem.Base is not KeycardItem keycardItem) continue;
if (!ev.Generator.Base.CheckPermissions(keycardItem, out _)) continue;
ev.Generator.IsOpen = !ev.Generator.IsOpen;
ev.Generator.IsUnlocked = true;
return;
}
}
private void OnInteractingLocker(PlayerInteractingLockerEventArgs ev)
{
if (!ev.IsAllowed) return;
if (ev.Chamber.Base.RequiredPermissions == DoorPermissionFlags.None) return;
if (ev.Player.CurrentItem?.Base is KeycardItem keycard)
if (ev.Chamber.Base.CheckPermissions(keycard, out _))
return;
foreach (var playerItem in ev.Player.Items)
{
//is keycard?
if (playerItem.Type is > ItemType.KeycardO5 and < ItemType.KeycardCustomTaskForce) continue;
if (playerItem.Base is not KeycardItem keycardItem) continue;
if (!ev.Chamber.Base.CheckPermissions(keycardItem, out _)) continue;
ev.Chamber.IsOpen = !ev.Chamber.IsOpen;
return;
}
}
private void OnUnlockingWarhead(PlayerUnlockingWarheadButtonEventArgs ev)
{
if (ev.IsAllowed) return;
foreach (var playerItem in ev.Player.Items)
{
//is keycard?
if (playerItem.Type is > ItemType.KeycardO5 and < ItemType.KeycardCustomTaskForce) continue;
if (playerItem.Base is not KeycardItem keycardItem) continue;
if (!AlphaWarheadActivationPanel.Instance.CheckPermissions(keycardItem, out _)) continue;
ev.IsAllowed = true;
return;
}
}
private static void OnBulletHole(PlayerPlacedBulletHoleEventArgs ev)
{
var direction = (ev.HitPosition - ev.RaycastStart).normalized;
var distance = Vector3.Distance(ev.RaycastStart, ev.HitPosition);
var hits = Physics.RaycastAll(ev.RaycastStart, direction, distance);
foreach (var hit in hits)
{
ButtonVariant doorButton = hit.collider.GetComponent<LcdButton>();
if (!doorButton) doorButton = hit.collider.GetComponent<CheckpointKeycardButton>();
if (!doorButton) doorButton = hit.collider.GetComponent<KeycardButton>();
if (!doorButton) doorButton = hit.collider.GetComponent<SimpleButton>();
if (!doorButton) continue;
var doorVariant = DoorVariant.AllDoors.AsEnumerable()!.First(x =>
x.Buttons.Any(c => c.GetInstanceID() == doorButton.GetInstanceID()));
doorVariant.ServerInteract(ev.Player.ReferenceHub, doorButton.ColliderId);
StartDoorLockCoroutine(doorVariant);
return;
}
}
public override void Enable()
{
Logger.Debug("starting...");
Singleton = this;
PlayerEvents.InteractingDoor += OnInteractingDoor;
PlayerEvents.InteractingGenerator += OnInteractingGenerator;
PlayerEvents.InteractingLocker += OnInteractingLocker;
PlayerEvents.UnlockingWarheadButton += OnUnlockingWarhead;
PlayerEvents.PlacedBulletHole += OnBulletHole;
}
private static void StartDoorLockCoroutine(DoorVariant door)
{
door.StartCoroutine(LockDoorCoroutine(door));
}
private static IEnumerator LockDoorCoroutine(DoorVariant door)
{
var doorType = DoorLockConfiguration.GetDoorType(door);
var lockDuration = Singleton.DoorLockConfiguration.LockDurations[doorType];
door.ServerChangeLock(DoorLockReason.SpecialDoorFeature, true);
yield return new WaitForSeconds(lockDuration);
door.ServerChangeLock(DoorLockReason.SpecialDoorFeature, false);
}
public override void Disable()
{
PlayerEvents.InteractingDoor -= OnInteractingDoor;
PlayerEvents.InteractingGenerator -= OnInteractingGenerator;
PlayerEvents.InteractingLocker -= OnInteractingLocker;
PlayerEvents.UnlockingWarheadButton -= OnUnlockingWarhead;
PlayerEvents.PlacedBulletHole -= OnBulletHole;
Logger.Debug("unloading...");
Singleton = null;
}
} }

View File

@ -1,40 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net48</TargetFramework> <TargetFramework>net48</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable> <Nullable>disable</Nullable>
<LangVersion>10</LangVersion> <LangVersion>10</LangVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<Optimize>true</Optimize> <Optimize>true</Optimize>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<DebugType>full</DebugType> <DebugType>full</DebugType>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<Optimize>true</Optimize> <Optimize>true</Optimize>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<DebugType>none</DebugType> <DebugType>none</DebugType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Assembly-CSharp"> <Reference Include="Assembly-CSharp">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Assembly-CSharp.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Assembly-CSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="Mirror"> <Reference Include="Mirror">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll</HintPath>
</Reference> </Reference>
<Reference Include="UnityEngine.CoreModule"> <Reference Include="UnityEngine.CoreModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
</Reference> </Reference>
<Reference Include="UnityEngine.PhysicsModule"> <Reference Include="UnityEngine.PhysicsModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -2,30 +2,29 @@
using LabApi.Features; using LabApi.Features;
using LabApi.Loader.Features.Plugins; using LabApi.Loader.Features.Plugins;
namespace LogEvents namespace LogEvents;
internal class LogPlugin : Plugin
{ {
internal class LogPlugin : Plugin public override string Name { get; } = "LogPlugin";
public override string Description { get; } = "Example Plugin that logs (almost) all events.";
public override string Author { get; } = "Northwood";
public override Version Version { get; } = new(1, 0, 0, 0);
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
public MyCustomEventsHandler Events { get; } = new();
public override void Enable()
{ {
public override string Name { get; } = "LogPlugin"; CustomHandlersManager.RegisterEventsHandler(Events);
}
public override string Description { get; } = "Example Plugin that logs (almost) all events."; public override void Disable()
{
public override string Author { get; } = "Northwood"; CustomHandlersManager.UnregisterEventsHandler(Events);
public override Version Version { get; } = new Version(1, 0, 0, 0);
public override Version RequiredApiVersion { get; } = new Version(LabApiProperties.CompiledVersion);
public MyCustomEventsHandler Events { get; } = new();
public override void Enable()
{
CustomHandlersManager.RegisterEventsHandler(Events);
}
public override void Disable()
{
CustomHandlersManager.UnregisterEventsHandler(Events);
}
} }
} }

View File

@ -723,7 +723,8 @@ internal class MyCustomEventsHandler : CustomEventsHandler
public override void OnPlayerStayingInHazard(PlayersStayingInHazardEventArgs ev) public override void OnPlayerStayingInHazard(PlayersStayingInHazardEventArgs ev)
{ {
Logger.Info($"{nameof(OnPlayerStayingInHazard)} triggered by {string.Join(", ", ev.AffectedPlayers.Select(x => x.UserId))}"); Logger.Info(
$"{nameof(OnPlayerStayingInHazard)} triggered by {string.Join(", ", ev.AffectedPlayers.Select(x => x.UserId))}");
} }
public override void OnPlayerLeavingHazard(PlayerLeavingHazardEventArgs ev) public override void OnPlayerLeavingHazard(PlayerLeavingHazardEventArgs ev)
@ -1397,5 +1398,4 @@ internal class MyCustomEventsHandler : CustomEventsHandler
// } // }
#endregion #endregion
} }

View File

@ -23,21 +23,9 @@
<Reference Include="Assembly-CSharp"> <Reference Include="Assembly-CSharp">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Assembly-CSharp.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Assembly-CSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="Mirror">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.Physics2DModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.Physics2DModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.PhysicsModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -11,7 +11,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2"/> <PackageReference Include="coverlet.collector" Version="6.0.2"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0"/>
<PackageReference Include="NUnit" Version="4.3.2" /> <PackageReference Include="NUnit" Version="4.3.2"/>
<PackageReference Include="NUnit.Analyzers" Version="4.4.0"/> <PackageReference Include="NUnit.Analyzers" Version="4.4.0"/>
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/> <PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
</ItemGroup> </ItemGroup>
@ -21,7 +21,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\RangeBan\RangeBan.csproj" /> <ProjectReference Include="..\RangeBan\RangeBan.csproj"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,5 +1,4 @@
using System.Runtime.Serialization; using LabApi.Events.Arguments.PlayerEvents;
using LabApi.Events.Arguments.PlayerEvents;
using LabApi.Events.Handlers; using LabApi.Events.Handlers;
using LabApi.Features; using LabApi.Features;
using LabApi.Features.Console; using LabApi.Features.Console;
@ -7,8 +6,13 @@ using LabApi.Loader.Features.Plugins;
namespace RangeBan; namespace RangeBan;
public class RangeBan: Plugin<RangeBanConfig> public class RangeBan : Plugin<RangeBanConfig>
{ {
public override string Name => "RangeBan";
public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0);
public override string Description => "Ban IP Ranges with ease";
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
public override void Enable() public override void Enable()
{ {
@ -26,16 +30,11 @@ public class RangeBan: Plugin<RangeBanConfig>
{ {
Logger.Debug($"Ranges: {string.Join(" ; ", Config!.IpRanges)}"); Logger.Debug($"Ranges: {string.Join(" ; ", Config!.IpRanges)}");
if (!Config!.IpRanges.Any(configIpRange => IsInRange(configIpRange, ev.IpAddress))) return; if (!Config!.IpRanges.Any(configIpRange => IsInRange(configIpRange, ev.IpAddress))) return;
ev.RejectCustom("Your IP belongs to a banned player, please contact the server administrator for more information."); ev.RejectCustom(
"Your IP belongs to a banned player, please contact the server administrator for more information.");
Logger.Warn($"Player with IP {ev.IpAddress} got kicked. UserId: {ev.UserId}"); Logger.Warn($"Player with IP {ev.IpAddress} got kicked. UserId: {ev.UserId}");
} }
public override string Name => "RangeBan";
public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0);
public override string Description => "Ban IP Ranges with ease";
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
public static bool IsInRange(string range, string ip) public static bool IsInRange(string range, string ip)
{ {
@ -46,29 +45,24 @@ public class RangeBan: Plugin<RangeBanConfig>
if (!range.Contains("/")) if (!range.Contains("/"))
{ {
//We only handle direct IPs and CIDR //We only handle direct IPs and CIDR
if (range.Split('.').Length != 4) if (range.Split('.').Length != 4) return false;
{
return false;
}
return ip == range; return ip == range;
}; }
;
var parts = range.Split('/'); var parts = range.Split('/');
if (parts.Length != 2 || !int.TryParse(parts[1], out var cidrBits)) if (parts.Length != 2 || !int.TryParse(parts[1], out var cidrBits))
return false; return false;
if (cidrBits > 32) if (cidrBits > 32) return false;
{
return false;
}
var networkAddress = IPToUInt32(parts[0]); var networkAddress = IPToUInt32(parts[0]);
var mask = uint.MaxValue << (32 - cidrBits); var mask = uint.MaxValue << (32 - cidrBits);
var ipAddress = IPToUInt32(ip); var ipAddress = IPToUInt32(ip);
return (ipAddress & mask) == (networkAddress & mask); return (ipAddress & mask) == (networkAddress & mask);
} }
private static uint IPToUInt32(string ipAddress) private static uint IPToUInt32(string ipAddress)
@ -84,11 +78,12 @@ public class RangeBan: Plugin<RangeBanConfig>
throw new ArgumentException("Invalid IP address segment"); throw new ArgumentException("Invalid IP address segment");
result = (result << 8) | part; result = (result << 8) | part;
} }
return result; return result;
} }
} }
public class RangeBanConfig public class RangeBanConfig
{ {
public string[] IpRanges { get; set; } = {}; public string[] IpRanges { get; set; } = { };
} }

View File

@ -20,18 +20,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Assembly-CSharp"> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Assembly-CSharp.dll</HintPath>
</Reference>
<Reference Include="Mirror">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -12,144 +12,138 @@ using PlayerRoles.PlayableScps.Scp096;
using PlayerRoles.PlayableScps.Scp3114; using PlayerRoles.PlayableScps.Scp3114;
using Timer = System.Timers.Timer; using Timer = System.Timers.Timer;
namespace SCPTeamHint namespace SCPTeamHint;
public class Plugin : LabApi.Loader.Features.Plugins.Plugin
{ {
public class Plugin : LabApi.Loader.Features.Plugins.Plugin private readonly object _hintsLock = new();
private readonly Dictionary<Player, Hint> _spectatorHints = new();
private Timer _timer;
public override string Name => "SCPTeamHint";
public override string Author => "HoherGeist, Code002Lover";
public override Version Version { get; } = new(1, 0, 0);
public override string Description => "Displays information about your SCP Teammates";
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
public override void Enable()
{ {
public override string Name => "SCPTeamHint"; Logger.Debug("Apple juice");
public override string Author => "HoherGeist, Code002Lover"; PlayerEvents.Joined += OnJoin;
public override Version Version { get; } = new(1, 0, 0); PlayerEvents.Left += OnLeft;
public override string Description => "Displays information about your SCP Teammates";
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
private Timer _timer; _timer = new Timer(1000);
private readonly object _hintsLock = new(); _timer.Elapsed += (_, _) => UpdateHints();
private readonly Dictionary<Player,Hint> _spectatorHints = new(); _timer.Start();
}
public override void Enable() public override void Disable()
{
PlayerEvents.Joined -= OnJoin;
PlayerEvents.Left -= OnLeft;
_timer?.Stop();
_timer?.Dispose();
_timer = null;
}
private void UpdateHints()
{
var hintTexts = new List<string>();
lock (_hintsLock)
{ {
Logger.Debug("Apple juice"); foreach (var player in Player.ReadyList.Where(x => !x.IsHost && !x.IsDummy && x.IsSCP))
PlayerEvents.Joined += OnJoin;
PlayerEvents.Left += OnLeft;
_timer = new Timer(1000);
_timer.Elapsed += (_,_) => UpdateHints();
_timer.Start();
}
public override void Disable()
{
PlayerEvents.Joined -= OnJoin;
PlayerEvents.Left -= OnLeft;
_timer?.Stop();
_timer?.Dispose();
_timer = null;
}
private void UpdateHints()
{
var hintTexts = new List<string>();
lock (_hintsLock)
{ {
var text =
$" <size=25><color=red>{player.RoleBase.RoleName}</color> | <color=#6761cd>{player.HumeShield}</color> | <color=#da0101>{player.Health}</color> | <color=grey>{player.Zone}</color></size> ";
switch (player.RoleBase)
foreach (var player in Player.ReadyList.Where(x => !x.IsHost && !x.IsDummy && x.IsSCP))
{ {
var text = case Scp096Role scp:
$" <size=25><color=red>{player.RoleBase.RoleName}</color> | <color=#6761cd>{player.HumeShield}</color> | <color=#da0101>{player.Health}</color> | <color=grey>{player.Zone}</color></size> "; text += "\n";
switch (player.RoleBase) scp.SubroutineModule.TryGetSubroutine(out Scp096TargetsTracker tracker);
if (!tracker) break;
text += $"Targets: {tracker.Targets.Count}";
break;
case Scp3114Role scp3114:
{ {
case Scp096Role scp: text += "\n";
text += "\n";
scp.SubroutineModule.TryGetSubroutine(out Scp096TargetsTracker tracker); var stolenRole = scp3114.CurIdentity.StolenRole;
if(!tracker) break; text += $" {stolenRole}";
break;
text += $"Targets: {tracker.Targets.Count}";
break;
case Scp3114Role scp3114:
{
text += "\n";
var stolenRole = scp3114.CurIdentity.StolenRole;
text += $" {stolenRole}";
break;
}
case Scp079Role scp079:
text =
$" <size=25><color=red>{player.RoleBase.RoleName}</color> | <color=grey>{scp079.CurrentCamera.Room.Zone}</color></size> ";
text += "\n";
scp079.SubroutineModule.TryGetSubroutine(out Scp079AuxManager auxManager);
scp079.SubroutineModule.TryGetSubroutine(out Scp079TierManager tierManager);
if(!auxManager || !tierManager) break;
text +=
$" <color=grey>AUX: {auxManager.CurrentAuxFloored} / {auxManager.MaxAux} | Level {tierManager.AccessTierLevel}</color>";
break;
} }
case Scp079Role scp079:
text =
$" <size=25><color=red>{player.RoleBase.RoleName}</color> | <color=grey>{scp079.CurrentCamera.Room.Zone}</color></size> ";
text += "\n";
hintTexts.Add(text); scp079.SubroutineModule.TryGetSubroutine(out Scp079AuxManager auxManager);
scp079.SubroutineModule.TryGetSubroutine(out Scp079TierManager tierManager);
if (!auxManager || !tierManager) break;
text +=
$" <color=grey>AUX: {auxManager.CurrentAuxFloored} / {auxManager.MaxAux} | Level {tierManager.AccessTierLevel}</color>";
break;
} }
var hintText = string.Join("\n", hintTexts); hintTexts.Add(text);
foreach (var player in Player.ReadyList.Where(x => !x.IsHost && !x.IsDummy))
{
Logger.Debug($"Updating hint for {player.DisplayName}");
UpdateHint(player, hintText);
}
}
}
private void UpdateHint(Player player, string hintText)
{
if (!_spectatorHints.TryGetValue(player, out var hint))
{
Logger.Debug($"No hint found for player {player.DisplayName}");
return;
} }
Logger.Debug($"Player {player.Nickname} is on team {player.RoleBase.Team} | hide: {player.RoleBase.Team != Team.SCPs}"); var hintText = string.Join("\n", hintTexts);
hint.Hide = player.RoleBase.Team != Team.SCPs;
if (!hint.Hide) foreach (var player in Player.ReadyList.Where(x => !x.IsHost && !x.IsDummy))
{ {
hint.Text = hintText; Logger.Debug($"Updating hint for {player.DisplayName}");
} UpdateHint(player, hintText);
}
private void OnJoin(PlayerJoinedEventArgs ev)
{
if(ev.Player.IsDummy || ev.Player.IsHost) return;
var hint = new Hint
{
Text = "", Alignment = HintAlignment.Left, YCoordinate = 100, Hide = true
};
var playerDisplay = PlayerDisplay.Get(ev.Player);
playerDisplay.AddHint(hint);
lock (_hintsLock)
{
_spectatorHints[ev.Player] = hint;
}
}
private void OnLeft(PlayerLeftEventArgs ev)
{
if(ev.Player.IsDummy || ev.Player.IsHost) return;
lock (_hintsLock)
{
_spectatorHints.Remove(ev.Player);
} }
} }
} }
private void UpdateHint(Player player, string hintText)
{
if (!_spectatorHints.TryGetValue(player, out var hint))
{
Logger.Debug($"No hint found for player {player.DisplayName}");
return;
}
Logger.Debug(
$"Player {player.Nickname} is on team {player.RoleBase.Team} | hide: {player.RoleBase.Team != Team.SCPs}");
hint.Hide = player.RoleBase.Team != Team.SCPs;
if (!hint.Hide) hint.Text = hintText;
}
private void OnJoin(PlayerJoinedEventArgs ev)
{
if (ev.Player.IsDummy || ev.Player.IsHost) return;
var hint = new Hint
{
Text = "", Alignment = HintAlignment.Left, YCoordinate = 100, Hide = true
};
var playerDisplay = PlayerDisplay.Get(ev.Player);
playerDisplay.AddHint(hint);
lock (_hintsLock)
{
_spectatorHints[ev.Player] = hint;
}
}
private void OnLeft(PlayerLeftEventArgs ev)
{
if (ev.Player.IsDummy || ev.Player.IsHost) return;
lock (_hintsLock)
{
_spectatorHints.Remove(ev.Player);
}
}
} }

View File

@ -20,31 +20,26 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="0Harmony"> <Reference Include="Assembly-CSharp">
<HintPath>..\dependencies\0Harmony.dll</HintPath> <HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="Assembly-CSharp"> <Reference Include="HintServiceMeow">
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath> <HintPath>..\dependencies\HintServiceMeow-LabAPI.dll</HintPath>
</Reference> </Reference>
<Reference Include="HintServiceMeow"> <Reference Include="Mirror">
<HintPath>..\dependencies\HintServiceMeow-LabAPI.dll</HintPath> <HintPath>..\dependencies\Mirror.dll</HintPath>
</Reference> </Reference>
<Reference Include="Mirror"> <Reference Include="Pooling">
<HintPath>..\dependencies\Mirror.dll</HintPath> <HintPath>..\dependencies\Pooling.dll</HintPath>
</Reference> </Reference>
<Reference Include="Pooling"> <Reference Include="UnityEngine.CoreModule">
<HintPath>..\dependencies\Pooling.dll</HintPath> <HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath>
</Reference> </Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,5 +1,4 @@
using LabApi.Events.Handlers; using LabApi.Features;
using LabApi.Features;
using LabApi.Loader.Features.Plugins; using LabApi.Loader.Features.Plugins;
namespace ScpSwap; namespace ScpSwap;
@ -18,6 +17,5 @@ public class ScpSwap : Plugin
public override void Disable() public override void Disable()
{ {
} }
} }

View File

@ -24,7 +24,7 @@
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath> <HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="CommandSystem.Core"> <Reference Include="CommandSystem.Core">
<HintPath>..\dependencies\CommandSystem.Core.dll</HintPath> <HintPath>..\dependencies\CommandSystem.Core.dll</HintPath>
</Reference> </Reference>
<Reference Include="Mirror"> <Reference Include="Mirror">
<HintPath>..\dependencies\Mirror.dll</HintPath> <HintPath>..\dependencies\Mirror.dll</HintPath>
@ -38,6 +38,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -40,7 +40,7 @@ public class SwapCommand : ICommand
"096", "096",
"106", "106",
"173", "173",
"939", "939"
]; ];
var arg = arguments.First(); var arg = arguments.First();
@ -51,7 +51,8 @@ public class SwapCommand : ICommand
return false; return false;
} }
if (Player.List.Where(x=>x.IsSCP).Select(x=>x.RoleBase).Any(playerRole => playerRole.RoleName == "SCP-" + arg)) if (Player.List.Where(x => x.IsSCP).Select(x => x.RoleBase)
.Any(playerRole => playerRole.RoleName == "SCP-" + arg))
{ {
response = "Already exists"; response = "Already exists";
return false; return false;
@ -77,5 +78,5 @@ public class SwapCommand : ICommand
public string Command { get; } = "scpswap"; public string Command { get; } = "scpswap";
public string[] Aliases { get; } = ["ss"]; public string[] Aliases { get; } = ["ss"];
public string Description { get; } = "Swaps SCPs"; public string Description { get; } = "Swaps SCPs";
} }

View File

@ -8,46 +8,45 @@ using UnityEngine;
using Logger = LabApi.Features.Console.Logger; using Logger = LabApi.Features.Console.Logger;
using TimedGrenadePickup = InventorySystem.Items.ThrowableProjectiles.TimedGrenadePickup; using TimedGrenadePickup = InventorySystem.Items.ThrowableProjectiles.TimedGrenadePickup;
namespace SensitiveGrenades namespace SensitiveGrenades;
public class SensitiveGrenades : Plugin
{ {
public class SensitiveGrenades : Plugin public override string Name => "SensitiveGrenades";
public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0);
public override string Description => "Shoot grenades to blow them up!";
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
public override void Enable()
{ {
public override string Name => "SensitiveGrenades"; Logger.Debug("starting...");
public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0);
public override string Description => "Shoot grenades to blow them up!";
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
public override void Enable() PlayerEvents.PlacedBulletHole += ShotWeapon;
}
private static void ShotWeapon(PlayerPlacedBulletHoleEventArgs ev)
{
var direction = (ev.HitPosition - ev.RaycastStart).normalized;
var distance = Vector3.Distance(ev.RaycastStart, ev.HitPosition);
var hits = Physics.RaycastAll(ev.RaycastStart, direction, distance);
foreach (var hit in hits)
{ {
Logger.Debug("starting..."); var itemPickup = hit.collider.GetComponent<ItemPickupBase>();
PlayerEvents.PlacedBulletHole += ShotWeapon; var grenade = itemPickup as TimedGrenadePickup;
}
private static void ShotWeapon(PlayerPlacedBulletHoleEventArgs ev) if (!grenade) continue;
{
var direction = (ev.HitPosition - ev.RaycastStart).normalized;
var distance = Vector3.Distance(ev.RaycastStart, ev.HitPosition);
var hits = Physics.RaycastAll(ev.RaycastStart, direction, distance); itemPickup.DestroySelf();
foreach (var hit in hits) TimedGrenadeProjectile.SpawnActive(itemPickup.Position, itemPickup.Info.ItemId, ev.Player);
{ break;
var itemPickup = hit.collider.GetComponent<ItemPickupBase>();
var grenade = itemPickup as TimedGrenadePickup;
if (!grenade) continue;
itemPickup.DestroySelf();
TimedGrenadeProjectile.SpawnActive(itemPickup.Position, itemPickup.Info.ItemId, ev.Player);
break;
}
}
public override void Disable()
{
Logger.Debug("unloading...");
} }
} }
public override void Disable()
{
Logger.Debug("unloading...");
}
} }

View File

@ -30,15 +30,12 @@
<Reference Include="UnityEngine.CoreModule"> <Reference Include="UnityEngine.CoreModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
</Reference> </Reference>
<Reference Include="UnityEngine.Physics2DModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.Physics2DModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.PhysicsModule"> <Reference Include="UnityEngine.PhysicsModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -6,7 +6,7 @@ using MEC;
namespace ServerHints; namespace ServerHints;
public class ServerHints: Plugin public class ServerHints : Plugin
{ {
public override string Name => "ServerHints"; public override string Name => "ServerHints";
public override string Author => "Code002Lover"; public override string Author => "Code002Lover";
@ -36,16 +36,14 @@ public class ServerHints: Plugin
{ {
ServerEvents.RoundStarted -= OnRoundStarted; ServerEvents.RoundStarted -= OnRoundStarted;
} }
private void OnRoundStarted() private void OnRoundStarted()
{ {
var random = new Random(); var random = new Random();
var hint = Hints[random.Next(Hints.Length)]; var hint = Hints[random.Next(Hints.Length)];
Timing.CallDelayed(1, () => Timing.CallDelayed(1, () =>
{ {
foreach (var player in Player.ReadyList) foreach (var player in Player.ReadyList) player.SendBroadcast($"<color=grey>{hint}</color>", 3);
{
player.SendBroadcast($"<color=grey>{hint}</color>", 3);
}
}); });
} }
} }

View File

@ -26,21 +26,15 @@
<Reference Include="Assembly-CSharp-firstpass"> <Reference Include="Assembly-CSharp-firstpass">
<HintPath>..\dependencies\Assembly-CSharp-firstpass.dll</HintPath> <HintPath>..\dependencies\Assembly-CSharp-firstpass.dll</HintPath>
</Reference> </Reference>
<Reference Include="Mirror">
<HintPath>..\dependencies\Mirror.dll</HintPath>
</Reference>
<Reference Include="NorthwoodLib"> <Reference Include="NorthwoodLib">
<HintPath>..\dependencies\NorthwoodLib.dll</HintPath> <HintPath>..\dependencies\NorthwoodLib.dll</HintPath>
</Reference> </Reference>
<Reference Include="Pooling">
<HintPath>..\dependencies\Pooling.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule"> <Reference Include="UnityEngine.CoreModule">
<HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath> <HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,5 +1,4 @@
using HintServiceMeow.Core.Enum; using HintServiceMeow.Core.Enum;
using HintServiceMeow.Core.Models.HintContent;
using HintServiceMeow.Core.Models.Hints; using HintServiceMeow.Core.Models.Hints;
using HintServiceMeow.Core.Utilities; using HintServiceMeow.Core.Utilities;
using LabApi.Events.Arguments.PlayerEvents; using LabApi.Events.Arguments.PlayerEvents;
@ -9,195 +8,187 @@ using LabApi.Features.Console;
using LabApi.Features.Wrappers; using LabApi.Features.Wrappers;
using LabApi.Loader.Features.Plugins; using LabApi.Loader.Features.Plugins;
using PlayerRoles; using PlayerRoles;
using PlayerRoles.Spectating;
using Timer = System.Timers.Timer; using Timer = System.Timers.Timer;
namespace VisibleSpectators namespace VisibleSpectators;
public class Plugin : Plugin<SpectatorConfig>
{ {
public class Plugin : Plugin<SpectatorConfig> private static Plugin _singleton;
private static readonly Dictionary<string, string> GetColorMap = new()
{ {
public override string Name => "VisibleSpectators"; { "DEFAULT", "FFFFFF" },
public override string Author => "Code002Lover"; { "PUMPKIN", "EE7600" },
public override Version Version { get; } = new(1, 0, 0); { "ARMY_GREEN", "4B5320" },
public override string Description => "See your spectators"; { "MINT", "98FB98" },
public override Version RequiredApiVersion { get; } = new (LabApiProperties.CompiledVersion); { "NICKEL", "727472" },
{ "CARMINE", "960018" },
{ "EMERALD", "50C878" },
{ "GREEN", "228B22" },
{ "LIME", "BFFF00" },
{ "POLICE_BLUE", "002DB3" },
{ "ORANGE", "FF9966" },
{ "SILVER_BLUE", "666699" },
{ "BLUE_GREEN", "4DFFB8" },
{ "MAGENTA", "FF0090" },
{ "YELLOW", "FAFF86" },
{ "TOMATO", "FF6448" },
{ "DEEP_PINK", "FF1493" },
{ "AQUA", "00FFFF" },
{ "CYAN", "00B7EB" },
{ "CRIMSON", "DC143C" },
{ "LIGHT_GREEN", "32CD32" },
{ "SILVER", "A0A0A0" },
{ "BROWN", "944710" },
{ "RED", "C50000" },
{ "PINK", "FF96DE" },
{ "LIGHT_RED", "FD8272" },
{ "PURPLE", "8137CE" },
{ "BLUE", "005EBC" },
{ "TEAL", "008080" },
{ "GOLD", "EFC01A" }
};
public int YCoordinate { get; set; } = 100; private readonly Dictionary<Player, Hint> _spectatorHints = new();
private Timer _timer;
public override string Name => "VisibleSpectators";
public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0);
public override string Description => "See your spectators";
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
private static Plugin _singleton; public int YCoordinate { get; set; } = 100;
private Timer _timer;
private readonly Dictionary<Player,Hint> _spectatorHints = new();
public override void Enable() public override void Enable()
{
Logger.Debug("starting...");
_singleton = this;
PlayerEvents.ChangedSpectator += OnSpectate;
PlayerEvents.Joined += OnJoin;
_timer = new Timer(1000);
_timer.Elapsed += (_, _) => UpdateSpectators();
_timer.Start();
}
public override void Disable()
{
Logger.Debug("unloading...");
_timer.Stop();
_timer.Dispose();
_timer = null;
PlayerEvents.Joined -= OnJoin;
PlayerEvents.ChangedSpectator -= OnSpectate;
_singleton = null;
}
private void UpdateSpectators()
{
foreach (var player in GetPlayers()) UpdateSpectators(player);
}
private void AddPlayerHint(Player player)
{
var hint = new Hint
{ {
Logger.Debug("starting..."); Text = $"{Config!.HeaderMessage}\n{Config!.NoSpectatorsMessage}",
_singleton = this; Alignment = HintAlignment.Right,
YCoordinate = YCoordinate,
PlayerEvents.ChangedSpectator += OnSpectate; Hide = true
PlayerEvents.Joined += OnJoin;
_timer = new Timer(1000);
_timer.Elapsed += (_, _) => UpdateSpectators();
_timer.Start();
}
public override void Disable()
{
Logger.Debug("unloading...");
_timer.Stop();
_timer.Dispose();
_timer = null;
PlayerEvents.Joined -= OnJoin;
PlayerEvents.ChangedSpectator -= OnSpectate;
_singleton = null;
}
private void UpdateSpectators()
{
foreach (var player in GetPlayers())
{
UpdateSpectators(player);
}
}
private void AddPlayerHint(Player player)
{
var hint = new Hint
{
Text = $"{Config!.HeaderMessage}\n{Config!.NoSpectatorsMessage}",
Alignment = HintAlignment.Right,
YCoordinate = YCoordinate,
Hide = true
};
var playerDisplay = PlayerDisplay.Get(player);
playerDisplay.AddHint(hint);
_spectatorHints[player] = hint;
}
private static readonly Dictionary<string, string> GetColorMap = new()
{
{ "DEFAULT", "FFFFFF" },
{ "PUMPKIN", "EE7600" },
{ "ARMY_GREEN", "4B5320" },
{ "MINT", "98FB98" },
{ "NICKEL", "727472" },
{ "CARMINE", "960018" },
{ "EMERALD", "50C878" },
{ "GREEN", "228B22" },
{ "LIME", "BFFF00" },
{ "POLICE_BLUE", "002DB3" },
{ "ORANGE", "FF9966" },
{ "SILVER_BLUE", "666699" },
{ "BLUE_GREEN", "4DFFB8" },
{ "MAGENTA", "FF0090" },
{ "YELLOW", "FAFF86" },
{ "TOMATO", "FF6448" },
{ "DEEP_PINK", "FF1493" },
{ "AQUA", "00FFFF" },
{ "CYAN", "00B7EB" },
{ "CRIMSON", "DC143C" },
{ "LIGHT_GREEN", "32CD32" },
{ "SILVER", "A0A0A0" },
{ "BROWN", "944710" },
{ "RED", "C50000" },
{ "PINK", "FF96DE" },
{ "LIGHT_RED", "FD8272" },
{ "PURPLE", "8137CE" },
{ "BLUE", "005EBC" },
{ "TEAL", "008080" },
{ "GOLD", "EFC01A" }
}; };
private static string PlayerToDisplay(Player player) var playerDisplay = PlayerDisplay.Get(player);
playerDisplay.AddHint(hint);
_spectatorHints[player] = hint;
}
private static string PlayerToDisplay(Player player)
{
if (player == null) return "";
if (!player.IsReady) return "";
// Default color if GroupColor is null or not found in the map
const string defaultColor = "FFFFFF";
try
{ {
if (player == null) return ""; var groupColor = player.GroupColor;
if (!player.IsReady) return ""; if (string.IsNullOrEmpty(groupColor))
// Default color if GroupColor is null or not found in the map
const string defaultColor = "FFFFFF";
try
{
var groupColor = player.GroupColor;
if (string.IsNullOrEmpty(groupColor))
return $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
return GetColorMap.TryGetValue(groupColor.ToUpper(), out var color) ? $"<color=#{color}FF>{player.DisplayName}</color>" : $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
}
catch
{
return $"<color=#{defaultColor}FF>{player.DisplayName}</color>"; return $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
}
return GetColorMap.TryGetValue(groupColor.ToUpper(), out var color)
? $"<color=#{color}FF>{player.DisplayName}</color>"
: $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
} }
catch
private static bool IsNotOverwatch(Player player)
{ {
return player != null && player.Role != RoleTypeId.Overwatch; return $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
}
private void UpdateSpectators(Player player)
{
// Safety check - if player doesn't have a hint, create one
if (!_spectatorHints.ContainsKey(player))
{
AddPlayerHint(player);
}
var spectators = Config!.NoSpectatorsMessage;
try
{
spectators = string.Join("\n",player.CurrentSpectators.Where(IsNotOverwatch).Select(PlayerToDisplay));
if (player.Role == RoleTypeId.Spectator)
spectators = player.CurrentlySpectating == null
? Config!.NoSpectatorsMessage
: string.Join("\n",
player.CurrentlySpectating?.CurrentSpectators.Where(IsNotOverwatch)
.Select(PlayerToDisplay) ?? Array.Empty<string>());
} catch (Exception e)
{
Logger.Error(e);
}
if (spectators.Length < 2)
{
spectators = Config!.NoSpectatorsMessage;
}
_spectatorHints[player].Text = $"{Config!.HeaderMessage}\n{spectators}";
_spectatorHints[player].Hide = player.Role is RoleTypeId.Destroyed or RoleTypeId.None;
_spectatorHints[player].YCoordinate = YCoordinate + player.CurrentSpectators.Count * 10;
}
private static Player[] GetPlayers()
{
return Player.ReadyList.Where(IsNotOverwatch).ToArray();
}
private static void OnSpectate(PlayerChangedSpectatorEventArgs ev)
{
_singleton.UpdateSpectators(ev.OldTarget);
_singleton.UpdateSpectators(ev.NewTarget);
_singleton.UpdateSpectators(ev.Player);
}
private void OnJoin(PlayerJoinedEventArgs ev)
{
AddPlayerHint(ev.Player);
} }
} }
public class SpectatorConfig private static bool IsNotOverwatch(Player player)
{ {
public string HeaderMessage { get; set; } = "Spectators:"; return player != null && player.Role != RoleTypeId.Overwatch;
public string NoSpectatorsMessage { get; set; } = "No spectators"; }
private void UpdateSpectators(Player player)
{
// Safety check - if player doesn't have a hint, create one
if (!_spectatorHints.ContainsKey(player)) AddPlayerHint(player);
var spectators = Config!.NoSpectatorsMessage;
try
{
spectators = string.Join("\n", player.CurrentSpectators.Where(IsNotOverwatch).Select(PlayerToDisplay));
if (player.Role == RoleTypeId.Spectator)
spectators = player.CurrentlySpectating == null
? Config!.NoSpectatorsMessage
: string.Join("\n",
player.CurrentlySpectating?.CurrentSpectators.Where(IsNotOverwatch)
.Select(PlayerToDisplay) ?? Array.Empty<string>());
}
catch (Exception e)
{
Logger.Error(e);
}
if (spectators.Length < 2) spectators = Config!.NoSpectatorsMessage;
_spectatorHints[player].Text = $"{Config!.HeaderMessage}\n{spectators}";
_spectatorHints[player].Hide = player.Role is RoleTypeId.Destroyed or RoleTypeId.None;
_spectatorHints[player].YCoordinate = YCoordinate + player.CurrentSpectators.Count * 10;
}
private static Player[] GetPlayers()
{
return Player.ReadyList.Where(IsNotOverwatch).ToArray();
}
private static void OnSpectate(PlayerChangedSpectatorEventArgs ev)
{
_singleton.UpdateSpectators(ev.OldTarget);
_singleton.UpdateSpectators(ev.NewTarget);
_singleton.UpdateSpectators(ev.Player);
}
private void OnJoin(PlayerJoinedEventArgs ev)
{
AddPlayerHint(ev.Player);
} }
} }
public class SpectatorConfig
{
public string HeaderMessage { get; set; } = "Spectators:";
public string NoSpectatorsMessage { get; set; } = "No spectators";
}

View File

@ -20,14 +20,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="0Harmony">
<HintPath>..\dependencies\0Harmony.dll</HintPath>
</Reference>
<Reference Include="Assembly-CSharp"> <Reference Include="Assembly-CSharp">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Assembly-CSharp.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Assembly-CSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="HintServiceMeow"> <Reference Include="HintServiceMeow">
<HintPath>..\dependencies\HintServiceMeow-LabAPI.dll</HintPath> <HintPath>..\dependencies\HintServiceMeow-LabAPI.dll</HintPath>
</Reference> </Reference>
<Reference Include="Mirror"> <Reference Include="Mirror">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll</HintPath> <HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll</HintPath>
@ -38,6 +35,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -21,12 +21,11 @@ public class WarheadEvents : Plugin
public override void Disable() public override void Disable()
{ {
} }
private static void OnExplode(WarheadDetonatedEventArgs ev) private static void OnExplode(WarheadDetonatedEventArgs ev)
{ {
var door = Door.Get(DoorVariant.AllDoors.First(x=>x.DoorName.ToUpper() == "ESCAPE_FINAL")); var door = Door.Get(DoorVariant.AllDoors.First(x => x.DoorName.ToUpper() == "ESCAPE_FINAL"));
door.IsOpened = true; door.IsOpened = true;
} }

View File

@ -23,21 +23,15 @@
<Reference Include="Assembly-CSharp"> <Reference Include="Assembly-CSharp">
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath> <HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="Assembly-CSharp-firstpass">
<HintPath>..\dependencies\Assembly-CSharp-firstpass.dll</HintPath>
</Reference>
<Reference Include="Mirror"> <Reference Include="Mirror">
<HintPath>..\dependencies\Mirror.dll</HintPath> <HintPath>..\dependencies\Mirror.dll</HintPath>
</Reference> </Reference>
<Reference Include="Pooling">
<HintPath>..\dependencies\Pooling.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule"> <Reference Include="UnityEngine.CoreModule">
<HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath> <HintPath>..\dependencies\UnityEngine.CoreModule.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" /> <PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
</ItemGroup> </ItemGroup>
</Project> </Project>