Compare commits
2 Commits
9bf05f87aa
...
96596e9c08
Author | SHA1 | Date | |
---|---|---|---|
96596e9c08 | |||
17c654d889 |
134
AfkSwap/AfkSwap.cs
Normal file
134
AfkSwap/AfkSwap.cs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
using LabApi.Events.Arguments.PlayerEvents;
|
||||||
|
using LabApi.Events.Handlers;
|
||||||
|
using LabApi.Features;
|
||||||
|
using LabApi.Features.Wrappers;
|
||||||
|
using LabApi.Loader.Features.Plugins;
|
||||||
|
using MEC;
|
||||||
|
using PlayerRoles;
|
||||||
|
using UnityEngine;
|
||||||
|
using Logger = LabApi.Features.Console.Logger;
|
||||||
|
using Random = UnityEngine.Random;
|
||||||
|
using Version = System.Version;
|
||||||
|
|
||||||
|
namespace AfkSwap;
|
||||||
|
|
||||||
|
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 Author => "Code002Lover";
|
||||||
|
public override Version Version { get; } = new(1, 0, 0);
|
||||||
|
public override string Description => "Swaps AFK players with spectators after one minute.";
|
||||||
|
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
|
||||||
|
|
||||||
|
public override void Enable()
|
||||||
|
{
|
||||||
|
PlayerEvents.Spawned += OnPlayerSpawned;
|
||||||
|
|
||||||
|
Timing.RunCoroutine(CheckAfkPlayers());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Disable()
|
||||||
|
{
|
||||||
|
PlayerEvents.Spawned -= OnPlayerSpawned;
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
_playerSpawnTimes.Clear();
|
||||||
|
_playerPositions.Clear();
|
||||||
|
_afkPlayers.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayerSpawned(PlayerSpawnedEventArgs ev)
|
||||||
|
{
|
||||||
|
var player = ev.Player;
|
||||||
|
Timing.CallDelayed(1, () =>
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
_playerSpawnTimes[player] = DateTime.Now;
|
||||||
|
_playerPositions[player] = player.Position;
|
||||||
|
_afkPlayers[player] = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Debug($"Player {player.DisplayName} spawned");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator<float> CheckAfkPlayers()
|
||||||
|
{
|
||||||
|
Logger.Debug("Starting Afk Checking");
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
_playerSpawnTimes.Remove(playerTime.Key);
|
||||||
|
_playerPositions.Remove(playerTime.Key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_playerPositions[playerTime.Key].Equals(playerTime.Key.Position))
|
||||||
|
{
|
||||||
|
_playerSpawnTimes.Remove(playerTime.Key);
|
||||||
|
_playerPositions.Remove(playerTime.Key);
|
||||||
|
continue; // Player has moved, don't swap
|
||||||
|
}
|
||||||
|
|
||||||
|
_afkPlayers[playerTime.Key] = DateTime.Now;
|
||||||
|
SwapWithSpectator(playerTime.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return Timing.WaitForSeconds(1);
|
||||||
|
}
|
||||||
|
// ReSharper disable once IteratorNeverReturns
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SwapWithSpectator(Player afkPlayer)
|
||||||
|
{
|
||||||
|
var spectators = Player.ReadyList
|
||||||
|
.Where(p => p.Role == RoleTypeId.Spectator && (DateTime.Now - _afkPlayers[p]).TotalSeconds > 10).ToList();
|
||||||
|
if (!spectators.Any())
|
||||||
|
{
|
||||||
|
Logger.Warn("No spectators to swap to");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var randomSpectator = spectators[Random.Range(0, spectators.Count)];
|
||||||
|
Logger.Debug($"Swapping {afkPlayer.DisplayName} with {randomSpectator.DisplayName}");
|
||||||
|
|
||||||
|
// Store the AFK player's position and role
|
||||||
|
var afkPosition = afkPlayer.Position;
|
||||||
|
var afkRole = afkPlayer.Role;
|
||||||
|
|
||||||
|
// Give the spectator the AFK player's role and position
|
||||||
|
randomSpectator.Role = afkRole;
|
||||||
|
randomSpectator.Position = afkPosition;
|
||||||
|
|
||||||
|
// Make the AFK player a spectator
|
||||||
|
afkPlayer.Role = RoleTypeId.Spectator;
|
||||||
|
|
||||||
|
// Remove the AFK player from tracking
|
||||||
|
_playerSpawnTimes.Remove(afkPlayer);
|
||||||
|
_playerPositions.Remove(afkPlayer);
|
||||||
|
_playerSpawnTimes[randomSpectator] = DateTime.Now;
|
||||||
|
_playerPositions[randomSpectator] = randomSpectator.Position;
|
||||||
|
|
||||||
|
// Broadcast the swap
|
||||||
|
afkPlayer.SendBroadcast($"You were swapped with {randomSpectator.DisplayName} due to inactivity.", 10);
|
||||||
|
randomSpectator.SendBroadcast($"You were swapped with {afkPlayer.DisplayName} due to them being AFK.", 5);
|
||||||
|
}
|
||||||
|
}
|
37
AfkSwap/AfkSwap.csproj
Normal file
37
AfkSwap/AfkSwap.csproj
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net48</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<LangVersion>10</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Assembly-CSharp-firstpass">
|
||||||
|
<HintPath>..\dependencies\Assembly-CSharp-firstpass.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>
|
||||||
|
</Project>
|
25
CandySetting/CandySetting.csproj
Normal file
25
CandySetting/CandySetting.csproj
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net48</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<LangVersion>10</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Northwood.LabAPI" Version="1.0.2"/>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
32
CandySetting/Class1.cs
Normal file
32
CandySetting/Class1.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using LabApi.Events.Arguments.PlayerEvents;
|
||||||
|
using LabApi.Events.Handlers;
|
||||||
|
using LabApi.Features;
|
||||||
|
using LabApi.Loader.Features.Plugins;
|
||||||
|
|
||||||
|
namespace CandySetting;
|
||||||
|
|
||||||
|
public class CandySetting : Plugin
|
||||||
|
{
|
||||||
|
public override string Name => "CandySetting";
|
||||||
|
public override string Author => "HoherGeist, Code002Lover";
|
||||||
|
public override Version Version { get; } = new(1, 0, 0);
|
||||||
|
public override string Description => "Edits # of Candy you can take";
|
||||||
|
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
|
||||||
|
|
||||||
|
public int MaxUses { get; set; } = 6;
|
||||||
|
|
||||||
|
public override void Enable()
|
||||||
|
{
|
||||||
|
PlayerEvents.InteractingScp330 += TakingCandy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Disable()
|
||||||
|
{
|
||||||
|
PlayerEvents.InteractingScp330 -= TakingCandy;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TakingCandy(PlayerInteractingScp330EventArgs ev)
|
||||||
|
{
|
||||||
|
ev.AllowPunishment = ev.Uses > MaxUses;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
@ -16,16 +13,16 @@ public class CuffedFrenemies : Plugin
|
|||||||
{
|
{
|
||||||
public override string Name => "CuffedFrenemies";
|
public override string Name => "CuffedFrenemies";
|
||||||
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()
|
||||||
{
|
{
|
||||||
Logger.Debug("Loading");
|
Logger.Debug("Loading");
|
||||||
PlayerEvents.Cuffed += OnCuff;
|
PlayerEvents.Cuffed += OnCuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Disable()
|
public override void Disable()
|
||||||
{
|
{
|
||||||
PlayerEvents.Cuffed -= OnCuff;
|
PlayerEvents.Cuffed -= OnCuff;
|
||||||
@ -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,30 +38,23 @@ 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}");
|
||||||
var newItems = new List<Item>();
|
var newItems = new List<Item>();
|
||||||
ev.Target.Items.CopyTo(newItems);
|
ev.Target.Items.CopyTo(newItems);
|
||||||
newItems.Reverse();
|
newItems.Reverse();
|
||||||
|
|
||||||
var newPos = ev.Target.Position;
|
var newPos = ev.Target.Position;
|
||||||
|
|
||||||
ev.Target.Inventory.UserInventory.Items.Clear();
|
ev.Target.Inventory.UserInventory.Items.Clear();
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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>
|
||||||
|
235
CustomClasses/CustomClasses.cs
Normal file
235
CustomClasses/CustomClasses.cs
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
using Interactables.Interobjects.DoorUtils;
|
||||||
|
using InventorySystem.Items;
|
||||||
|
using LabApi.Events.Arguments.PlayerEvents;
|
||||||
|
using LabApi.Events.Arguments.ServerEvents;
|
||||||
|
using LabApi.Events.Handlers;
|
||||||
|
using LabApi.Features;
|
||||||
|
using LabApi.Features.Wrappers;
|
||||||
|
using LabApi.Loader.Features.Plugins;
|
||||||
|
using MapGeneration;
|
||||||
|
using MEC;
|
||||||
|
using PlayerRoles;
|
||||||
|
using UnityEngine;
|
||||||
|
using Logger = LabApi.Features.Console.Logger;
|
||||||
|
using Random = System.Random;
|
||||||
|
using Vector3 = UnityEngine.Vector3;
|
||||||
|
|
||||||
|
namespace CustomClasses;
|
||||||
|
|
||||||
|
public class CustomClasses : Plugin
|
||||||
|
{
|
||||||
|
private readonly CustomClassManager _classManager = new();
|
||||||
|
public override string Name => "CustomClasses";
|
||||||
|
public override string Author => "Code002Lover";
|
||||||
|
public override Version Version { get; } = new(1, 0, 0);
|
||||||
|
public override string Description => "Adds custom classes to the game";
|
||||||
|
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
|
||||||
|
|
||||||
|
public JanitorConfig JanitorConfig { get; set; } = new();
|
||||||
|
public ResearchSubjectConfig ResearchSubjectConfig { get; set; } = new();
|
||||||
|
public HeadGuardConfig HeadGuardConfig { get; set; } = new();
|
||||||
|
|
||||||
|
public override void Enable()
|
||||||
|
{
|
||||||
|
PlayerEvents.Spawned += OnPlayerSpawned;
|
||||||
|
ServerEvents.RoundEnded += OnRoundEnded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Disable()
|
||||||
|
{
|
||||||
|
PlayerEvents.Spawned -= OnPlayerSpawned;
|
||||||
|
ServerEvents.RoundEnded -= OnRoundEnded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRoundEnded(RoundEndedEventArgs ev)
|
||||||
|
{
|
||||||
|
_classManager.ResetSpawnStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayerSpawned(PlayerSpawnedEventArgs ev)
|
||||||
|
{
|
||||||
|
if (_classManager.TryHandleSpawn(ev.Player, JanitorConfig, typeof(JanitorConfig))) return;
|
||||||
|
if (_classManager.TryHandleSpawn(ev.Player, ResearchSubjectConfig, typeof(ResearchSubjectConfig))) return;
|
||||||
|
if (_classManager.TryHandleSpawn(ev.Player, HeadGuardConfig, typeof(HeadGuardConfig))) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CustomClassManager
|
||||||
|
{
|
||||||
|
private readonly Dictionary<Type, ICustomClassHandler> _handlers = new();
|
||||||
|
private readonly object _lock = new();
|
||||||
|
private readonly Random _random = new();
|
||||||
|
private readonly Dictionary<Type, SpawnState> _spawnStates = new();
|
||||||
|
|
||||||
|
public CustomClassManager()
|
||||||
|
{
|
||||||
|
// Register handlers
|
||||||
|
RegisterHandler<JanitorConfig>(new JanitorHandler(this));
|
||||||
|
RegisterHandler<ResearchSubjectConfig>(new ResearchSubjectHandler(this));
|
||||||
|
RegisterHandler<HeadGuardConfig>(new HeadGuardHandler(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TeleportPlayerToAround(Player player, Vector3 position)
|
||||||
|
{
|
||||||
|
player.Position = position + new Vector3(0, 1, 0) + new Vector3((float)(_random.NextDouble() * 2), 0,
|
||||||
|
(float)(_random.NextDouble() * 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterHandler<T>(ICustomClassHandler handler) where T : CustomClassConfig
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
_spawnStates[typeof(T)] = new SpawnState();
|
||||||
|
}
|
||||||
|
|
||||||
|
_handlers[typeof(T)] = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetSpawnStates()
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
foreach (var key in _spawnStates.Keys.ToList()) _spawnStates[key] = new SpawnState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryHandleSpawn(Player player, CustomClassConfig config, Type configType)
|
||||||
|
{
|
||||||
|
if (player.Role != config.RequiredRole) return false;
|
||||||
|
if (Player.ReadyList.Count() <= config.MinPlayers) return false;
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
var state = _spawnStates[configType];
|
||||||
|
if (state.Spawns >= config.MaxSpawns)
|
||||||
|
{
|
||||||
|
Logger.Debug($"Max spawns reached {configType} - {player.Nickname}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_random.NextDouble() > config.ChancePerPlayer)
|
||||||
|
{
|
||||||
|
Logger.Debug($"Chance not met {configType} - {player.Nickname}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Spawns++;
|
||||||
|
|
||||||
|
Logger.Debug($"Player spawning {configType} - {player.Nickname} - {state.Spawns} / {config.MaxSpawns}");
|
||||||
|
|
||||||
|
if (_handlers.TryGetValue(configType, out var handler)) return handler.HandleSpawn(player, config, _random);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ICustomClassHandler
|
||||||
|
{
|
||||||
|
bool HandleSpawn(Player player, CustomClassConfig config, Random random);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class JanitorHandler(CustomClassManager manager) : ICustomClassHandler
|
||||||
|
{
|
||||||
|
public bool HandleSpawn(Player player, CustomClassConfig config, Random random)
|
||||||
|
{
|
||||||
|
var scp914 = Map.Rooms.First(r => r.Name == RoomName.Lcz914);
|
||||||
|
Timing.CallDelayed(0.5f, () =>
|
||||||
|
{
|
||||||
|
manager.TeleportPlayerToAround(player, scp914.Position);
|
||||||
|
|
||||||
|
foreach (var spawnItem in config.Items)
|
||||||
|
{
|
||||||
|
player.AddItem(spawnItem, ItemAddReason.StartingItem);
|
||||||
|
Logger.Debug($"Gave player {player.Nickname} spawn item {spawnItem}");
|
||||||
|
}
|
||||||
|
|
||||||
|
player.SendBroadcast("You're a <color=#A0A0A0>Janitor</color>!", 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ResearchSubjectHandler(CustomClassManager manager) : ICustomClassHandler
|
||||||
|
{
|
||||||
|
public bool HandleSpawn(Player player, CustomClassConfig config, Random random)
|
||||||
|
{
|
||||||
|
var scientist = Player.ReadyList.First(p => p.Role == RoleTypeId.Scientist);
|
||||||
|
Timing.CallDelayed(0.5f, () =>
|
||||||
|
{
|
||||||
|
manager.TeleportPlayerToAround(player, scientist.Position);
|
||||||
|
|
||||||
|
foreach (var spawnItem in config.Items)
|
||||||
|
{
|
||||||
|
player.AddItem(spawnItem, ItemAddReason.StartingItem);
|
||||||
|
Logger.Debug($"Gave player {player.Nickname} spawn item {spawnItem}");
|
||||||
|
}
|
||||||
|
|
||||||
|
player.SendBroadcast("You're a <color=#944710>Research Subject</color>!", 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HeadGuardHandler(CustomClassManager manager) : ICustomClassHandler
|
||||||
|
{
|
||||||
|
public bool HandleSpawn(Player player, CustomClassConfig config, Random random)
|
||||||
|
{
|
||||||
|
Timing.CallDelayed(0.5f, () =>
|
||||||
|
{
|
||||||
|
player.RemoveItem(ItemType.KeycardGuard);
|
||||||
|
|
||||||
|
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.RemoveItem(ItemType.ArmorLight);
|
||||||
|
player.AddItem(ItemType.ArmorCombat, ItemAddReason.StartingItem);
|
||||||
|
|
||||||
|
player.RemoveItem(ItemType.GunFSP9);
|
||||||
|
|
||||||
|
var pickup = Pickup.Create(ItemType.GunCrossvec, Vector3.one);
|
||||||
|
|
||||||
|
if (pickup != null) player.AddItem(pickup);
|
||||||
|
|
||||||
|
player.SetAmmo(ItemType.Ammo9x19, 120);
|
||||||
|
|
||||||
|
player.SendBroadcast("You're a <color=#00B7EB>Head Guard</color>!", 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal record SpawnState
|
||||||
|
{
|
||||||
|
public int Spawns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class CustomClassConfig
|
||||||
|
{
|
||||||
|
public virtual int MinPlayers { get; set; } = 4;
|
||||||
|
public virtual double ChancePerPlayer { get; set; } = 0.7;
|
||||||
|
public virtual int MaxSpawns { get; set; } = 1;
|
||||||
|
public virtual ItemType[] Items { get; set; } = [];
|
||||||
|
public virtual RoleTypeId RequiredRole { get; set; } = RoleTypeId.ClassD;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ResearchSubjectConfig : CustomClassConfig;
|
||||||
|
|
||||||
|
public class JanitorConfig : CustomClassConfig
|
||||||
|
{
|
||||||
|
public override int MinPlayers { get; set; } = 5;
|
||||||
|
public override double ChancePerPlayer { get; set; } = 0.3;
|
||||||
|
public override int MaxSpawns { get; set; } = 2;
|
||||||
|
public override ItemType[] Items { get; set; } = [ItemType.KeycardJanitor];
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HeadGuardConfig : CustomClassConfig
|
||||||
|
{
|
||||||
|
public override int MinPlayers { get; set; } = 9;
|
||||||
|
public override RoleTypeId RequiredRole { get; set; } = RoleTypeId.FacilityGuard;
|
||||||
|
}
|
43
CustomClasses/CustomClasses.csproj
Normal file
43
CustomClasses/CustomClasses.csproj
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net48</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Assembly-CSharp-firstpass">
|
||||||
|
<HintPath>..\dependencies\Assembly-CSharp-firstpass.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Mirror">
|
||||||
|
<HintPath>..\dependencies\Mirror.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="NorthwoodLib">
|
||||||
|
<HintPath>..\dependencies\NorthwoodLib.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>
|
||||||
|
</Project>
|
79
CustomItemSpawn/CustomItemSpawn.cs
Normal file
79
CustomItemSpawn/CustomItemSpawn.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
using LabApi.Events.Handlers;
|
||||||
|
using LabApi.Features;
|
||||||
|
using LabApi.Features.Wrappers;
|
||||||
|
using LabApi.Loader.Features.Plugins;
|
||||||
|
using MEC;
|
||||||
|
using Logger = LabApi.Features.Console.Logger;
|
||||||
|
using Random = System.Random;
|
||||||
|
using Vector3 = UnityEngine.Vector3;
|
||||||
|
|
||||||
|
namespace CustomItemSpawn;
|
||||||
|
|
||||||
|
public class CustomItemSpawn : Plugin<ItemConfig>
|
||||||
|
{
|
||||||
|
private static CustomItemSpawn _singleton;
|
||||||
|
public override string Name => "CustomItemSpawn";
|
||||||
|
public override string Author => "Code002Lover";
|
||||||
|
public override Version Version { get; } = new(1, 0, 0);
|
||||||
|
public override string Description => "Spawns items in a custom location.";
|
||||||
|
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
|
||||||
|
|
||||||
|
public override void Enable()
|
||||||
|
{
|
||||||
|
_singleton = this;
|
||||||
|
ServerEvents.RoundStarted += OnRoundStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Disable()
|
||||||
|
{
|
||||||
|
ServerEvents.RoundStarted -= OnRoundStart;
|
||||||
|
_singleton = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnRoundStart()
|
||||||
|
{
|
||||||
|
Timing.CallDelayed(10, SpawnItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SpawnItems()
|
||||||
|
{
|
||||||
|
Random rng = new();
|
||||||
|
|
||||||
|
foreach (var pickup in from configPair in _singleton.Config!.Items
|
||||||
|
let itemType = configPair.Key
|
||||||
|
let config = configPair.Value
|
||||||
|
where rng.NextDouble() * 100f <= config.Chance
|
||||||
|
select Pickup.Create(itemType, config.Position + new Vector3(0, 1, 0)))
|
||||||
|
{
|
||||||
|
if (pickup == null)
|
||||||
|
{
|
||||||
|
Logger.Error("Could not create pickup.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pickup.Spawn();
|
||||||
|
Logger.Debug($"Spawned Pickup: {pickup.Base} @ {pickup.Position}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ItemConfig
|
||||||
|
{
|
||||||
|
public Dictionary<ItemType, SpecificConfig> Items { get; set; } = new()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
ItemType.GunAK,
|
||||||
|
new SpecificConfig
|
||||||
|
{
|
||||||
|
Position = new Vector3(0, 0, 0),
|
||||||
|
Chance = 100f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SpecificConfig
|
||||||
|
{
|
||||||
|
public Vector3 Position { get; set; }
|
||||||
|
public float Chance { get; set; } = 100f;
|
||||||
|
}
|
40
CustomItemSpawn/CustomItemSpawn.csproj
Normal file
40
CustomItemSpawn/CustomItemSpawn.csproj
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net48</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<LangVersion>10</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Assembly-CSharp-firstpass">
|
||||||
|
<HintPath>..\dependencies\Assembly-CSharp-firstpass.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Mirror">
|
||||||
|
<HintPath>..\dependencies\Mirror.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>
|
||||||
|
</Project>
|
@ -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;
|
|
||||||
public GamblingCoinMessages ConfigMessages;
|
|
||||||
public GamblingCoinChancesConfig ConfigChances;
|
|
||||||
|
|
||||||
public override void LoadConfigs()
|
ConfigGameplay = this.LoadConfig<GamblingCoinGameplayConfig>("gameplay.yml");
|
||||||
{
|
ConfigMessages = this.LoadConfig<GamblingCoinMessages>("messages.yml");
|
||||||
base.LoadConfigs();
|
ConfigChances = this.LoadConfig<GamblingCoinChancesConfig>("chances.yml");
|
||||||
|
}
|
||||||
|
|
||||||
ConfigGameplay = this.LoadConfig< GamblingCoinGameplayConfig > ("gameplay.yml");
|
public override void Enable()
|
||||||
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;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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>
|
||||||
|
@ -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 UncommonItemChance { get; set; } = 400;
|
||||||
|
public int RareItemChance { get; set; } = 250;
|
||||||
|
public int EpicItemChance { get; set; } = 100;
|
||||||
|
public int LegendaryItemChance { get; set; } = 30;
|
||||||
|
public int RandomTeleportChance { get; set; } = 200;
|
||||||
|
public int StealItemChance { get; set; } = 100;
|
||||||
|
public int ExplosionChance { get; set; } = 40;
|
||||||
|
public int AntiMicroChance { get; set; } = 10;
|
||||||
|
public int GrenadeChance { get; set; } = 50;
|
||||||
|
public int PocketDimensionChance { get; set; } = 30;
|
||||||
|
public int SwitchInventoryChance { get; set; } = 150;
|
||||||
|
public int PositiveEffectChance { get; set; } = 300;
|
||||||
|
public int NegativeEffectChance { get; set; } = 350;
|
||||||
|
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 string ItemSpawnMessage { get; set; } = "*plop*";
|
||||||
|
public string UncommonItemSpawnMessage { get; set; } = "*bump*";
|
||||||
|
public string RareItemSpawnMessage { get; set; } = "*badunk*";
|
||||||
|
public string EpicItemSpawnMessage { get; set; } = "*katong*";
|
||||||
|
public string LegendaryItemSpawnMessage { get; set; } = "*sounds of monetary loss*";
|
||||||
|
public string RandomTeleportMessage { get; set; } = "Where did you go?";
|
||||||
|
public string StealItemMessage { get; set; } = "Be careful, the coin is slippery!";
|
||||||
|
public string ExplosionMessage { get; set; } = "How did you even die '-'";
|
||||||
|
public string AntiMicroMessage { get; set; } = "Where did all the micros go...";
|
||||||
|
public string GrenadeMessage { get; set; } = "Watch out!";
|
||||||
|
public string PocketDimensionMessage { get; set; } = "I hear he likes to see people suffer...";
|
||||||
|
public string PositiveEffectMessage { get; set; } = "You feel slightly better";
|
||||||
|
public string AdvancedPositiveEffectMessage { get; set; } = "You feel better";
|
||||||
|
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 ushort BroadcastDuration { get; set; } = 3;
|
||||||
|
public float TeleportHeightOffset { get; set; } = 1f;
|
||||||
|
public int MaxMicrosToRemove { get; set; } = 8;
|
||||||
|
|
||||||
|
public ItemPoolConfig Items { get; set; } = new();
|
||||||
|
public EffectConfig Effects { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ItemPoolConfig
|
||||||
|
{
|
||||||
|
public ItemType[] CommonItems { get; set; } =
|
||||||
{
|
{
|
||||||
public int NukeChance { get; set; } = 10;
|
ItemType.KeycardJanitor,
|
||||||
public int SpawnWaveChance { get; set; } = 150;
|
ItemType.KeycardScientist,
|
||||||
public int CommonItemChance { get; set; } = 600;
|
ItemType.Medkit,
|
||||||
public int UncommonItemChance { get; set; } = 400;
|
ItemType.Painkillers,
|
||||||
public int RareItemChance { get; set; } = 250;
|
ItemType.Radio,
|
||||||
public int EpicItemChance { get; set; } = 100;
|
ItemType.Flashlight
|
||||||
public int LegendaryItemChance { get; set; } = 30;
|
};
|
||||||
public int RandomTeleportChance { get; set; } = 200;
|
|
||||||
public int StealItemChance { get; set; } = 100;
|
public ItemType[] UncommonItems { get; set; } =
|
||||||
public int ExplosionChance { get; set; } = 40;
|
|
||||||
public int AntiMicroChance { get; set; } = 10;
|
|
||||||
public int GrenadeChance { get; set; } = 50;
|
|
||||||
public int PocketDimensionChance { get; set; } = 30;
|
|
||||||
public int SwitchInventoryChance { get; set; } = 150;
|
|
||||||
public int PositiveEffectChance { get; set; } = 300;
|
|
||||||
public int NegativeEffectChance { get; set; } = 350;
|
|
||||||
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...?";
|
ItemType.KeycardZoneManager,
|
||||||
public string ItemSpawnMessage { get; set; } = "*plop*";
|
ItemType.KeycardGuard,
|
||||||
public string UncommonItemSpawnMessage { get; set; } = "*bump*";
|
ItemType.KeycardResearchCoordinator,
|
||||||
public string RareItemSpawnMessage { get; set; } = "*badunk*";
|
ItemType.Adrenaline,
|
||||||
public string EpicItemSpawnMessage { get; set; } = "*katong*";
|
ItemType.ArmorLight,
|
||||||
public string LegendaryItemSpawnMessage { get; set; } = "*sounds of monetary loss*";
|
ItemType.GrenadeFlash
|
||||||
public string RandomTeleportMessage { get; set; } = "Where did you go?";
|
};
|
||||||
public string StealItemMessage { get; set; } = "Be careful, the coin is slippery!";
|
|
||||||
public string ExplosionMessage { get; set; } = "How did you even die '-'";
|
|
||||||
public string AntiMicroMessage { get; set; } = "Where did all the micros go...";
|
|
||||||
public string GrenadeMessage { get; set; } = "Watch out!";
|
|
||||||
public string PocketDimensionMessage { get; set; } = "I hear he likes to see people suffer...";
|
|
||||||
public string PositiveEffectMessage { get; set; } = "You feel slightly better";
|
|
||||||
public string AdvancedPositiveEffectMessage { get; set; } = "You feel better";
|
|
||||||
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 ItemType[] RareItems { get; set; } =
|
||||||
{
|
{
|
||||||
public float WarheadTimeIncrease { get; set; } = 20f;
|
ItemType.KeycardMTFPrivate,
|
||||||
public ushort BroadcastDuration { get; set; } = 3;
|
ItemType.KeycardContainmentEngineer,
|
||||||
public float TeleportHeightOffset { get; set; } = 1f;
|
ItemType.KeycardMTFOperative,
|
||||||
public int MaxMicrosToRemove { get; set; } = 8;
|
ItemType.ArmorCombat,
|
||||||
|
ItemType.ArmorHeavy,
|
||||||
public ItemPoolConfig Items { get; set; } = new();
|
ItemType.SCP330,
|
||||||
public EffectConfig Effects { get; set; } = new();
|
ItemType.Lantern,
|
||||||
}
|
ItemType.GrenadeHE
|
||||||
|
};
|
||||||
public class ItemPoolConfig
|
|
||||||
|
public ItemType[] EpicItems { get; set; } =
|
||||||
{
|
{
|
||||||
public ItemType[] CommonItems { get; set; } = {
|
ItemType.KeycardFacilityManager,
|
||||||
ItemType.KeycardJanitor,
|
ItemType.KeycardChaosInsurgency,
|
||||||
ItemType.KeycardScientist,
|
ItemType.KeycardMTFCaptain,
|
||||||
ItemType.Medkit,
|
ItemType.SCP500
|
||||||
ItemType.Painkillers,
|
};
|
||||||
ItemType.Radio,
|
|
||||||
ItemType.Flashlight
|
|
||||||
};
|
|
||||||
|
|
||||||
public ItemType[] UncommonItems { get; set; } = {
|
public ItemType[] LegendaryItems { get; set; } =
|
||||||
ItemType.KeycardZoneManager,
|
|
||||||
ItemType.KeycardGuard,
|
|
||||||
ItemType.KeycardResearchCoordinator,
|
|
||||||
ItemType.Adrenaline,
|
|
||||||
ItemType.ArmorLight,
|
|
||||||
ItemType.GrenadeFlash
|
|
||||||
};
|
|
||||||
|
|
||||||
public ItemType[] RareItems { get; set; } = {
|
|
||||||
ItemType.KeycardMTFPrivate,
|
|
||||||
ItemType.KeycardContainmentEngineer,
|
|
||||||
ItemType.KeycardMTFOperative,
|
|
||||||
ItemType.ArmorCombat,
|
|
||||||
ItemType.ArmorHeavy,
|
|
||||||
ItemType.SCP330,
|
|
||||||
ItemType.Lantern,
|
|
||||||
ItemType.GrenadeHE
|
|
||||||
};
|
|
||||||
|
|
||||||
public ItemType[] EpicItems { get; set; } = {
|
|
||||||
ItemType.KeycardFacilityManager,
|
|
||||||
ItemType.KeycardChaosInsurgency,
|
|
||||||
ItemType.KeycardMTFCaptain,
|
|
||||||
ItemType.SCP500
|
|
||||||
};
|
|
||||||
|
|
||||||
public ItemType[] LegendaryItems { get; set; } = {
|
|
||||||
ItemType.KeycardO5,
|
|
||||||
ItemType.MicroHID,
|
|
||||||
ItemType.Jailbird,
|
|
||||||
ItemType.GunCom45,
|
|
||||||
ItemType.Coin
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EffectConfig
|
|
||||||
{
|
{
|
||||||
public AdvancedEffectSettings AdvancedPositive { get; set; } = new()
|
ItemType.KeycardO5,
|
||||||
|
ItemType.MicroHID,
|
||||||
|
ItemType.Jailbird,
|
||||||
|
ItemType.GunCom45,
|
||||||
|
ItemType.Coin
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EffectConfig
|
||||||
|
{
|
||||||
|
public AdvancedEffectSettings AdvancedPositive { get; set; } = new()
|
||||||
|
{
|
||||||
|
Effects = new[] { nameof(Invisible), nameof(DamageReduction), nameof(MovementBoost) },
|
||||||
|
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) },
|
|
||||||
Settings = new Dictionary<string, EffectSettings>
|
|
||||||
{
|
|
||||||
{ nameof(Invigorated), new EffectSettings(1, 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),
|
|
||||||
nameof(Concussed), nameof(Deafened), nameof(Disabled) },
|
|
||||||
Settings = new Dictionary<string, EffectSettings>
|
|
||||||
{
|
|
||||||
{ nameof(Asphyxiated), new EffectSettings(1, 10f, 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) },
|
|
||||||
{ nameof(Deafened), new EffectSettings(1, 5f, true) },
|
|
||||||
{ nameof(Disabled), new EffectSettings(1, 5f, true) }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public AdvancedEffectSettings AdvancedNegative { get; set; } = new()
|
|
||||||
{
|
|
||||||
Effects = new[] { nameof(InsufficientLighting), nameof(AmnesiaVision) },
|
|
||||||
Settings = new Dictionary<string, EffectSettings>
|
|
||||||
{
|
|
||||||
{ nameof(InsufficientLighting), new EffectSettings(1, 20f, true) },
|
|
||||||
{ nameof(AmnesiaVision), new EffectSettings(3, 30f, true) },
|
|
||||||
{ nameof(Bleeding), new EffectSettings(3, 40f, true) },
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AdvancedEffectSettings
|
|
||||||
{
|
|
||||||
public string[] Effects { get; set; }
|
|
||||||
public Dictionary<string, EffectSettings> Settings { get; set; }
|
|
||||||
|
|
||||||
public AdvancedEffectSettings(){}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EffectSettings
|
|
||||||
{
|
|
||||||
public byte Intensity { get; set; }
|
|
||||||
public float Duration { get; set; }
|
|
||||||
public bool AddDuration { get; set; }
|
|
||||||
|
|
||||||
public EffectSettings(byte intensity, float duration, bool addDuration)
|
|
||||||
{
|
|
||||||
Intensity = intensity;
|
|
||||||
Duration = duration;
|
|
||||||
AddDuration = addDuration;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
public EffectSettings(){}
|
|
||||||
|
public AdvancedEffectSettings Positive { get; set; } = new()
|
||||||
|
{
|
||||||
|
Effects = new[] { nameof(Invigorated), nameof(RainbowTaste), nameof(Vitality), nameof(BodyshotReduction) },
|
||||||
|
Settings = new Dictionary<string, EffectSettings>
|
||||||
|
{
|
||||||
|
{ nameof(Invigorated), new EffectSettings(1, 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),
|
||||||
|
nameof(Concussed), nameof(Deafened), nameof(Disabled)
|
||||||
|
},
|
||||||
|
Settings = new Dictionary<string, EffectSettings>
|
||||||
|
{
|
||||||
|
{ nameof(Asphyxiated), new EffectSettings(1, 10f, 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) },
|
||||||
|
{ nameof(Deafened), new EffectSettings(1, 5f, true) },
|
||||||
|
{ nameof(Disabled), new EffectSettings(1, 5f, true) }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public AdvancedEffectSettings AdvancedNegative { get; set; } = new()
|
||||||
|
{
|
||||||
|
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) },
|
||||||
|
{ nameof(Burned), new EffectSettings(3, 60f, true) }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AdvancedEffectSettings
|
||||||
|
{
|
||||||
|
public string[] Effects { get; set; }
|
||||||
|
public Dictionary<string, EffectSettings> Settings { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EffectSettings
|
||||||
|
{
|
||||||
|
public EffectSettings(byte intensity, float duration, bool addDuration)
|
||||||
|
{
|
||||||
|
Intensity = intensity;
|
||||||
|
Duration = duration;
|
||||||
|
AddDuration = addDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EffectSettings()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Intensity { get; set; }
|
||||||
|
public float Duration { get; set; }
|
||||||
|
public bool AddDuration { get; set; }
|
||||||
}
|
}
|
@ -1,244 +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);
|
|
||||||
|
|
||||||
var newPos = Map.Rooms.First(roomIdentifier => roomIdentifier.Zone==FacilityZone.Other).Position;
|
|
||||||
|
|
||||||
x.Player.ReferenceHub.playerEffectsController.ChangeState(nameof(Corroding),1, 999, true);
|
|
||||||
|
|
||||||
x.Player.Position = newPos + new UnityEngine.Vector3(0, configGameplay.TeleportHeightOffset, 0);
|
|
||||||
},
|
|
||||||
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 (pickup == null) return;
|
|
||||||
|
|
||||||
pickup.Spawn();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpawnRandomItemAtPlayer(Player player, ItemType[] items)
|
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 itemIndex = Random.Range(0, items.Length);
|
||||||
SpawnItemAtPlayer(player, items[itemIndex]);
|
var item = items[itemIndex];
|
||||||
}
|
|
||||||
|
|
||||||
Player[] GetPlayers()
|
var pickup = Pickup.Create(item, player.Position + new 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 Vector3(0, 1, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pickup.Spawn();
|
||||||
|
}, configChances.LegendaryItemChance)
|
||||||
|
.AddAction(x =>
|
||||||
{
|
{
|
||||||
return Player.Dictionary.Values.ToArray();
|
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 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)];
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
@ -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>
|
||||||
@ -34,31 +16,27 @@ public class WeightedRandomExecutor<TEvent>
|
|||||||
var weightedAction = new WeightedAction(action, weight);
|
var weightedAction = new WeightedAction(action, weight);
|
||||||
_actions.Add(weightedAction);
|
_actions.Add(weightedAction);
|
||||||
_totalWeight += weight;
|
_totalWeight += weight;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
75
GrowingZombies/GrowingZombies.cs
Normal file
75
GrowingZombies/GrowingZombies.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
using CustomPlayerEffects;
|
||||||
|
using InventorySystem.Items.Usables.Scp330;
|
||||||
|
using LabApi.Events.Arguments.PlayerEvents;
|
||||||
|
using LabApi.Events.Arguments.Scp0492Events;
|
||||||
|
using LabApi.Events.Arguments.ServerEvents;
|
||||||
|
using LabApi.Events.Handlers;
|
||||||
|
using LabApi.Features;
|
||||||
|
using LabApi.Features.Wrappers;
|
||||||
|
using LabApi.Loader.Features.Plugins;
|
||||||
|
|
||||||
|
namespace GrowingZombies;
|
||||||
|
|
||||||
|
public class GrowingZombies : Plugin
|
||||||
|
{
|
||||||
|
private readonly Dictionary<Player, int> _zombieCorpseCount = new();
|
||||||
|
public override string Name => "GrowingZombies";
|
||||||
|
public override string Author => "Code002Lover";
|
||||||
|
public override Version Version { get; } = new(1, 0, 0);
|
||||||
|
public override string Description => "Makes zombies grow stronger as they eat more";
|
||||||
|
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
|
||||||
|
|
||||||
|
public override void Enable()
|
||||||
|
{
|
||||||
|
Scp0492Events.ConsumedCorpse += OnZombieEat;
|
||||||
|
ServerEvents.RoundEnded += OnRoundEnd;
|
||||||
|
PlayerEvents.Left += OnPlayerLeave;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Disable()
|
||||||
|
{
|
||||||
|
Scp0492Events.ConsumedCorpse -= OnZombieEat;
|
||||||
|
ServerEvents.RoundEnded -= OnRoundEnd;
|
||||||
|
PlayerEvents.Left -= OnPlayerLeave;
|
||||||
|
_zombieCorpseCount.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRoundEnd(RoundEndedEventArgs ev)
|
||||||
|
{
|
||||||
|
_zombieCorpseCount.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayerLeave(PlayerLeftEventArgs ev)
|
||||||
|
{
|
||||||
|
_zombieCorpseCount.Remove(ev.Player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnZombieEat(Scp0492ConsumedCorpseEventArgs ev)
|
||||||
|
{
|
||||||
|
if (!ev?.Player.ReferenceHub.playerEffectsController)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Increment corpse count for this zombie
|
||||||
|
if (!_zombieCorpseCount.ContainsKey(ev.Player))
|
||||||
|
_zombieCorpseCount[ev.Player] = 0;
|
||||||
|
_zombieCorpseCount[ev.Player]++;
|
||||||
|
|
||||||
|
var corpsesEaten = _zombieCorpseCount[ev.Player];
|
||||||
|
|
||||||
|
ev.Player.MaxHealth += 50;
|
||||||
|
|
||||||
|
var movementBoostIntensity = (byte)Math.Min(1 + corpsesEaten * 0.1f, 3f);
|
||||||
|
ev.Player.ReferenceHub.playerEffectsController.ChangeState<MovementBoost>(movementBoostIntensity, 30);
|
||||||
|
|
||||||
|
// Add damage resistance after eating multiple corpses
|
||||||
|
var damageResistance = (byte)Math.Min(0.5 - corpsesEaten * 0.5f, 2f);
|
||||||
|
if (corpsesEaten >= 3)
|
||||||
|
ev.Player.ReferenceHub.playerEffectsController.ChangeState<DamageReduction>(damageResistance, 20);
|
||||||
|
|
||||||
|
// Add regeneration effect after eating multiple corpses
|
||||||
|
if (corpsesEaten < 5) return;
|
||||||
|
var regenIntensity = Math.Min(1 + corpsesEaten * 0.2f, 3f);
|
||||||
|
|
||||||
|
Scp330Bag.AddSimpleRegeneration(ev.Player.ReferenceHub, regenIntensity, 15f);
|
||||||
|
}
|
||||||
|
}
|
40
GrowingZombies/GrowingZombies.csproj
Normal file
40
GrowingZombies/GrowingZombies.csproj
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net48</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Mirror">
|
||||||
|
<HintPath>..\dependencies\Mirror.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="NorthwoodLib">
|
||||||
|
<HintPath>..\dependencies\NorthwoodLib.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>
|
||||||
|
</Project>
|
@ -12,13 +12,13 @@ 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 },
|
||||||
{ DoorType.Checkpoint, 3f }
|
{ DoorType.Checkpoint, 3f }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static DoorType GetDoorType(DoorVariant door)
|
public static DoorType GetDoorType(DoorVariant door)
|
||||||
{
|
{
|
||||||
Logger.Debug("Door name: " + door.name);
|
Logger.Debug("Door name: " + door.name);
|
||||||
|
@ -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;
|
||||||
DoorLockConfiguration = this.LoadConfig< DoorLockConfiguration > ("door_locks.yml");
|
if (playerItem.Base is not KeycardItem keycardItem) continue;
|
||||||
}
|
|
||||||
|
|
||||||
private void OnInteractingDoor(PlayerInteractingDoorEventArgs ev)
|
if (!ev.Door.Base.CheckPermissions(keycardItem, out _)) continue;
|
||||||
{
|
ev.Door.IsOpened = !ev.Door.IsOpened;
|
||||||
if (ev.CanOpen)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ev.Door.IsLocked)
|
return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var playerItem in ev.Player.Items)
|
|
||||||
{
|
|
||||||
//is keycard?
|
|
||||||
if (playerItem.Type > ItemType.KeycardO5) 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 > ItemType.KeycardO5) 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 > ItemType.KeycardO5) 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 > ItemType.KeycardO5) 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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -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>
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -25,7 +25,7 @@ internal class MyCustomEventsHandler : CustomEventsHandler
|
|||||||
{
|
{
|
||||||
Logger.Info($"{nameof(OnPlayerActivatedGenerator)} triggered by {ev.Player.UserId}");
|
Logger.Info($"{nameof(OnPlayerActivatedGenerator)} triggered by {ev.Player.UserId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnPlayerUnlockingGenerator(PlayerUnlockingGeneratorEventArgs ev)
|
public override void OnPlayerUnlockingGenerator(PlayerUnlockingGeneratorEventArgs ev)
|
||||||
{
|
{
|
||||||
Logger.Info($"{nameof(OnPlayerUnlockingGenerator)} triggered by {ev.Player.UserId}");
|
Logger.Info($"{nameof(OnPlayerUnlockingGenerator)} triggered by {ev.Player.UserId}");
|
||||||
@ -35,7 +35,7 @@ internal class MyCustomEventsHandler : CustomEventsHandler
|
|||||||
{
|
{
|
||||||
Logger.Info($"{nameof(OnPlayerUnlockedGenerator)} triggered by {ev.Player.UserId}");
|
Logger.Info($"{nameof(OnPlayerUnlockedGenerator)} triggered by {ev.Player.UserId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnPlayerUnlockingWarheadButton(PlayerUnlockingWarheadButtonEventArgs ev)
|
public override void OnPlayerUnlockingWarheadButton(PlayerUnlockingWarheadButtonEventArgs ev)
|
||||||
{
|
{
|
||||||
Logger.Info($"{nameof(OnPlayerUnlockingWarheadButton)} triggered by {ev.Player.UserId}");
|
Logger.Info($"{nameof(OnPlayerUnlockingWarheadButton)} triggered by {ev.Player.UserId}");
|
||||||
@ -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)
|
||||||
@ -1310,7 +1311,7 @@ internal class MyCustomEventsHandler : CustomEventsHandler
|
|||||||
{
|
{
|
||||||
Logger.Info($"{nameof(OnServerCassieQueuingScpTermination)} triggered");
|
Logger.Info($"{nameof(OnServerCassieQueuingScpTermination)} triggered");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnServerCassieQueuedScpTermination(CassieQueuedScpTerminationEventArgs ev)
|
public override void OnServerCassieQueuedScpTermination(CassieQueuedScpTerminationEventArgs ev)
|
||||||
{
|
{
|
||||||
Logger.Info($"{nameof(OnServerCassieQueuedScpTermination)} triggered");
|
Logger.Info($"{nameof(OnServerCassieQueuedScpTermination)} triggered");
|
||||||
@ -1375,8 +1376,8 @@ internal class MyCustomEventsHandler : CustomEventsHandler
|
|||||||
{
|
{
|
||||||
Logger.Info($"{nameof(OnWarheadDetonated)} triggered by {ev.Player.UserId}");
|
Logger.Info($"{nameof(OnWarheadDetonated)} triggered by {ev.Player.UserId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#region Excluded Events
|
#region Excluded Events
|
||||||
|
|
||||||
// The following events spam the console and are therefore excluded from this example:
|
// The following events spam the console and are therefore excluded from this example:
|
||||||
@ -1397,5 +1398,4 @@ internal class MyCustomEventsHandler : CustomEventsHandler
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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,9 +6,14 @@ 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()
|
||||||
{
|
{
|
||||||
Logger.Debug("Loading...");
|
Logger.Debug("Loading...");
|
||||||
@ -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; } = { };
|
||||||
}
|
}
|
@ -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>
|
||||||
|
@ -12,53 +12,60 @@ 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;
|
|
||||||
private readonly Dictionary<Player,Hint> _spectatorHints = new();
|
|
||||||
|
|
||||||
public override void Enable()
|
|
||||||
{
|
|
||||||
Logger.Debug("Apple juice");
|
|
||||||
PlayerEvents.Joined += OnJoin;
|
|
||||||
|
|
||||||
_timer = new Timer(1000);
|
_timer = new Timer(1000);
|
||||||
_timer.Elapsed += (_,_) => UpdateHints();
|
_timer.Elapsed += (_, _) => UpdateHints();
|
||||||
_timer.Start();
|
_timer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Disable()
|
public override void Disable()
|
||||||
{
|
{
|
||||||
PlayerEvents.Joined -= OnJoin;
|
PlayerEvents.Joined -= OnJoin;
|
||||||
_timer.Stop();
|
PlayerEvents.Left -= OnLeft;
|
||||||
}
|
_timer?.Stop();
|
||||||
|
_timer?.Dispose();
|
||||||
|
_timer = null;
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateHints()
|
private void UpdateHints()
|
||||||
|
{
|
||||||
|
var hintTexts = new List<string>();
|
||||||
|
|
||||||
|
lock (_hintsLock)
|
||||||
{
|
{
|
||||||
var hintTexts = new List<string>();
|
foreach (var player in Player.ReadyList.Where(x => !x.IsHost && !x.IsDummy && x.IsSCP))
|
||||||
|
|
||||||
foreach (var player in Player.List)
|
|
||||||
{
|
{
|
||||||
if (player.IsDummy || player.IsHost) continue;
|
var text =
|
||||||
if (!player.IsSCP) continue;
|
$" <size=25><color=red>{player.RoleBase.RoleName}</color> | <color=#6761cd>{player.HumeShield}</color> | <color=#da0101>{player.Health}</color> | <color=grey>{player.Zone}</color></size> ";
|
||||||
|
|
||||||
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)
|
switch (player.RoleBase)
|
||||||
{
|
{
|
||||||
case Scp096Role scp:
|
case Scp096Role scp:
|
||||||
text += "\n";
|
text += "\n";
|
||||||
|
|
||||||
scp.SubroutineModule.TryGetSubroutine(out Scp096TargetsTracker tracker);
|
scp.SubroutineModule.TryGetSubroutine(out Scp096TargetsTracker tracker);
|
||||||
|
|
||||||
|
if (!tracker) break;
|
||||||
|
|
||||||
text += $"Targets: {tracker.Targets.Count}";
|
text += $"Targets: {tracker.Targets.Count}";
|
||||||
break;
|
break;
|
||||||
case Scp3114Role scp3114:
|
case Scp3114Role scp3114:
|
||||||
@ -66,7 +73,7 @@ namespace SCPTeamHint
|
|||||||
text += "\n";
|
text += "\n";
|
||||||
|
|
||||||
var stolenRole = scp3114.CurIdentity.StolenRole;
|
var stolenRole = scp3114.CurIdentity.StolenRole;
|
||||||
|
|
||||||
text += $" {stolenRole}";
|
text += $" {stolenRole}";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -77,44 +84,66 @@ namespace SCPTeamHint
|
|||||||
|
|
||||||
scp079.SubroutineModule.TryGetSubroutine(out Scp079AuxManager auxManager);
|
scp079.SubroutineModule.TryGetSubroutine(out Scp079AuxManager auxManager);
|
||||||
scp079.SubroutineModule.TryGetSubroutine(out Scp079TierManager tierManager);
|
scp079.SubroutineModule.TryGetSubroutine(out Scp079TierManager tierManager);
|
||||||
|
|
||||||
text += $" <color=grey>AUX: {auxManager.CurrentAuxFloored} / {auxManager.MaxAux} Level: {tierManager.AccessTierLevel}</color>";
|
if (!auxManager || !tierManager) break;
|
||||||
|
|
||||||
|
text +=
|
||||||
|
$" <color=grey>AUX: {auxManager.CurrentAuxFloored} / {auxManager.MaxAux} | Level {tierManager.AccessTierLevel}</color>";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
hintTexts.Add(text);
|
hintTexts.Add(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var player in Player.List.Where(x=>!x.IsHost))
|
var hintText = string.Join("\n", hintTexts);
|
||||||
|
|
||||||
|
foreach (var player in Player.ReadyList.Where(x => !x.IsHost && !x.IsDummy))
|
||||||
{
|
{
|
||||||
Logger.Debug($"Updating hint for {player.DisplayName}");
|
Logger.Debug($"Updating hint for {player.DisplayName}");
|
||||||
UpdateHint(player, string.Join("\n", hintTexts));
|
UpdateHint(player, hintText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateHint(Player player, string hintText)
|
private void UpdateHint(Player player, string hintText)
|
||||||
|
{
|
||||||
|
if (!_spectatorHints.TryGetValue(player, out var hint))
|
||||||
{
|
{
|
||||||
var hint = _spectatorHints[player];
|
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;
|
|
||||||
|
|
||||||
hint.Text = hintText;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnJoin(PlayerJoinedEventArgs ev)
|
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 hint = new Hint
|
};
|
||||||
{
|
|
||||||
Text = "Apfelsaft", Alignment = HintAlignment.Left, YCoordinate = 100, Hide = true
|
|
||||||
};
|
|
||||||
|
|
||||||
var playerDisplay = PlayerDisplay.Get(ev.Player);
|
var playerDisplay = PlayerDisplay.Get(ev.Player);
|
||||||
playerDisplay.AddHint(hint);
|
playerDisplay.AddHint(hint);
|
||||||
|
|
||||||
|
lock (_hintsLock)
|
||||||
|
{
|
||||||
_spectatorHints[ev.Player] = hint;
|
_spectatorHints[ev.Player] = hint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLeft(PlayerLeftEventArgs ev)
|
||||||
|
{
|
||||||
|
if (ev.Player.IsDummy || ev.Player.IsHost) return;
|
||||||
|
|
||||||
|
lock (_hintsLock)
|
||||||
|
{
|
||||||
|
_spectatorHints.Remove(ev.Player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,32 +19,27 @@
|
|||||||
<DebugType>none</DebugType>
|
<DebugType>none</DebugType>
|
||||||
</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>
|
||||||
|
21
ScpSwap/ScpSwap.cs
Normal file
21
ScpSwap/ScpSwap.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using LabApi.Features;
|
||||||
|
using LabApi.Loader.Features.Plugins;
|
||||||
|
|
||||||
|
namespace ScpSwap;
|
||||||
|
|
||||||
|
public class ScpSwap : Plugin
|
||||||
|
{
|
||||||
|
public override string Name => "ScpSwap";
|
||||||
|
public override string Author => "HoherGeist, Code002Lover";
|
||||||
|
public override Version Version { get; } = new(1, 0, 0);
|
||||||
|
public override string Description => "Swap SCPs.";
|
||||||
|
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
|
||||||
|
|
||||||
|
public override void Enable()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Disable()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
43
ScpSwap/ScpSwap.csproj
Normal file
43
ScpSwap/ScpSwap.csproj
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net48</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="CommandSystem.Core">
|
||||||
|
<HintPath>..\dependencies\CommandSystem.Core.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>
|
||||||
|
</Project>
|
82
ScpSwap/SwapCommand.cs
Normal file
82
ScpSwap/SwapCommand.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using CommandSystem;
|
||||||
|
using LabApi.Features.Wrappers;
|
||||||
|
using PlayerRoles;
|
||||||
|
|
||||||
|
namespace ScpSwap;
|
||||||
|
|
||||||
|
[CommandHandler(typeof(ClientCommandHandler))]
|
||||||
|
public class SwapCommand : ICommand
|
||||||
|
{
|
||||||
|
public bool Execute(ArraySegment<string> arguments, ICommandSender sender, out string response)
|
||||||
|
{
|
||||||
|
if (arguments.Count != 1)
|
||||||
|
{
|
||||||
|
response = "Usage: .scpswap <SCP_NUMBER>";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Player.TryGet(sender, out var player))
|
||||||
|
{
|
||||||
|
response = "You must be a player to use this command!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Round.Duration.TotalSeconds > 120)
|
||||||
|
{
|
||||||
|
response = "You can't swap SCPs during a round!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!player.IsSCP)
|
||||||
|
{
|
||||||
|
response = "You must be an SCP to use this command!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> validScp =
|
||||||
|
[
|
||||||
|
"049",
|
||||||
|
"079",
|
||||||
|
"096",
|
||||||
|
"106",
|
||||||
|
"173",
|
||||||
|
"939"
|
||||||
|
];
|
||||||
|
|
||||||
|
var arg = arguments.First();
|
||||||
|
|
||||||
|
if (!validScp.Contains(arg))
|
||||||
|
{
|
||||||
|
response = "Invalid SCP number.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Player.List.Where(x => x.IsSCP).Select(x => x.RoleBase)
|
||||||
|
.Any(playerRole => playerRole.RoleName == "SCP-" + arg))
|
||||||
|
{
|
||||||
|
response = "Already exists";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var role = arg switch
|
||||||
|
{
|
||||||
|
"049" => RoleTypeId.Scp049,
|
||||||
|
"079" => RoleTypeId.Scp079,
|
||||||
|
"096" => RoleTypeId.Scp096,
|
||||||
|
"106" => RoleTypeId.Scp106,
|
||||||
|
"173" => RoleTypeId.Scp173,
|
||||||
|
"939" => RoleTypeId.Scp939,
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
};
|
||||||
|
|
||||||
|
player.SetRole(role);
|
||||||
|
|
||||||
|
response = "Swapping...";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Command { get; } = "scpswap";
|
||||||
|
public string[] Aliases { get; } = ["ss"];
|
||||||
|
public string Description { get; } = "Swaps SCPs";
|
||||||
|
}
|
@ -18,6 +18,22 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RangeBan.Tests", "RangeBan.
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CuffedFrenemies", "CuffedFrenemies\CuffedFrenemies.csproj", "{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CuffedFrenemies", "CuffedFrenemies\CuffedFrenemies.csproj", "{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CandySetting", "CandySetting\CandySetting.csproj", "{DF3E3243-BD16-4484-BA01-020170FFC871}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScpSwap", "ScpSwap\ScpSwap.csproj", "{B56CA1D5-0927-4542-B967-5E7F5B092E50}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomItemSpawn", "CustomItemSpawn\CustomItemSpawn.csproj", "{887DC217-999F-400B-8918-6737B7694BEE}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AfkSwap", "AfkSwap\AfkSwap.csproj", "{A21DBED5-2B6C-4298-B2CC-DE8F4BAC9766}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WarheadEvents", "WarheadEvents\WarheadEvents.csproj", "{83EB26E9-C1EB-43C9-B010-BBE0F7F05EE9}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomClasses", "CustomClasses\CustomClasses.csproj", "{234E0C4B-5CD2-4FEB-8222-950959E6C082}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerHints", "ServerHints\ServerHints.csproj", "{146AC6C6-AFE6-4EEA-B2F4-6403AD7189D9}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrowingZombies", "GrowingZombies\GrowingZombies.csproj", "{5751F8D6-7A8D-4C2C-B7E9-A8A3DB324329}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -60,5 +76,37 @@ Global
|
|||||||
{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{DF3E3243-BD16-4484-BA01-020170FFC871}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF3E3243-BD16-4484-BA01-020170FFC871}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DF3E3243-BD16-4484-BA01-020170FFC871}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{DF3E3243-BD16-4484-BA01-020170FFC871}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B56CA1D5-0927-4542-B967-5E7F5B092E50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B56CA1D5-0927-4542-B967-5E7F5B092E50}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B56CA1D5-0927-4542-B967-5E7F5B092E50}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B56CA1D5-0927-4542-B967-5E7F5B092E50}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{887DC217-999F-400B-8918-6737B7694BEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{887DC217-999F-400B-8918-6737B7694BEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{887DC217-999F-400B-8918-6737B7694BEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{887DC217-999F-400B-8918-6737B7694BEE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A21DBED5-2B6C-4298-B2CC-DE8F4BAC9766}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A21DBED5-2B6C-4298-B2CC-DE8F4BAC9766}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A21DBED5-2B6C-4298-B2CC-DE8F4BAC9766}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A21DBED5-2B6C-4298-B2CC-DE8F4BAC9766}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{83EB26E9-C1EB-43C9-B010-BBE0F7F05EE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{83EB26E9-C1EB-43C9-B010-BBE0F7F05EE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{83EB26E9-C1EB-43C9-B010-BBE0F7F05EE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{83EB26E9-C1EB-43C9-B010-BBE0F7F05EE9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{234E0C4B-5CD2-4FEB-8222-950959E6C082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{234E0C4B-5CD2-4FEB-8222-950959E6C082}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{234E0C4B-5CD2-4FEB-8222-950959E6C082}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{234E0C4B-5CD2-4FEB-8222-950959E6C082}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{146AC6C6-AFE6-4EEA-B2F4-6403AD7189D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{146AC6C6-AFE6-4EEA-B2F4-6403AD7189D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{146AC6C6-AFE6-4EEA-B2F4-6403AD7189D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{146AC6C6-AFE6-4EEA-B2F4-6403AD7189D9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5751F8D6-7A8D-4C2C-B7E9-A8A3DB324329}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5751F8D6-7A8D-4C2C-B7E9-A8A3DB324329}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5751F8D6-7A8D-4C2C-B7E9-A8A3DB324329}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5751F8D6-7A8D-4C2C-B7E9-A8A3DB324329}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@ -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...");
|
||||||
|
}
|
||||||
}
|
}
|
@ -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>
|
||||||
|
49
ServerHints/ServerHints.cs
Normal file
49
ServerHints/ServerHints.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using LabApi.Events.Handlers;
|
||||||
|
using LabApi.Features;
|
||||||
|
using LabApi.Features.Wrappers;
|
||||||
|
using LabApi.Loader.Features.Plugins;
|
||||||
|
using MEC;
|
||||||
|
|
||||||
|
namespace ServerHints;
|
||||||
|
|
||||||
|
public class ServerHints : Plugin
|
||||||
|
{
|
||||||
|
public override string Name => "ServerHints";
|
||||||
|
public override string Author => "Code002Lover";
|
||||||
|
public override Version Version { get; } = new(1, 0, 0);
|
||||||
|
public override string Description => "Adds hints for custom features.";
|
||||||
|
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
|
||||||
|
|
||||||
|
public string[] Hints { get; set; } =
|
||||||
|
[
|
||||||
|
"Man kann gegnerische Einheiten festnehmen, um sie zu seiner Seite zu bringen.",
|
||||||
|
"Als Hausmeister beginnst du in der Nähe von SCP-914.",
|
||||||
|
"Du kannst als SCP mit .scpswap <SCP nummer> deine Rolle tauschen. (Ö)",
|
||||||
|
"Es gibt auf der Surface versteckte Items.",
|
||||||
|
"Man kann mehr als 2 Candies nehmen.",
|
||||||
|
"Man braucht seine Karte nicht in der Hand zu halten.",
|
||||||
|
"Man kann Türen aufschießen",
|
||||||
|
"Wenn man Granaten anschießt, explodieren sie sofort."
|
||||||
|
];
|
||||||
|
|
||||||
|
public override void Enable()
|
||||||
|
{
|
||||||
|
ServerEvents.RoundStarted += OnRoundStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void Disable()
|
||||||
|
{
|
||||||
|
ServerEvents.RoundStarted -= OnRoundStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRoundStarted()
|
||||||
|
{
|
||||||
|
var random = new Random();
|
||||||
|
var hint = Hints[random.Next(Hints.Length)];
|
||||||
|
Timing.CallDelayed(1, () =>
|
||||||
|
{
|
||||||
|
foreach (var player in Player.ReadyList) player.SendBroadcast($"<color=grey>{hint}</color>", 3);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
40
ServerHints/ServerHints.csproj
Normal file
40
ServerHints/ServerHints.csproj
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net48</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Assembly-CSharp-firstpass">
|
||||||
|
<HintPath>..\dependencies\Assembly-CSharp-firstpass.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="NorthwoodLib">
|
||||||
|
<HintPath>..\dependencies\NorthwoodLib.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>
|
||||||
|
</Project>
|
@ -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,201 +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)
|
|
||||||
{
|
|
||||||
if (player == null) return;
|
|
||||||
|
|
||||||
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);
|
||||||
if (player == null) return "";
|
|
||||||
|
|
||||||
// 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>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsNotOverwatch(Player player)
|
_spectatorHints[player] = hint;
|
||||||
{
|
|
||||||
return player != null && player.Role != RoleTypeId.Overwatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateSpectators(Player player)
|
|
||||||
{
|
|
||||||
if (player == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.Dictionary.Values.Where(x=>!x.IsHost).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 string PlayerToDisplay(Player player)
|
||||||
{
|
{
|
||||||
public string HeaderMessage => "Spectators:";
|
if (player == null) return "";
|
||||||
public string NoSpectatorsMessage => "No spectators";
|
if (!player.IsReady) return "";
|
||||||
|
|
||||||
|
// 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>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsNotOverwatch(Player player)
|
||||||
|
{
|
||||||
|
return player != null && player.Role != RoleTypeId.Overwatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
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";
|
||||||
}
|
}
|
@ -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>
|
||||||
|
32
WarheadEvents/WarheadEvents.cs
Normal file
32
WarheadEvents/WarheadEvents.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using Interactables.Interobjects.DoorUtils;
|
||||||
|
using LabApi.Events.Arguments.WarheadEvents;
|
||||||
|
using LabApi.Features;
|
||||||
|
using LabApi.Features.Wrappers;
|
||||||
|
using LabApi.Loader.Features.Plugins;
|
||||||
|
|
||||||
|
namespace WarheadEvents;
|
||||||
|
|
||||||
|
public class WarheadEvents : Plugin
|
||||||
|
{
|
||||||
|
public override string Name => "WarheadEvents";
|
||||||
|
public override string Author => "Code002Lover";
|
||||||
|
public override Version Version { get; } = new(1, 0, 0);
|
||||||
|
public override string Description => "Misc. stuff for after the Warhead explosion.";
|
||||||
|
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
|
||||||
|
|
||||||
|
public override void Enable()
|
||||||
|
{
|
||||||
|
LabApi.Events.Handlers.WarheadEvents.Detonated += OnExplode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Disable()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnExplode(WarheadDetonatedEventArgs ev)
|
||||||
|
{
|
||||||
|
var door = Door.Get(DoorVariant.AllDoors.First(x => x.DoorName.ToUpper() == "ESCAPE_FINAL"));
|
||||||
|
|
||||||
|
door.IsOpened = true;
|
||||||
|
}
|
||||||
|
}
|
37
WarheadEvents/WarheadEvents.csproj
Normal file
37
WarheadEvents/WarheadEvents.csproj
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net48</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<LangVersion>10</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\dependencies\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Mirror">
|
||||||
|
<HintPath>..\dependencies\Mirror.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>
|
||||||
|
</Project>
|
Loading…
x
Reference in New Issue
Block a user