diff --git a/AfkSwap/AfkSwap.cs b/AfkSwap/AfkSwap.cs index bf605e7..6653c82 100644 --- a/AfkSwap/AfkSwap.cs +++ b/AfkSwap/AfkSwap.cs @@ -27,8 +27,26 @@ public class AfkSwap : Plugin public override string Description => "Swaps AFK players with spectators after one minute."; public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + PlayerEvents.Spawned += OnPlayerSpawned; Timing.RunCoroutine(CheckAfkPlayers()); diff --git a/CandySetting/Class1.cs b/CandySetting/CandySetting.cs similarity index 51% rename from CandySetting/Class1.cs rename to CandySetting/CandySetting.cs index d5c3c1b..95b7dcd 100644 --- a/CandySetting/Class1.cs +++ b/CandySetting/CandySetting.cs @@ -1,6 +1,7 @@ using LabApi.Events.Arguments.PlayerEvents; using LabApi.Events.Handlers; using LabApi.Features; +using LabApi.Features.Console; using LabApi.Loader.Features.Plugins; namespace CandySetting; @@ -15,8 +16,26 @@ public class CandySetting : Plugin public int MaxUses { get; set; } = 6; + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + PlayerEvents.InteractingScp330 += TakingCandy; } diff --git a/CuffedFrenemies/CuffedFrenemies.cs b/CuffedFrenemies/CuffedFrenemies.cs index ad5c1ca..c1c25b7 100644 --- a/CuffedFrenemies/CuffedFrenemies.cs +++ b/CuffedFrenemies/CuffedFrenemies.cs @@ -1,3 +1,4 @@ +using CustomClasses; using LabApi.Events.Arguments.PlayerEvents; using LabApi.Events.Handlers; using LabApi.Features; @@ -17,9 +18,26 @@ public class CuffedFrenemies : Plugin public override string Description => "Cuff your enemies"; public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { - Logger.Debug("Loading"); + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + PlayerEvents.Cuffed += OnCuff; } @@ -34,27 +52,26 @@ public class CuffedFrenemies : Plugin if (ev.Target.Team == ev.Player.Team) { - Logger.Debug("Same team, not changing role"); return; } if (ev.Target.Team is Team.SCPs or Team.Dead) return; - var newRole = ev.Target.Team == Team.ChaosInsurgency ? RoleTypeId.NtfPrivate : RoleTypeId.ChaosConscript; + if (SerpentsHandManager.IsSerpentsHand(ev.Player)) + { + + SerpentsHandManager.PreSpawn(ev.Target); + + return; + } + + if (ev.Target.Role == RoleTypeId.Tutorial) + { + return; + } + + var newRole = ev.Player.Team is Team.ChaosInsurgency or Team.ClassD ? RoleTypeId.ChaosConscript : RoleTypeId.NtfPrivate; Logger.Debug($"Setting role to {newRole}"); - var newItems = new List(); - ev.Target.Items.CopyTo(newItems); - newItems.Reverse(); - - var newPos = ev.Target.Position; - - ev.Target.Inventory.UserInventory.Items.Clear(); - - ev.Target.SetRole(newRole); - ev.Target.ClearItems(); - - foreach (var newItem in newItems) ev.Target.Inventory.UserInventory.Items.Add(newItem.Serial, newItem.Base); - - ev.Target.Position = newPos; + ev.Target.SetRole(newRole, RoleChangeReason.ItemUsage, RoleSpawnFlags.None); } } diff --git a/CuffedFrenemies/CuffedFrenemies.csproj b/CuffedFrenemies/CuffedFrenemies.csproj index 23e061e..f303a7e 100644 --- a/CuffedFrenemies/CuffedFrenemies.csproj +++ b/CuffedFrenemies/CuffedFrenemies.csproj @@ -34,4 +34,8 @@ + + + + diff --git a/CustomClasses/CustomClasses.cs b/CustomClasses/CustomClasses.cs index 9713a94..82958a1 100644 --- a/CustomClasses/CustomClasses.cs +++ b/CustomClasses/CustomClasses.cs @@ -1,8 +1,11 @@ using System.Diagnostics.CodeAnalysis; using CustomPlayerEffects; +using HintServiceMeow.Core.Models.Hints; using Interactables.Interobjects.DoorUtils; +using InventorySystem; using InventorySystem.Items; using InventorySystem.Items.Firearms.Modules; +using JetBrains.Annotations; using LabApi.Events.Arguments.PlayerEvents; using LabApi.Events.Arguments.Scp914Events; using LabApi.Events.Arguments.ServerEvents; @@ -13,6 +16,7 @@ using LabApi.Loader.Features.Plugins; using MapGeneration; using MEC; using PlayerRoles; +using Scp914.Processors; using UnityEngine; using Logger = LabApi.Features.Console.Logger; using Random = System.Random; @@ -20,16 +24,14 @@ using Vector3 = UnityEngine.Vector3; namespace CustomClasses; + /// /// Main plugin class for CustomClasses. Handles plugin lifecycle and event subscriptions. /// public sealed class CustomClasses : Plugin { - private readonly CustomClassManager _classManager; - public CustomClasses() - { - _classManager = new CustomClassManager(); - } + public readonly CustomClassManager ClassManager = new(); + public SerpentsHandManager SerpentsHandManager; /// public override string Name => "CustomClasses"; @@ -41,7 +43,9 @@ public sealed class CustomClasses : Plugin public override string Description => "Adds custom classes to the game"; /// public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); - + + public const ushort BroadcastDuration = 10; + /// /// Configuration for the Janitor class. /// @@ -67,20 +71,79 @@ public sealed class CustomClasses : Plugin /// Configuration for the ShadowStepper class. /// public ShadowStepperConfig ShadowStepperConfig { get; private set; } = new(); + + public MtfDemolitionistConfig MtfDemolitionistConfig { get; private set; } = new(); + public ScoutConfig ScoutConfig { get; private set; } = new(); + public ExplosiveMasterConfig ExplosiveMasterConfig { get; private set; } = new(); + public FlashMasterConfig FlashMasterConfig { get; private set; } = new(); + public SerpentsHandConfig SerpentsHandConfig { get; private set; } = new(); + + internal readonly Dictionary Hints = new(); + + public static CustomClasses Instance { get; private set; } + + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; - /// public override void Enable() { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + PlayerEvents.Spawned += OnPlayerSpawned; ServerEvents.RoundEnded += OnRoundEnded; Scp914Events.ProcessingPickup += OnScp914ProcessingPickup; Scp914Events.ProcessingInventoryItem += OnScp914ProcessingInventoryItem; - PlayerEvents.Escaped += OnEscaped; - } - - private void OnEscaped(PlayerEscapedEventArgs ev) - { + ServerEvents.WaveTeamSelected += OnWaveTeamSelected; + ServerEvents.WaveRespawning += OnWaveRespawning; + PlayerEvents.UsedItem += OnItemUsed; + ServerEvents.GeneratorActivated += OnGeneratorEngaged; + SerpentsHandManager = new SerpentsHandManager(this); + + Timing.RunCoroutine(SerpentsHandManager.UpdateSerpentsHandHint()); + + if (InventoryItemLoader.AvailableItems.TryGetValue(ItemType.KeycardCustomTaskForce, out var itemBase)) + { + if (!itemBase.TryGetComponent(out _)) + { + var processor = itemBase.gameObject.AddComponent(); + + var type = processor.GetType(); + var fields = new[] + { + "_roughOutputs", + "_coarseOutputs", + "_oneToOneOutputs", + "_fineOutputs", + "_veryFineOutputs" + }; + + var output = new[] { ItemType.KeycardMTFCaptain }; + + foreach (var fieldName in fields) + { + var field = type.GetField(fieldName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + field?.SetValue(processor, output); + } + + } + } + + + Instance = this; } /// @@ -90,30 +153,142 @@ public sealed class CustomClasses : Plugin ServerEvents.RoundEnded -= OnRoundEnded; Scp914Events.ProcessingPickup -= OnScp914ProcessingPickup; Scp914Events.ProcessingInventoryItem -= OnScp914ProcessingInventoryItem; - PlayerEvents.Escaped -= OnEscaped; + ServerEvents.WaveTeamSelected -= OnWaveTeamSelected; + ServerEvents.WaveRespawning -= OnWaveRespawning; + PlayerEvents.UsedItem -= OnItemUsed; + ServerEvents.GeneratorActivated -= OnGeneratorEngaged; + + Instance = null; + } + + private void OnGeneratorEngaged(GeneratorActivatedEventArgs ev) + { + if (ClassManager.GetSpawnState(typeof(SerpentsHandConfig)) is not SerpentsHandState state) return; + + state.ExtraChance += 2.5f; + } + + private void OnItemUsed(PlayerUsedItemEventArgs ev) + { + if (ClassManager.GetSpawnState(typeof(SerpentsHandConfig)) is not SerpentsHandState state) return; + + switch (ev.UsableItem.Type) + { + case ItemType.SCP268 or ItemType.SCP1576 or ItemType.SCP1344: + state.ExtraChance += 1; + break; + case ItemType.SCP500 or ItemType.SCP207 or ItemType.SCP1853 or ItemType.AntiSCP207 + or ItemType.SCP018 or ItemType.SCP2176: + state.ExtraChance += 2; + break; + case ItemType.SCP244a or ItemType.SCP244b: + state.ExtraChance += 0.5f; + break; + } + } + + [SuppressMessage("ReSharper", "RedundantJumpStatement")] + private void OnWaveTeamSelected(WaveTeamSelectedEventArgs ev) + { + var spectators = Player.ReadyList.Where(p => p.Role == RoleTypeId.Spectator).ToList(); + if (spectators.Count <= 1) return; + + var random = new Random(); + + var spectator = spectators[random.Next(spectators.Count-1)]; + + if (ev.Wave == RespawnWaves.MiniChaosWave && ClassManager.GetSpawnState(typeof(SerpentsHandConfig)) is SerpentsHandState + { + HasSpawned: false + } state) + { + if (random.Next(0, 100) > SerpentsHandConfig.BaseChance + state.ExtraChance) + { + state.SetSpawned(); + state.SetWillSpawn(); + + ClassManager.TryHandleSpawn(spectator, ScoutConfig, typeof(ScoutConfig), () => + { + if (!ClassManager.ForceSpawn(spectator, SerpentsHandConfig, typeof(SerpentsHandConfig), PreSpawn)) + Logger.Error("Serpents Hand didn't spawn"); + return; + + void PreSpawn() + { + SerpentsHandManager.PreSpawn(spectator); + } + }); + + return; + } + } + + if (ClassManager.TryHandleSpawn(spectator, ScoutConfig, typeof(ScoutConfig), () => + { + spectator.SetRole(ev.Wave.Faction == Faction.FoundationStaff ? RoleTypeId.NtfPrivate : RoleTypeId.ChaosConscript, RoleChangeReason.Respawn, RoleSpawnFlags.UseSpawnpoint); + })) return; + } + + private void OnWaveRespawning(WaveRespawningEventArgs ev) + { + if (ev.Wave != RespawnWaves.MiniChaosWave) return; + if (ClassManager.GetSpawnState(typeof(SerpentsHandConfig)) is not SerpentsHandState state) return; + + if (!state.WillSpawn) return; + + Cassie.Message("pitch_0.23 .G4 yield_03 .G4 pitch_1 Space yield_0.65 time breach detected near site yield_0.45 entrance yield_1.5 Security yield_0.8 pitch_0.95 Personnel pitch_1 proceed jam_01_2 .G6 with yield_0.4 pitch_0.45 jam_02_3 .G3 yield_0.15 pitch_0.35 .G2 jam_01_5 yield_0.15 pitch_0.2 .G1 pitch_0.9 yield_0.8 protocol", true, false, customSubtitles: "Space-time breach detected near site entrance. Security Personnel proceed with {DATA-EXPUNGED} protocol."); + + state.SetWillNotSpawn(); + + ev.IsAllowed = false; + foreach (var evSpawningPlayer in ev.SpawningPlayers) + { + if (!ClassManager.ForceSpawn(evSpawningPlayer, SerpentsHandConfig, typeof(SerpentsHandConfig), PreSpawn)) + Logger.Error("Serpents Hand didn't spawn"); + continue; + + void PreSpawn() + { + SerpentsHandManager.PreSpawn(evSpawningPlayer); + } + } } private void OnRoundEnded(RoundEndedEventArgs ev) { - _classManager.ResetSpawnStates(); + ClassManager.ResetSpawnStates(); } [SuppressMessage("ReSharper", "RedundantJumpStatement")] 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; - if (_classManager.TryHandleSpawn(ev.Player, MedicConfig, typeof(MedicConfig))) return; - if (_classManager.TryHandleSpawn(ev.Player, GamblerConfig, typeof(GamblerConfig))) return; - if (_classManager.TryHandleSpawn(ev.Player, ShadowStepperConfig, typeof(ShadowStepperConfig))) return; + ev.Player.CustomInfo = ""; + + if (ClassManager.TryHandleSpawn(ev.Player, JanitorConfig, typeof(JanitorConfig), null)) return; + if (ClassManager.TryHandleSpawn(ev.Player, ResearchSubjectConfig, typeof(ResearchSubjectConfig), null)) return; + if (ClassManager.TryHandleSpawn(ev.Player, HeadGuardConfig, typeof(HeadGuardConfig), null)) return; + if (ClassManager.TryHandleSpawn(ev.Player, MedicConfig, typeof(MedicConfig), null)) return; + if (ClassManager.TryHandleSpawn(ev.Player, GamblerConfig, typeof(GamblerConfig), null)) return; + if (ClassManager.TryHandleSpawn(ev.Player, ShadowStepperConfig, typeof(ShadowStepperConfig), null)) return; + if (ClassManager.TryHandleSpawn(ev.Player, MtfDemolitionistConfig, typeof(MtfDemolitionistConfig), null)) return; + if (ClassManager.TryHandleSpawn(ev.Player, ExplosiveMasterConfig, typeof(ExplosiveMasterConfig), null)) return; + if (ClassManager.TryHandleSpawn(ev.Player, FlashMasterConfig, typeof(FlashMasterConfig), null)) return; } private static void OnScp914ProcessingPickup(Scp914ProcessingPickupEventArgs ev) { - if (ev.Pickup.Type < ItemType.KeycardCustomTaskForce) return; // Process custom upgrade - if (ev.Pickup is not KeycardPickup keycard) return; + if (ev.Pickup is not KeycardPickup keycard) + { + Logger.Debug($"Keycard not found for SCP-914 pickup {ev.Pickup.Serial}"); + return; + } + + if (keycard.Type < ItemType.KeycardCustomTaskForce) + { + Logger.Debug($"Keycard not a custom card {ev.Pickup.Serial}"); + return; + } var pickup = Pickup.Create(ItemType.KeycardMTFCaptain, keycard.Position); keycard.Destroy(); pickup?.Spawn(); @@ -121,9 +296,9 @@ public sealed class CustomClasses : Plugin private static void OnScp914ProcessingInventoryItem(Scp914ProcessingInventoryItemEventArgs ev) { - if (ev.Item.Type < ItemType.KeycardCustomTaskForce) return; // Process custom upgrade if (ev.Item is not KeycardItem keycard) return; + if (!keycard.Base.Customizable) return; ev.Player.RemoveItem(keycard); ev.Player.AddItem(ItemType.KeycardMTFCaptain, ItemAddReason.Scp914Upgrade); } @@ -145,11 +320,24 @@ public class CustomClassManager public CustomClassManager() { RegisterHandler(new JanitorHandler(this)); - RegisterHandler(new ResearchSubjectHandler(this)); + RegisterHandler(new ResearchSubjectHandler()); RegisterHandler(new HeadGuardHandler()); RegisterHandler(new MedicHandler()); RegisterHandler(new GamblerHandler()); RegisterHandler(new ShadowStepperHandler()); + RegisterHandler(new DemolitionistHandler()); + RegisterHandler(new ScoutHandler()); + RegisterHandler(new ExplosiveMasterHandler()); + RegisterHandler(new FlashMasterHandler()); + RegisterHandler(new SerpentsHandHandler(), new SerpentsHandState()); + } + + public SpawnState GetSpawnState(Type configType) + { + lock (_lock) + { + return _spawnStates[configType]; + } } /// @@ -159,7 +347,7 @@ public class CustomClassManager /// The base position. 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)); + player.Position = position + new Vector3(0, 1, 0) + new Vector3((float)(_random.NextDouble() * 2 - 1), 0, (float)(_random.NextDouble() * 2 - 1)); } /// @@ -167,11 +355,12 @@ public class CustomClassManager /// /// The config type. /// The handler instance. - private void RegisterHandler(ICustomClassHandler handler) where T : CustomClassConfig + /// Optional custom spawn state + private void RegisterHandler(ICustomClassHandler handler, [CanBeNull] SpawnState spawnState = null) where T : CustomClassConfig { lock (_lock) { - _spawnStates[typeof(T)] = new SpawnState(); + _spawnStates[typeof(T)] = spawnState ?? new SpawnState(); _handlers[typeof(T)] = handler; } } @@ -184,7 +373,7 @@ public class CustomClassManager lock (_lock) { foreach (var key in _spawnStates.Keys.ToList()) - _spawnStates[key] = new SpawnState(); + _spawnStates[key].Reset(); } } @@ -194,8 +383,9 @@ public class CustomClassManager /// The player to handle. /// The config instance. /// The config type. + /// /// True if the spawn was handled; otherwise, false. - public bool TryHandleSpawn(Player player, CustomClassConfig config, Type configType) + public bool TryHandleSpawn(Player player, CustomClassConfig config, Type configType, Action preSpawn) { if (player.Role != config.RequiredRole) return false; if (Player.ReadyList.Count() <= config.MinPlayers) return false; @@ -216,12 +406,18 @@ public class CustomClassManager } state.Spawns++; Logger.Debug($"Player spawning {configType} - {player.Nickname} - {state.Spawns} / {config.MaxSpawns}"); - if (!_handlers.TryGetValue(configType, out var handler)) - return false; - Timing.CallDelayed(0.5f, () => { handler.HandleSpawn(player, config, _random); }); - return true; + return ForceSpawn(player, config, configType, preSpawn); } } + + public bool ForceSpawn(Player player, CustomClassConfig config, Type configType, Action preSpawn) + { + if (!_handlers.TryGetValue(configType, out var handler)) + return false; + preSpawn?.Invoke(); + Timing.CallDelayed(0.5f, () => { handler.HandleSpawn(player, config, _random); }); + return true; + } } /// @@ -236,8 +432,6 @@ public interface ICustomClassHandler /// The configuration for the custom class. /// A random number generator. void HandleSpawn(Player player, CustomClassConfig config, Random random); - - void HandleEscape(Player player, CustomClassConfig config); } public abstract class CustomClassHandler: ICustomClassHandler @@ -269,14 +463,14 @@ public class JanitorHandler(CustomClassManager manager) : CustomClassHandler player.AddItem(spawnItem, ItemAddReason.StartingItem); Logger.Debug($"Gave player {player.Nickname} spawn item {spawnItem}"); } - player.SendBroadcast("You're a Janitor!", 3); + player.SendBroadcast("You're a Janitor!", CustomClasses.BroadcastDuration); } } /// /// Handler for the Research Subject custom class. /// -public class ResearchSubjectHandler(CustomClassManager manager) : CustomClassHandler +public class ResearchSubjectHandler : CustomClassHandler { public override void HandleSpawn(Player player, CustomClassConfig config, Random random) { @@ -286,13 +480,13 @@ public class ResearchSubjectHandler(CustomClassManager manager) : CustomClassHan Logger.Error("No Scientist found for Research Subject spawn."); return; } - manager.TeleportPlayerToAround(player, scientist.Position); + player.Position = 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 Research Subject!", 3); + player.SendBroadcast("You're a Research Subject!", CustomClasses.BroadcastDuration); } } @@ -314,7 +508,7 @@ public class HeadGuardHandler : CustomClassHandler { if (firearm.Base.Template.TryGetModule(out MagazineModule magazine)) { - magazine.ServerSetInstanceAmmo(firearm.Base.Template.ItemSerial, magazine.AmmoMax); + magazine.ServerSetInstanceAmmo(firearm.Serial, magazine.AmmoMax); } else { @@ -325,9 +519,9 @@ public class HeadGuardHandler : CustomClassHandler { Logger.Error("Failed to get firearm from pickup for Head Guard."); } - if (pickup != null) player.AddItem(pickup); + player.AddItem(pickup!); player.SetAmmo(ItemType.Ammo9x19, 120); - player.SendBroadcast("You're a Head Guard!", 3); + player.SendBroadcast("You're a Head Guard!", CustomClasses.BroadcastDuration); } } @@ -343,7 +537,7 @@ public class MedicHandler : CustomClassHandler player.AddItem(spawnItem, ItemAddReason.StartingItem); Logger.Debug($"Gave player {player.Nickname} spawn item {spawnItem}"); } - player.SendBroadcast("You're a Medic!", 3); + player.SendBroadcast("You're a Medic!", CustomClasses.BroadcastDuration); } } @@ -356,7 +550,7 @@ public class ShadowStepperHandler : CustomClassHandler { ApplyEffects(player); - player.SendBroadcast("You're a ShadowStepper!", 3); + player.SendBroadcast("You're a ShadowStepper!", CustomClasses.BroadcastDuration); } public override void HandleEscape(Player player, CustomClassConfig config) @@ -369,7 +563,7 @@ public class ShadowStepperHandler : CustomClassHandler private static void ApplyEffects(Player player) { player.ReferenceHub.playerEffectsController.ChangeState(100,float.MaxValue); - player.ReferenceHub.playerEffectsController.ChangeState(20,float.MaxValue); + player.ReferenceHub.playerEffectsController.ChangeState(10,float.MaxValue); } } @@ -396,7 +590,166 @@ public class GamblerHandler : SimpleAddItemHandler public override void HandleSpawn(Player player, CustomClassConfig config, Random random) { base.HandleSpawn(player, config, random); - player.SendBroadcast("You're a Gambler!", 3); + player.SendBroadcast("You're a Gambler!", CustomClasses.BroadcastDuration); + } +} + +/// +/// Handler for the Demolitionist custom class. +/// +public class DemolitionistHandler : SimpleAddItemHandler +{ + public override void HandleSpawn(Player player, CustomClassConfig config, Random random) + { + base.HandleSpawn(player, config, random); + player.SendBroadcast("You're a NTF Demolitionist!", CustomClasses.BroadcastDuration); + } +} + +public class ScoutHandler : SimpleAddItemHandler +{ + public override void HandleSpawn(Player player, CustomClassConfig config, Random random) + { + base.HandleSpawn(player, config, random); + + const ItemType gun = ItemType.GunCrossvec; + var gunPickup = Pickup.Create(gun, Vector3.one); + if (gunPickup is FirearmPickup firearm) + { + if (firearm.Base.Template.TryGetModule(out MagazineModule magazine)) + { + magazine.ServerSetInstanceAmmo(firearm.Serial, magazine.AmmoMax); + } + else + { + Logger.Error("Failed to get magazine module for Serpents Hand firearm."); + } + } + else + { + Logger.Error("Failed to get firearm from pickup for Serpents Hand."); + } + + player.AddItem(gunPickup!); + + player.ReferenceHub.playerEffectsController.ChangeState(40,32); + + Timing.RunCoroutine(DecreaseSpeedBoost()); + + player.SendBroadcast("You're a Scout for your Faction! The rest of your Faction will spawn shortly.", CustomClasses.BroadcastDuration); + return; + + IEnumerator DecreaseSpeedBoost() + { + const float baseIntensity = 40f; + const float baseDuration = 30f; + const float minimumIntensity = 10f; + const float deltaIntensity = baseIntensity - minimumIntensity; + const float intensityStep = deltaIntensity / baseDuration; + var duration = baseDuration; + while (duration-- > 0) + { + yield return Timing.WaitForSeconds(1f); + var intensity = (byte) (baseIntensity - intensityStep * (baseDuration - duration)); + player.ReferenceHub.playerEffectsController.ChangeState(intensity, 5); + } + player.ReferenceHub.playerEffectsController.ChangeState(10,9999); + } + } +} + +public class ExplosiveMasterHandler : SimpleAddItemHandler +{ + public override void HandleSpawn(Player player, CustomClassConfig config, Random random) + { + base.HandleSpawn(player, config, random); + player.SendBroadcast("You're an Explosive Master!", CustomClasses.BroadcastDuration); + player.SendBroadcast("IF YOU THROW THE GRENADE YOU WILL EXPLODE.", CustomClasses.BroadcastDuration); + + PlayerEvents.ThrowingProjectile += HandleGrenade; + PlayerEvents.Spawning += HandlePlayerSpawn; + PlayerEvents.UsingItem += HandleUsing; + PlayerEvents.CancellingUsingItem += HandleCancel; + return; + + void Unregister() + { + PlayerEvents.ThrowingProjectile -= HandleGrenade; + PlayerEvents.Spawning -= HandlePlayerSpawn; + PlayerEvents.UsingItem -= HandleUsing; + PlayerEvents.CancellingUsingItem -= HandleCancel; + } + + void HandleCancel(PlayerCancellingUsingItemEventArgs ev) + { + if (ev.Player != player) return; + if (ev.UsableItem.Type is not ItemType.GrenadeHE) return; + + player.DisableEffect(); + } + + void HandleUsing(PlayerUsingItemEventArgs ev) + { + if (ev.Player != player) return; + + if (ev.UsableItem.Type is ItemType.GrenadeHE) + { + player.EnableEffect(10, float.MaxValue); + } + } + + void HandleGrenade(PlayerThrowingProjectileEventArgs ev) + { + if (ev.Player != player) return; + if (ev.ThrowableItem.Type is not ItemType.GrenadeHE) return; + TimedGrenadeProjectile.SpawnActive(ev.Player.Position, ItemType.GrenadeHE, ev.Player); + TimedGrenadeProjectile.SpawnActive(ev.Player.Position, ItemType.GrenadeHE, ev.Player); + + PlayerEvents.ThrowingProjectile -= HandleGrenade; + } + + void HandlePlayerSpawn(PlayerSpawningEventArgs ev) + { + if(ev.Player != player) return; + Unregister(); + } + } + + +} + +public class FlashMasterHandler : SimpleAddItemHandler +{ + public override void HandleSpawn(Player player, CustomClassConfig config, Random random) + { + base.HandleSpawn(player, config, random); + player.SendBroadcast("You're a Flash Master!", CustomClasses.BroadcastDuration); + + PlayerEvents.ThrowingProjectile += HandleGrenade; + PlayerEvents.Spawning += HandlePlayerSpawn; + return; + + void Unregister() + { + PlayerEvents.ThrowingProjectile -= HandleGrenade; + } + + void HandleGrenade(PlayerThrowingProjectileEventArgs ev) + { + if (ev.Player != player) return; + if (ev.ThrowableItem.Type is not ItemType.GrenadeFlash) return; + + for (var i = 0; i < 3; i++) + TimedGrenadeProjectile.SpawnActive(ev.Player.Position, ItemType.GrenadeFlash, ev.Player); + + PlayerEvents.ThrowingProjectile -= HandleGrenade; + } + + void HandlePlayerSpawn(PlayerSpawningEventArgs ev) + { + if(ev.Player != player) return; + Unregister(); + } } } @@ -477,15 +830,50 @@ public sealed class GamblerConfig : CustomClassConfig /// /// Configuration for the Shadow Stepper class. /// -public sealed class ShadowStepperConfig : CustomClassConfig +public sealed class ShadowStepperConfig : CustomClassConfig; + +public sealed class MtfDemolitionistConfig : CustomClassConfig { - + public override double ChancePerPlayer { get; set; } = 0.2; + public override int MaxSpawns { get; set; } = int.MaxValue; + public override RoleTypeId RequiredRole { get; set; } = RoleTypeId.NtfPrivate; + public override ItemType[] Items { get; set; } = [ItemType.GrenadeHE, ItemType.GrenadeHE, ItemType.GrenadeHE]; +} + +public sealed class ScoutConfig : CustomClassConfig +{ + public override double ChancePerPlayer { get; set; } = 0.25; + public override int MaxSpawns { get; set; } = int.MaxValue; + public override RoleTypeId RequiredRole { get; set; } = RoleTypeId.Spectator; + public override ItemType[] Items { get; set; } = [ItemType.GrenadeFlash, ItemType.KeycardMTFOperative, ItemType.ArmorLight, ItemType.Medkit ,ItemType.Ammo9x19, ItemType.Ammo9x19, ItemType.Ammo9x19, ItemType.Ammo9x19, ItemType.Ammo9x19, ItemType.Ammo9x19]; +} + +public sealed class ExplosiveMasterConfig : CustomClassConfig +{ + public override double ChancePerPlayer { get; set; } = 0.2; + public override int MaxSpawns { get; set; } = int.MaxValue; + public override RoleTypeId RequiredRole { get; set; } = RoleTypeId.ChaosMarauder; + public override ItemType[] Items { get; set; } = [ItemType.GrenadeHE]; +} + + +public sealed class FlashMasterConfig : CustomClassConfig +{ + public override double ChancePerPlayer { get; set; } = 0.0; + public override int MaxSpawns { get; set; } = int.MaxValue; + public override RoleTypeId RequiredRole { get; set; } = RoleTypeId.ChaosMarauder; + public override ItemType[] Items { get; set; } = [ItemType.GrenadeFlash]; } /// /// Tracks the spawn state for a custom class. /// -internal sealed record SpawnState +public record SpawnState { public int Spawns; + + public virtual void Reset() + { + Spawns = 0; + } } \ No newline at end of file diff --git a/CustomClasses/CustomClasses.csproj b/CustomClasses/CustomClasses.csproj index a0ec31e..d4a879e 100644 --- a/CustomClasses/CustomClasses.csproj +++ b/CustomClasses/CustomClasses.csproj @@ -26,12 +26,24 @@ ..\dependencies\Assembly-CSharp-firstpass.dll + + ..\dependencies\CommandSystem.Core.dll + + + ..\dependencies\HintServiceMeow-LabAPI.dll + ..\dependencies\Mirror.dll ..\dependencies\NorthwoodLib.dll + + ..\dependencies\Pooling.dll + + + ..\dependencies\System.Collections.Immutable.dll + ..\dependencies\UnityEngine.CoreModule.dll diff --git a/CustomClasses/SerpentsHandManager.cs b/CustomClasses/SerpentsHandManager.cs new file mode 100644 index 0000000..db8d841 --- /dev/null +++ b/CustomClasses/SerpentsHandManager.cs @@ -0,0 +1,276 @@ +using CommandSystem; +using CustomPlayerEffects; +using HintServiceMeow.Core.Enum; +using HintServiceMeow.Core.Models.Hints; +using HintServiceMeow.Core.Utilities; +using Interactables.Interobjects.DoorUtils; +using InventorySystem.Items.Firearms.Modules; +using LabApi.Events.Handlers; +using LabApi.Features.Permissions; +using LabApi.Features.Wrappers; +using MEC; +using PlayerRoles; +using UnityEngine; +using Logger = LabApi.Features.Console.Logger; +using Random = System.Random; + +namespace CustomClasses; + +public class SerpentsHandManager +{ + public static bool IsSerpentsHand(Player player) => player.CustomInfo.Contains("SerpentsHand"); + + private readonly CustomClasses _customClasses; + public SerpentsHandManager(CustomClasses customClasses) + { + _customClasses = customClasses; + + PlayerEvents.Escaping += ev => + { + if (!IsSerpentsHand(ev.Player)) return; + var state = (SerpentsHandState) _customClasses.ClassManager.GetSpawnState(typeof(SerpentsHandConfig)); + var hadItem = false; + foreach (var playerItem in ev.Player.Items) + { + switch (playerItem.Type) + { + case ItemType.SCP018 or ItemType.SCP207 or ItemType.SCP244a or ItemType.SCP244b + or ItemType.SCP268 or ItemType.SCP330 or ItemType.SCP500 or ItemType.SCP1344 or ItemType.SCP1576 + or ItemType.SCP1853 or ItemType.SCP2176 or ItemType.AntiSCP207: + state.Points += 1; + hadItem = true; + break; + case ItemType.GunSCP127: + state.Points += 2; + hadItem = true; + break; + } + } + + if (!hadItem) return; + + ev.Player.SendBroadcast("You brought back the SCP items...", 5); + + ev.Player.SetRole(RoleTypeId.Spectator); + + Logger.Info($"New SH Points: {state.Points}"); + }; + + ServerEvents.RoundEnding += ev => + { + var factions = + Player.ReadyList.Select(x => + { + return x.Team switch + { + Team.ChaosInsurgency or Team.ClassD => Faction.FoundationEnemy, + Team.FoundationForces or Team.Scientists => Faction.FoundationStaff, + Team.Flamingos => Faction.Flamingos, + Team.SCPs => Faction.SCP, + Team.OtherAlive when IsSerpentsHand(x) => (Faction)35, + _ => Faction.Unclassified + }; + }).Where(x=>x!=Faction.Unclassified).GroupBy(x=>x).Select(x=>x.Key).ToArray(); + + if (factions.Length > 1) + { + ev.IsAllowed = false; + return; + } + + var state = (SerpentsHandState) _customClasses.ClassManager.GetSpawnState(typeof(SerpentsHandConfig)); + if (state.Points >= 10) + { + ev.LeadingTeam = RoundSummary.LeadingTeam.Flamingos; + } + + }; + } + + public static void PreSpawn(Player player) + { + player.SetRole(RoleTypeId.Tutorial, RoleChangeReason.RespawnMiniwave, RoleSpawnFlags.None); + const string customInfo = "SerpentsHand"; + if (!Player.ValidateCustomInfo(customInfo, out var reason)) + { + Logger.Error($"Invalid custom info for Serpents Hand: {reason}"); + } + else + { + player.CustomInfo = customInfo; + player.InfoArea |= PlayerInfoArea.CustomInfo; + } + } + + public IEnumerator UpdateSerpentsHandHint() + { + while (true) + { + yield return Timing.WaitForSeconds(1); + + if (_customClasses.ClassManager.GetSpawnState(typeof(SerpentsHandConfig)) is not SerpentsHandState state) continue; + + foreach (var player in Player.ReadyList) + { + if (!_customClasses.Hints.ContainsKey(player)) + { + _customClasses.Hints[player] = new Hint + { + Text = "", Alignment = HintAlignment.Center, YCoordinate = 900, Hide = true + }; + + var playerDisplay = PlayerDisplay.Get(player); + playerDisplay.AddHint(_customClasses.Hints[player]); + } + + _customClasses.Hints[player].Text = + $"Serpents Hand Chance: {state.ExtraChance + SerpentsHandConfig.BaseChance:0.00}%"; + _customClasses.Hints[player].Hide = state.HasSpawned || player.Role != RoleTypeId.Spectator; + } + } + // ReSharper disable once IteratorNeverReturns + } +} + +public sealed record SerpentsHandState: SpawnState +{ + public bool HasSpawned => _hasSpawned || PanicDisable; + public float ExtraChance; + public int Points; + public bool WillSpawn => _willSpawn && !PanicDisable; + + private bool _hasSpawned; + private bool _willSpawn; + + public bool PanicDisable; + + public override void Reset() + { + base.Reset(); + _hasSpawned = false; + ExtraChance = 0f; + Points = 0; + _willSpawn = false; + } + + public void SetSpawned() + { + _hasSpawned = true; + } + + public void SetWillSpawn() + { + _willSpawn = true; + } + + public void SetWillNotSpawn() + { + _willSpawn = false; + } +} + +public sealed class SerpentsHandConfig : CustomClassConfig +{ + public override double ChancePerPlayer { get; set; } = 1.0; + public override int MaxSpawns { get; set; } = int.MaxValue; + public override RoleTypeId RequiredRole { get; set; } = RoleTypeId.Tutorial; + public override ItemType[] Items { get; set; } = [ItemType.Painkillers, ItemType.Medkit, ItemType.ArmorCombat]; + + public const float BaseChance = 20f; +} + +public class SerpentsHandHandler : SimpleAddItemHandler +{ + public override void HandleSpawn(Player player, CustomClassConfig config, Random random) + { + base.HandleSpawn(player, config, random); + + // player.Position = new Vector3(123.921f + (float)(random.NextDouble() * 2 - 1), 288.792f, 20.929f + (float)(random.NextDouble() * 2 - 1)); + + player.Position = new Vector3(0.22f + (float)(random.NextDouble() * 2 - 1), 300.96f, -0.31f + (float)(random.NextDouble() * 2 - 1)); + + ItemType[] guns = [ItemType.GunAK, ItemType.GunE11SR, ItemType.GunCrossvec]; + var gun = guns[random.Next(0, guns.Length-1)]; + var gunPickup = Pickup.Create(gun, Vector3.one); + if (gunPickup is FirearmPickup firearm) + { + if (firearm.Base.Template.TryGetModule(out MagazineModule magazine)) + { + magazine.ServerSetInstanceAmmo(firearm.Serial, magazine.AmmoMax); + player.SetAmmo(magazine.AmmoType, 120); + } + else + { + Logger.Error("Failed to get magazine module for Serpents Hand firearm."); + } + } + else + { + Logger.Error("Failed to get firearm from pickup for Serpents Hand."); + } + + player.AddItem(gunPickup!); + + KeycardItem.CreateCustomKeycardTaskForce( + player, + "Serpent's Hand Keycard", + $"SH. {player.Nickname}", + new KeycardLevels(3, 3, 2), + Color.black, + new Color(0.271f, 0.271f, 0.271f), + "SH", + 3 + ); + + player.EnableEffect(20, 30); + + player.SendBroadcast("You're a Serpent's Hand member!", CustomClasses.BroadcastDuration); + } +} + + +[CommandHandler(typeof(RemoteAdminCommandHandler))] +public class PanicDisableRemoteAdminCommand : ICommand +{ + public string Command => "panicdisableserpentshand"; + public string[] Aliases => []; + public string Description => "Panic disable Serpents Hand."; + + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + var state = (SerpentsHandState)CustomClasses.Instance.ClassManager.GetSpawnState(typeof(SerpentsHandConfig)); + state.PanicDisable = true; + + response = "Serpents Hand has been disabled."; + return true; + } +} + +[CommandHandler(typeof(ClientCommandHandler))] +public class PanicDisableCommand : ICommand +{ + public string Command => "panicdisableserpentshand"; + public string[] Aliases => []; + public string Description => "Panic disable Serpents Hand."; + + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + if (!Player.TryGet(sender, out var player)) + { + response = "You must be a player to use this command!"; + return false; + } + + if (!player.HasPermissions("panicdisable.serpentshand") && player.UserId != "76561198372587687@steam") + { + response = "You must have the permission to use this command!"; + return false; + } + + var state = (SerpentsHandState)CustomClasses.Instance.ClassManager.GetSpawnState(typeof(SerpentsHandConfig)); + state.PanicDisable = true; + + response = "Serpents Hand has been disabled."; + return true; + } +} diff --git a/CustomClasses/SetCClassCommand.cs b/CustomClasses/SetCClassCommand.cs new file mode 100644 index 0000000..d1e39de --- /dev/null +++ b/CustomClasses/SetCClassCommand.cs @@ -0,0 +1,66 @@ +using CommandSystem; +using LabApi.Features.Wrappers; + +namespace CustomClasses; + +[CommandHandler(typeof(RemoteAdminCommandHandler))] +public class SetCClassCommand : ICommand +{ + public string Command => "setcclass"; + public string[] Aliases => ["scc"]; + public string Description => "Forces a player to become a specific custom class"; + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + var args = arguments.Array!; + if (arguments.Count < 2) + { + response = "Usage: setcclass "; + return false; + } + + // Find the last argument as the class name + var className = args[arguments.Offset + arguments.Count - 1].ToLower(); + + // Join all arguments except the last one to get the full player name + var playerName = string.Join(" ", args.Skip(arguments.Offset).Take(arguments.Count - 1)); + + var player = Player.ReadyList.FirstOrDefault(x => x.Nickname == playerName || x.UserId == playerName); + if (player == null) + { + response = $"Player {playerName} not found"; + return false; + } + + var customClasses = CustomClasses.Instance; + var manager = new CustomClassManager(); + + var success = className switch + { + "janitor" => manager.ForceSpawn(player, customClasses.JanitorConfig, typeof(JanitorConfig), null), + "subject" or "researchsubject" => manager.ForceSpawn(player, customClasses.ResearchSubjectConfig, typeof(ResearchSubjectConfig), null), + "headguard" => manager.ForceSpawn(player, customClasses.HeadGuardConfig, typeof(HeadGuardConfig), null), + "medic" => manager.ForceSpawn(player, customClasses.MedicConfig, typeof(MedicConfig), null), + "gambler" => manager.ForceSpawn(player, customClasses.GamblerConfig, typeof(GamblerConfig), null), + "shadowstepper" => manager.ForceSpawn(player, customClasses.ShadowStepperConfig, typeof(ShadowStepperConfig), null), + "demolitionist" => manager.ForceSpawn(player, customClasses.MtfDemolitionistConfig, typeof(MtfDemolitionistConfig), null), + "scout" => manager.ForceSpawn(player, customClasses.ScoutConfig, typeof(ScoutConfig), null), + "explosivemaster" => manager.ForceSpawn(player, customClasses.ExplosiveMasterConfig, typeof(ExplosiveMasterConfig), null), + "flashmaster" => manager.ForceSpawn(player, customClasses.FlashMasterConfig, typeof(FlashMasterConfig), null), + "serpentshand" => manager.ForceSpawn(player, customClasses.SerpentsHandConfig, typeof(SerpentsHandConfig), + () => + { + SerpentsHandManager.PreSpawn(player); + }), + _ => false + }; + + if (!success) + { + response = $"Failed to set {playerName} to {className}. Make sure the player has the correct base role for the custom class."; + return false; + } + + response = $"Successfully set {playerName} to {className}"; + return true; + } +} \ No newline at end of file diff --git a/CustomItemSpawn/CustomItemSpawn.cs b/CustomItemSpawn/CustomItemSpawn.cs index dc7d8a7..6aa39de 100644 --- a/CustomItemSpawn/CustomItemSpawn.cs +++ b/CustomItemSpawn/CustomItemSpawn.cs @@ -18,8 +18,26 @@ public class CustomItemSpawn : Plugin public override string Description => "Spawns items in a custom location."; public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + _singleton = this; ServerEvents.RoundStarted += OnRoundStart; } diff --git a/GamblingCoin/GamblingCoin.cs b/GamblingCoin/GamblingCoin.cs index e2ce072..6b3ee04 100644 --- a/GamblingCoin/GamblingCoin.cs +++ b/GamblingCoin/GamblingCoin.cs @@ -28,9 +28,26 @@ public class Plugin : LabApi.Loader.Features.Plugins.Plugin ConfigChances = this.LoadConfig("chances.yml"); } + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { - Logger.Debug("starting..."); + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + Singleton = this; _eventHandler = new GamblingCoinEventHandler(); PlayerEvents.FlippedCoin += _eventHandler.OnFlippedCoin; diff --git a/GamblingCoin/GamblingCoin.csproj b/GamblingCoin/GamblingCoin.csproj index 3658590..ee4d3b8 100644 --- a/GamblingCoin/GamblingCoin.csproj +++ b/GamblingCoin/GamblingCoin.csproj @@ -23,6 +23,9 @@ ..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Assembly-CSharp.dll + + ..\dependencies\Assembly-CSharp-firstpass.dll + ..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll diff --git a/GamblingCoin/GamblingCoinEventHandler.cs b/GamblingCoin/GamblingCoinEventHandler.cs index 3995e8c..7c8aef6 100644 --- a/GamblingCoin/GamblingCoinEventHandler.cs +++ b/GamblingCoin/GamblingCoinEventHandler.cs @@ -1,11 +1,11 @@ using LabApi.Events.Arguments.PlayerEvents; using LabApi.Features.Wrappers; using MapGeneration; +using MEC; using Mirror; using PlayerRoles; using Respawning; using UnityEngine; -using MicroHIDItem = InventorySystem.Items.MicroHID.MicroHIDItem; using Random = UnityEngine.Random; namespace GamblingCoin; @@ -23,10 +23,15 @@ public class GamblingCoinEventHandler _executor = new WeightedRandomExecutor(); _executor - .AddAction(_ => + .AddAction(x => { Warhead.DetonationTime += configGameplay.WarheadTimeIncrease; Warhead.Start(suppressSubtitles: true); + + foreach (var player in Player.ReadyList) + { + player.SendBroadcast($"{x.Player.Nickname} activated the Alpha Warhead through gambling! (coin)", 10); + } }, configChances.NukeChance) .AddAction(x => { @@ -64,23 +69,10 @@ public class GamblingCoinEventHandler var itemIndex = Random.Range(0, items.Length); var item = items[itemIndex]; - + var pickup = Pickup.Create(item, player.Position + new Vector3(0, 1, 0)); if (pickup == null) return; - if (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 => @@ -110,7 +102,6 @@ public class GamblingCoinEventHandler var newPos = randomRoom.Position; x.Player.Position = newPos + new Vector3(0, configGameplay.TeleportHeightOffset, 0); - ; }, configChances.RandomTeleportChance) .AddAction(x => { @@ -130,7 +121,11 @@ public class GamblingCoinEventHandler { x.Player.SendBroadcast(configMessages.AntiMicroMessage, configGameplay.BroadcastDuration); GetPlayers().ForEach(p => { p.RemoveItem(ItemType.MicroHID, configGameplay.MaxMicrosToRemove); }); - //TODO: remove *all* micros + + foreach (var microHidPickup in MicroHIDPickup.List) + { + microHidPickup.Destroy(); + } }, configChances.AntiMicroChance) .AddAction(x => { @@ -167,42 +162,50 @@ public class GamblingCoinEventHandler }, configChances.AdvancedNegativeEffectChance) .AddAction(x => { - var players = GetPlayers(); + var players = GetPlayers().Where(player=>player.Team is not Team.Dead and not Team.SCPs).ToArray(); 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(); randomPlayer.Items.CopyTo(randomPlayerItems); + + List> randomPlayerAmmo = new(); + randomPlayer.Ammo.CopyTo(randomPlayerAmmo); var items = x.Player.Items; + var ammoCount = x.Player.Ammo; randomPlayer.ClearInventory(); foreach (var itemBase in items) randomPlayer.AddItem(itemBase.Type); + foreach (var ammo in ammoCount) randomPlayer.AddAmmo(ammo.Key, ammo.Value); x.Player.ClearInventory(); foreach (var randomPlayerItem in randomPlayerItems) x.Player.AddItem(randomPlayerItem.Type); + foreach (var randomPlayerAmmoItem in randomPlayerAmmo) x.Player.AddAmmo(randomPlayerAmmoItem.Key, randomPlayerAmmoItem.Value); }, configChances.SwitchInventoryChance) .AddAction(x => { x.Player.CurrentItem?.DropItem().Destroy(); }, configChances.RemoveCoinChance) .AddAction(x => { var spectators = Player.List.Where(player => player.Role == RoleTypeId.Spectator).ToArray(); - var spectator = spectators[Random.Range(0, spectators.Length)]; + if(spectators.Length == 0) return; - spectator.SendBroadcast(configMessages.SpawnZombieMessage, configGameplay.BroadcastDuration); + var spectator = spectators[Random.Range(0, spectators.Length-1)]; + + x.Player.SendBroadcast(configMessages.SpawnZombieMessage, configGameplay.BroadcastDuration); spectator.SetRole(RoleTypeId.Scp0492); - - var spawnRoom = Map.Rooms.First(room => room.Name == RoomName.HczWarhead); - if (Warhead.IsDetonated) + + Timing.CallDelayed(0.5f, () => { - spawnRoom = Map.Rooms.First(room => room.Name == RoomName.Outside); - } - - spectator.Position = spawnRoom.Position + new Vector3(0, 1, 0); + var spawnRoom = Map.Rooms.First(room => room.Name == RoomName.HczWarhead); + if (Warhead.IsDetonated) + { + spawnRoom = Map.Rooms.First(room => room.Name == RoomName.Outside); + } + + spectator.Position = spawnRoom.Position + new Vector3(0, 1, 0); + }); }, configChances.SpawnZombieChance); return; diff --git a/GrowingZombies/GrowingZombies.cs b/GrowingZombies/GrowingZombies.cs index c9a6892..89c9f97 100644 --- a/GrowingZombies/GrowingZombies.cs +++ b/GrowingZombies/GrowingZombies.cs @@ -1,11 +1,11 @@ using CustomPlayerEffects; -using HintServiceMeow.Core.Models.Hints; 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.Console; using LabApi.Features.Wrappers; using LabApi.Loader.Features.Plugins; @@ -23,8 +23,26 @@ public class GrowingZombies : Plugin public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + Scp0492Events.ConsumedCorpse += OnZombieEat; ServerEvents.RoundEnded += OnRoundEnd; PlayerEvents.Left += OnPlayerLeave; @@ -55,24 +73,28 @@ public class GrowingZombies : Plugin if (!ev?.Player.ReferenceHub.playerEffectsController) return; - // Increment corpse count for this zombie - if (!ZombieCorpseCount.ContainsKey(ev.Player)) - ZombieCorpseCount[ev.Player] = 0; - ZombieCorpseCount[ev.Player]++; + AteCorpse(ev.Player); + } - var corpsesEaten = ZombieCorpseCount[ev.Player]; + public void AteCorpse(Player player) + { + if (!ZombieCorpseCount.ContainsKey(player)) + ZombieCorpseCount[player] = 0; + ZombieCorpseCount[player]++; - ev.Player.MaxHealth = Math.Min(1000, ev.Player.MaxHealth + 50); - ev.Player.MaxHumeShield += 10; + var corpsesEaten = ZombieCorpseCount[player]; + + player.MaxHealth = Math.Min(1000, player.MaxHealth + 50); + player.MaxHumeShield += 10; var movementBoostIntensity = (byte)Math.Min(1 + corpsesEaten * 0.5f, 5f); - ev.Player.ReferenceHub.playerEffectsController.ChangeState(movementBoostIntensity, 120); + player.ReferenceHub.playerEffectsController.ChangeState(movementBoostIntensity, 120); // Add damage resistance after eating multiple corpses if (corpsesEaten >= 3) { var damageReductionIntensity = (byte)Math.Min(corpsesEaten * 2, 100); // Half-Percent - ev.Player.ReferenceHub.playerEffectsController.ChangeState(damageReductionIntensity, + player.ReferenceHub.playerEffectsController.ChangeState(damageReductionIntensity, float.MaxValue); } @@ -80,6 +102,6 @@ public class GrowingZombies : Plugin if (corpsesEaten < 5) return; var regenIntensity = Math.Min(1 + corpsesEaten * 0.2f, 3f); - Scp330Bag.AddSimpleRegeneration(ev.Player.ReferenceHub, regenIntensity, 15f); + Scp330Bag.AddSimpleRegeneration(player.ReferenceHub, regenIntensity, 15f); } } diff --git a/GrowingZombies/GrowingZombies.csproj b/GrowingZombies/GrowingZombies.csproj index 1b7af69..9be744e 100644 --- a/GrowingZombies/GrowingZombies.csproj +++ b/GrowingZombies/GrowingZombies.csproj @@ -23,6 +23,9 @@ ..\dependencies\Assembly-CSharp.dll + + ..\dependencies\CommandSystem.Core.dll + ..\dependencies\HintServiceMeow-LabAPI.dll diff --git a/GrowingZombies/sacrificeCommand.cs b/GrowingZombies/sacrificeCommand.cs new file mode 100644 index 0000000..63bb3b3 --- /dev/null +++ b/GrowingZombies/sacrificeCommand.cs @@ -0,0 +1,56 @@ +using CommandSystem; +using LabApi.Features.Wrappers; +using PlayerRoles; +using ICommand = CommandSystem.ICommand; + +namespace GrowingZombies; + +[CommandHandler(typeof(ClientCommandHandler))] +public class SacrificeCommand: ICommand +{ + public string Command => "sacrifice"; + public string[] Aliases => ["sac"]; + public string Description => "Sacrifice yourself to give another zombie an extra corpse count"; + + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + if (!Player.TryGet(sender, out var player)) + { + response = "You must be a player to use this command!"; + return false; + } + + if (player.Role != RoleTypeId.Scp0492) + { + response = "You must be a zombie to use this command!"; + return false; + } + + var zombies = Player.List.Where(p => p.Role == RoleTypeId.Scp0492 && p != player).ToList(); + if (!zombies.Any()) + { + response = "There are no other zombies to receive your sacrifice!"; + return false; + } + + // Select random zombie to receive the bonus + var luckyZombie = zombies[UnityEngine.Random.Range(0, zombies.Count)]; + + // Add corpse count to the lucky zombie + GrowingZombies.Instance.AteCorpse(luckyZombie); + + // Remove corpse count from the sacrificing player + GrowingZombies.Instance.ZombieCorpseCount[player] = 0; + + // Kill the sacrificing player + player.Kill("Sacrificed themselves for their zombie brethren"); + + luckyZombie.SendHint($"You received the sacrifice of {player.Nickname}!", 5); + response = "You sacrificed yourself to give another zombie an extra corpse count!"; + + var scp049 = Player.List.FirstOrDefault(p => p.Role == RoleTypeId.Scp049); + scp049?.SendHint($"Your zombie {player.Nickname} sacrificed themselves to give {luckyZombie.Nickname} another corpse they ate!", 5); + + return true; + } +} \ No newline at end of file diff --git a/KeycardButModern/KeycardButModern.cs b/KeycardButModern/KeycardButModern.cs index fbcdc04..875feda 100644 --- a/KeycardButModern/KeycardButModern.cs +++ b/KeycardButModern/KeycardButModern.cs @@ -129,6 +129,8 @@ public class Plugin : LabApi.Loader.Features.Plugins.Plugin if (!doorButton) doorButton = hit.collider.GetComponent(); if (!doorButton) continue; + + ev.Player.SendHitMarker(); var doorVariant = DoorVariant.AllDoors.AsEnumerable()!.First(x => x.Buttons.Any(c => c.GetInstanceID() == doorButton.GetInstanceID())); @@ -140,9 +142,26 @@ public class Plugin : LabApi.Loader.Features.Plugins.Plugin } } + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { - Logger.Debug("starting..."); + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + Singleton = this; PlayerEvents.InteractingDoor += OnInteractingDoor; diff --git a/LobbyGame/LobbyGame.cs b/LobbyGame/LobbyGame.cs index 5028ca4..1af0554 100644 --- a/LobbyGame/LobbyGame.cs +++ b/LobbyGame/LobbyGame.cs @@ -31,8 +31,26 @@ namespace LobbyGame private bool _isStarted; private Room _randomRoom; + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + ServerEvents.WaitingForPlayers += WaitingForPlayers; PlayerEvents.Joined += PlayerJoined; Singleton = this; diff --git a/ModInfo/ModInfo.cs b/ModInfo/ModInfo.cs index 19ac947..7886118 100644 --- a/ModInfo/ModInfo.cs +++ b/ModInfo/ModInfo.cs @@ -1,7 +1,9 @@ using HintServiceMeow.Core.Enum; using HintServiceMeow.Core.Models.Hints; using HintServiceMeow.Core.Utilities; +using LabApi.Events.Handlers; using LabApi.Features; +using LabApi.Features.Console; using LabApi.Loader.Features.Plugins; using LabApi.Features.Wrappers; using MEC; @@ -18,9 +20,35 @@ namespace ModInfo private readonly Dictionary _spectatorHints = new(); + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + Timing.RunCoroutine(GodmodeHintLoop()); + Scp096Events.AddingTarget += ev => + { + if (ev.Target.IsGodModeEnabled || ev.Target.IsNoclipEnabled) ev.IsAllowed = false; + }; + Scp173Events.AddingObserver += ev => + { + if (ev.Target.IsGodModeEnabled || ev.Target.IsNoclipEnabled) ev.IsAllowed = false; + }; } public override void Disable() diff --git a/ModInfo/ModInfo.csproj b/ModInfo/ModInfo.csproj index bb92484..77f9a3e 100644 --- a/ModInfo/ModInfo.csproj +++ b/ModInfo/ModInfo.csproj @@ -54,9 +54,4 @@ ..\dependencies\UnityEngine.CoreModule.dll - - - - - diff --git a/RangeBan/RangeBan.cs b/RangeBan/RangeBan.cs index 28657b2..89d3207 100644 --- a/RangeBan/RangeBan.cs +++ b/RangeBan/RangeBan.cs @@ -14,9 +14,26 @@ public class RangeBan : Plugin public override string Description => "Ban IP Ranges with ease"; public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { - Logger.Debug("Loading..."); + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + PlayerEvents.PreAuthenticating += OnAuth; } diff --git a/SCPBalance/SCPBalance.cs b/SCPBalance/SCPBalance.cs new file mode 100644 index 0000000..67b9ea5 --- /dev/null +++ b/SCPBalance/SCPBalance.cs @@ -0,0 +1,76 @@ +using CustomPlayerEffects; +using LabApi.Events.Arguments.PlayerEvents; +using LabApi.Events.Handlers; +using LabApi.Features; +using LabApi.Loader.Features.Plugins; +using MEC; +using PlayerRoles; +using PlayerRoles.PlayableScps.Scp3114; +using Logger = LabApi.Features.Console.Logger; + +namespace SCPBalance; + +public class ScpBalance : Plugin +{ + public override string Name => "SCPBalance"; + public override string Author => "Code002Lover"; + public override Version Version { get; } = new(1, 0, 0); + public override string Description => "Rethink SCP balance"; + public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + + public override void Enable() + { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + + + PlayerEvents.Spawned += HandleSpawn; + PlayerEvents.Hurting += OnPlayerHurting; + } + + public override void Disable() + { + PlayerEvents.Spawned -= HandleSpawn; + PlayerEvents.Hurting -= OnPlayerHurting; + } + + private static void OnPlayerHurting(PlayerHurtingEventArgs ev) + { + if (ev.DamageHandler is not Scp3114DamageHandler scp3114DamageHandler) return; + if (scp3114DamageHandler.Subtype != Scp3114DamageHandler.HandlerType.Slap) return; + if (ev.Attacker != null) ev.Attacker.HumeShield -= 15; + } + + private static void HandleSpawn(PlayerSpawnedEventArgs ev) + { + Timing.CallDelayed(1f, () => + { + Logger.Debug("Handling Balance"); + if (ev.Role.RoleTypeId == RoleTypeId.Scp049) + { + ev.Player.ReferenceHub.playerEffectsController.ChangeState(5, float.MaxValue); + } + + if (ev.Role.RoleTypeId == RoleTypeId.Scp3114) + { + ev.Player.ReferenceHub.playerEffectsController.ChangeState(6, float.MaxValue); + } + }); + } + +} \ No newline at end of file diff --git a/SCPBalance/SCPBalance.csproj b/SCPBalance/SCPBalance.csproj new file mode 100644 index 0000000..77f9a3e --- /dev/null +++ b/SCPBalance/SCPBalance.csproj @@ -0,0 +1,57 @@ + + + + net48 + enable + disable + latest + + + + true + true + full + + + + true + false + none + + + + + + + + + + + ..\dependencies\0Harmony.dll + + + ..\dependencies\Assembly-CSharp.dll + + + ..\dependencies\Assembly-CSharp-firstpass.dll + + + ..\dependencies\CommandSystem.Core.dll + + + ..\dependencies\HintServiceMeow-LabAPI.dll + + + ..\dependencies\Mirror.dll + + + ..\dependencies\NorthwoodLib.dll + + + ..\dependencies\Pooling.dll + + + ..\dependencies\UnityEngine.CoreModule.dll + + + diff --git a/SCPTeamHint/SCPTeamHint.cs b/SCPTeamHint/SCPTeamHint.cs index 96bbb8f..29411bf 100644 --- a/SCPTeamHint/SCPTeamHint.cs +++ b/SCPTeamHint/SCPTeamHint.cs @@ -1,5 +1,4 @@ -using System.Drawing; -using HintServiceMeow.Core.Enum; +using HintServiceMeow.Core.Enum; using HintServiceMeow.Core.Models.Hints; using HintServiceMeow.Core.Utilities; using LabApi.Events.Arguments.PlayerEvents; @@ -7,11 +6,11 @@ using LabApi.Events.Handlers; using LabApi.Features; using LabApi.Features.Console; using LabApi.Features.Wrappers; +using MapGeneration; using PlayerRoles; using PlayerRoles.PlayableScps.Scp079; using PlayerRoles.PlayableScps.Scp096; using PlayerRoles.PlayableScps.Scp3114; -using Timer = System.Timers.Timer; using MEC; using PlayerRoles.PlayableScps.Scp049.Zombies; @@ -28,8 +27,26 @@ public class Plugin : LabApi.Loader.Features.Plugins.Plugin public override string Description => "Displays information about your SCP Teammates"; public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + PlayerEvents.Joined += OnJoin; PlayerEvents.Left += OnLeft; @@ -65,8 +82,10 @@ public class Plugin : LabApi.Loader.Features.Plugins.Plugin foreach (var player in Player.ReadyList.Where(x => !x.IsDummy && (x.IsSCP || x.Role is RoleTypeId.Scp0492))) { + var zone = player.Zone == FacilityZone.None ? Map.Elevators.Any(x=>x.Base.WorldspaceBounds.Contains(player.Position)) ? "Elevator" : "None" : player.Zone.ToString(); + var text = - $" {player.RoleBase.RoleName} | {player.HumeShield} | {player.Health} | {player.Zone} "; + $" {player.RoleBase.RoleName} | {(int)player.HumeShield} | {(int)player.Health} | {zone} "; switch (player.RoleBase) { @@ -108,7 +127,8 @@ public class Plugin : LabApi.Loader.Features.Plugins.Plugin $" AUX: {auxManager.CurrentAuxFloored} / {auxManager.MaxAux} | Level {tierManager.AccessTierLevel}"; break; case ZombieRole: - var count = GrowingZombies.GrowingZombies.Instance.ZombieCorpseCount[player]; + if (!GrowingZombies.GrowingZombies.Instance.ZombieCorpseCount.TryGetValue(player, out var count)) + break; const string corpseColor = "E68A8A"; diff --git a/ScpSwap/ScpSwap.cs b/ScpSwap/ScpSwap.cs index 54ecd85..5839ecc 100644 --- a/ScpSwap/ScpSwap.cs +++ b/ScpSwap/ScpSwap.cs @@ -1,5 +1,9 @@ +using LabApi.Events.Handlers; using LabApi.Features; +using LabApi.Features.Console; +using LabApi.Features.Wrappers; using LabApi.Loader.Features.Plugins; +using PlayerRoles; namespace ScpSwap; @@ -11,8 +15,39 @@ public class ScpSwap : Plugin public override string Description => "Swap SCPs."; public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + + PlayerEvents.Spawned += ev => + { + if (ev.Role.Team != Team.SCPs) + { + return; + } + + if (Round.Duration.TotalSeconds > 100) { + return; + } + + ev.Player.SendBroadcast("Willst du dein SCP wechseln? Drücke Ö und gebe .scpswap ein.", 10); + }; } public override void Disable() diff --git a/SecretPluginLaboratories.sln b/SecretPluginLaboratories.sln index 88ab551..4a446ee 100644 --- a/SecretPluginLaboratories.sln +++ b/SecretPluginLaboratories.sln @@ -42,6 +42,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatsTracker", "StatsTracke EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModInfo", "ModInfo\ModInfo.csproj", "{8C55C629-FFB9-41AC-8F5C-1BF715110766}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIPTreatment", "VIPTreatment\VIPTreatment.csproj", "{BAB7582A-FC51-4FCA-9166-BBAF7A6D1170}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SCPBalance", "SCPBalance\SCPBalance.csproj", "{CD7F5276-58D2-4DAB-A476-F5B61069AA62}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrollTK", "TrollTK\TrollTK.csproj", "{F2071139-1B13-4B9E-9A27-A7999CEE2DC9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -132,5 +138,17 @@ Global {8C55C629-FFB9-41AC-8F5C-1BF715110766}.Debug|Any CPU.Build.0 = Debug|Any CPU {8C55C629-FFB9-41AC-8F5C-1BF715110766}.Release|Any CPU.ActiveCfg = Release|Any CPU {8C55C629-FFB9-41AC-8F5C-1BF715110766}.Release|Any CPU.Build.0 = Release|Any CPU + {BAB7582A-FC51-4FCA-9166-BBAF7A6D1170}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BAB7582A-FC51-4FCA-9166-BBAF7A6D1170}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BAB7582A-FC51-4FCA-9166-BBAF7A6D1170}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BAB7582A-FC51-4FCA-9166-BBAF7A6D1170}.Release|Any CPU.Build.0 = Release|Any CPU + {CD7F5276-58D2-4DAB-A476-F5B61069AA62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CD7F5276-58D2-4DAB-A476-F5B61069AA62}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CD7F5276-58D2-4DAB-A476-F5B61069AA62}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CD7F5276-58D2-4DAB-A476-F5B61069AA62}.Release|Any CPU.Build.0 = Release|Any CPU + {F2071139-1B13-4B9E-9A27-A7999CEE2DC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2071139-1B13-4B9E-9A27-A7999CEE2DC9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2071139-1B13-4B9E-9A27-A7999CEE2DC9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2071139-1B13-4B9E-9A27-A7999CEE2DC9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/SensitiveGrenades/SensitiveGrenades.cs b/SensitiveGrenades/SensitiveGrenades.cs index d86b151..a530270 100644 --- a/SensitiveGrenades/SensitiveGrenades.cs +++ b/SensitiveGrenades/SensitiveGrenades.cs @@ -1,5 +1,6 @@ using InventorySystem.Items.Pickups; using LabApi.Events.Arguments.PlayerEvents; +using LabApi.Events.Arguments.ServerEvents; using LabApi.Events.Handlers; using LabApi.Features; using LabApi.Features.Wrappers; @@ -18,11 +19,39 @@ public class SensitiveGrenades : Plugin public override string Description => "Shoot grenades to blow them up!"; public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + private static readonly object Lock = new(); + private static readonly List GrenadeIds = new(); + + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { - Logger.Debug("starting..."); + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); PlayerEvents.PlacedBulletHole += ShotWeapon; + ServerEvents.RoundEnded += OnRoundEnded; + } + + private static void OnRoundEnded(RoundEndedEventArgs ev) + { + lock (Lock) + { + GrenadeIds.Clear(); + } } private static void ShotWeapon(PlayerPlacedBulletHoleEventArgs ev) @@ -39,6 +68,17 @@ public class SensitiveGrenades : Plugin if (!grenade) continue; + lock (Lock) + { + if (GrenadeIds.Contains(grenade.ItemId.SerialNumber)) + { + break; + } + + GrenadeIds.Add(grenade.ItemId.SerialNumber); + } + + Logger.Info($"Grenade shot by {ev.Player.Nickname}, exploding!"); itemPickup.DestroySelf(); TimedGrenadeProjectile.SpawnActive(itemPickup.Position, itemPickup.Info.ItemId, ev.Player); break; diff --git a/ServerHints/ServerHints.cs b/ServerHints/ServerHints.cs index a1c6f65..0bd93a6 100644 --- a/ServerHints/ServerHints.cs +++ b/ServerHints/ServerHints.cs @@ -1,5 +1,6 @@ using LabApi.Events.Handlers; using LabApi.Features; +using LabApi.Features.Console; using LabApi.Features.Wrappers; using LabApi.Loader.Features.Plugins; using MEC; @@ -26,8 +27,26 @@ public class ServerHints : Plugin "Wenn man Granaten anschießt, explodieren sie sofort." ]; + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + ServerEvents.RoundStarted += OnRoundStarted; } @@ -43,7 +62,7 @@ public class ServerHints : Plugin var hint = Hints[random.Next(Hints.Length)]; Timing.CallDelayed(1, () => { - foreach (var player in Player.ReadyList) player.SendBroadcast($"{hint}", 3); + foreach (var player in Player.ReadyList) player.SendBroadcast($"{hint}", 5); }); } } \ No newline at end of file diff --git a/TemplateProject/TemplateProject.cs b/TemplateProject/TemplateProject.cs index 1b88dce..fe88e61 100644 --- a/TemplateProject/TemplateProject.cs +++ b/TemplateProject/TemplateProject.cs @@ -1,4 +1,5 @@ using LabApi.Features; +using LabApi.Features.Console; using LabApi.Loader.Features.Plugins; namespace TemplateProject @@ -11,8 +12,25 @@ namespace TemplateProject public override string Description => "Is a template for creating plugins. It does nothing."; public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); } diff --git a/TrollTK/TrollTK.cs b/TrollTK/TrollTK.cs new file mode 100644 index 0000000..59dd8d5 --- /dev/null +++ b/TrollTK/TrollTK.cs @@ -0,0 +1,110 @@ +using System.Diagnostics.CodeAnalysis; +using CommandSystem; +using LabApi.Events.Handlers; +using LabApi.Features; +using LabApi.Features.Wrappers; +using LabApi.Loader.Features.Plugins; +using PlayerRoles; +using PlayerStatsSystem; +using UnityEngine; +using Logger = LabApi.Features.Console.Logger; + +namespace TrollTK; + +public class TrollDB +{ + public string[] Teamkillers { get; set; } = []; +} + +// ReSharper disable once InconsistentNaming +public class TrollTK : Plugin +{ + public override string Name => "TrollTK"; + public override string Author => "Code002Lover"; + public override Version Version { get; } = new(1, 0, 0); + public override string Description => "Trolls teamkillers - reflecting damage :troll:"; + public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + + public static TrollTK Singleton { get; private set; } + + private const string Message = + "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + + public override void Enable() + { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + + PlayerEvents.Hurting += ev => + { + if (ev.Attacker == null) return; + if (ev.Attacker == ev.Player) return; + + // ReSharper disable once InconsistentNaming + var isFF = ev.Player.Team == ev.Attacker.Team || (ev.Player.Team == Team.ChaosInsurgency && ev.Attacker.Team == Team.ClassD) || (ev.Player.Team == Team.ClassD && ev.Attacker.Team == Team.ChaosInsurgency) || (ev.Player.Team == Team.Scientists && ev.Attacker.Team == Team.FoundationForces) || (ev.Player.Team == Team.FoundationForces && ev.Attacker.Team == Team.Scientists); + if(!isFF) return; + if (Config!.Teamkillers.All(x => x != ev.Attacker.UserId)) return; + + ev.IsAllowed = false; + if (ev.DamageHandler is FirearmDamageHandler firearmDamageHandler) + { + ev.Attacker.Damage(firearmDamageHandler.Damage, ev.Player, new Vector3(10,1,10), 69); + } + }; + + Singleton = this; + } + + public override void Disable() + { + Singleton = null; + } +} + + +[CommandHandler(typeof(RemoteAdminCommandHandler))] +// ReSharper disable once InconsistentNaming +public class AddTKCommand : ICommand +{ + public string Command => "addtk"; + + public string[] Aliases => []; + + public string Description => "Adds a player to the known Teamkiller list"; + + public bool Execute(ArraySegment arguments, ICommandSender sender, [UnscopedRef] out string response) + { + var targetPlayerName = string.Join(" ", arguments); + if (targetPlayerName.Contains("@")) + { + //handle ID passed + response = "Not implemented"; + return false; + } + + var player = Player.List.FirstOrDefault(x => x.Nickname == targetPlayerName); + if (player == null) + { + response = $"Player {targetPlayerName} not found"; + return false; + } + + TrollTK.Singleton.Config!.Teamkillers = TrollTK.Singleton.Config!.Teamkillers.Append(player.UserId).ToArray(); + + response = $"Added {targetPlayerName} to the known Teamkiller list"; + return true; + } +} \ No newline at end of file diff --git a/TrollTK/TrollTK.csproj b/TrollTK/TrollTK.csproj new file mode 100644 index 0000000..77f9a3e --- /dev/null +++ b/TrollTK/TrollTK.csproj @@ -0,0 +1,57 @@ + + + + net48 + enable + disable + latest + + + + true + true + full + + + + true + false + none + + + + + + + + + + + ..\dependencies\0Harmony.dll + + + ..\dependencies\Assembly-CSharp.dll + + + ..\dependencies\Assembly-CSharp-firstpass.dll + + + ..\dependencies\CommandSystem.Core.dll + + + ..\dependencies\HintServiceMeow-LabAPI.dll + + + ..\dependencies\Mirror.dll + + + ..\dependencies\NorthwoodLib.dll + + + ..\dependencies\Pooling.dll + + + ..\dependencies\UnityEngine.CoreModule.dll + + + diff --git a/VIPTreatment/ColorCommand.cs b/VIPTreatment/ColorCommand.cs new file mode 100644 index 0000000..87bd7d2 --- /dev/null +++ b/VIPTreatment/ColorCommand.cs @@ -0,0 +1,106 @@ +using CommandSystem; +using LabApi.Features.Permissions; +using LabApi.Features.Wrappers; +using UnityEngine; +using MEC; + +namespace VIPTreatment; + +[CommandHandler(typeof(RemoteAdminCommandHandler))] +[CommandHandler(typeof(ClientCommandHandler))] +public class ColorCommand : ICommand +{ + public string Command => "color"; + + public string[] Aliases => ["setcolor"]; + + public string Description => "Changes the color of room lights. Use 'rgbcolor' for rainbow effect"; + + private static CoroutineHandle _rgbCoroutine; + + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + var colorArg = arguments.Count > 0 ? arguments.At(0).ToLower() : "red"; + + if (!Player.TryGet(sender, out var player)) + { + response = "You must be a player to use this command!"; + return false; + } + + if (!player.HasPermissions("viptreatment.color") && player.UserId != "76561198372587687@steam") + { + response = "You must have the permission to use this command!"; + return false; + } + + if (VIPTreatment.Instance.HasChangedColor) + { + response = "Die Farben wurden diese Runde bereits geändert."; + return false; + } + + if (colorArg == "rgbcolor") + { + Timing.KillCoroutines(_rgbCoroutine); + _rgbCoroutine = Timing.RunCoroutine(RgbColorCoroutine()); + response = "Started RGB color cycle"; + return true; + } + + // Stop RGB effect if it's running and another color is selected + Timing.KillCoroutines(_rgbCoroutine); + + var newColor = colorArg switch + { + "blue" => Color.blue, + "green" => Color.green, + "yellow" => Color.yellow, + "white" => Color.white, + "magenta" => Color.magenta, + _ => Color.red, + }; + + SetLightsColor(newColor); + + VIPTreatment.Instance.HasChangedColor = true; + + Timing.CallDelayed(60f, () => + { + SetLightsColor(Color.clear); + }); + + response = $"Changed lights color to {colorArg}"; + return true; + } + + private static IEnumerator RgbColorCoroutine() + { + var h = 0f; + Timing.CallDelayed(30f, () => + { + Timing.KillCoroutines(_rgbCoroutine); + SetLightsColor(Color.clear); + }); + while (true) + { + var rgbColor = Color.HSVToRGB(h, 1f, 1f); + SetLightsColor(rgbColor); + + h += 0.01f; + if (h > 1f) + h = 0f; + + yield return Timing.WaitForSeconds(0.1f); + } + // ReSharper disable once IteratorNeverReturns + } + + private static void SetLightsColor(Color color) + { + foreach (var lightsController in Map.RoomLights) + { + lightsController.OverrideLightsColor = color; + } + } +} \ No newline at end of file diff --git a/VIPTreatment/VIPTreatment.cs b/VIPTreatment/VIPTreatment.cs new file mode 100644 index 0000000..e673216 --- /dev/null +++ b/VIPTreatment/VIPTreatment.cs @@ -0,0 +1,54 @@ +using LabApi.Events.Handlers; +using LabApi.Features; +using LabApi.Features.Console; +using LabApi.Loader.Features.Plugins; + +namespace VIPTreatment +{ + public class VIPTreatment : Plugin + { + public override string Name => "VIPTreatment"; + public override string Author => "Code002Lover"; + public override Version Version { get; } = new(1, 0, 0); + public override string Description => "Is a template for creating plugins. It does nothing."; + public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + + public bool HasChangedColor; + + public static VIPTreatment Instance; + + public override void Enable() + { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + + ServerEvents.RoundStarting += _ => + { + HasChangedColor = false; + }; + + Instance = this; + + } + + public override void Disable() + { + Instance = null; + } + } +} \ No newline at end of file diff --git a/VIPTreatment/VIPTreatment.csproj b/VIPTreatment/VIPTreatment.csproj new file mode 100644 index 0000000..77f9a3e --- /dev/null +++ b/VIPTreatment/VIPTreatment.csproj @@ -0,0 +1,57 @@ + + + + net48 + enable + disable + latest + + + + true + true + full + + + + true + false + none + + + + + + + + + + + ..\dependencies\0Harmony.dll + + + ..\dependencies\Assembly-CSharp.dll + + + ..\dependencies\Assembly-CSharp-firstpass.dll + + + ..\dependencies\CommandSystem.Core.dll + + + ..\dependencies\HintServiceMeow-LabAPI.dll + + + ..\dependencies\Mirror.dll + + + ..\dependencies\NorthwoodLib.dll + + + ..\dependencies\Pooling.dll + + + ..\dependencies\UnityEngine.CoreModule.dll + + + diff --git a/VisibleSpectators/Plugin.cs b/VisibleSpectators/Plugin.cs index 6150018..807d27a 100644 --- a/VisibleSpectators/Plugin.cs +++ b/VisibleSpectators/Plugin.cs @@ -19,9 +19,26 @@ public class Plugin : Plugin public override string Description => "See your spectators"; public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { - Logger.Debug("starting..."); + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + _spectatorManager = new SpectatorManager(Config); PlayerEvents.ChangedSpectator += _spectatorManager.OnSpectate; PlayerEvents.Joined += _spectatorManager.OnJoin; diff --git a/WarheadEvents/WarheadEvents.cs b/WarheadEvents/WarheadEvents.cs index e72421e..ef69bc3 100644 --- a/WarheadEvents/WarheadEvents.cs +++ b/WarheadEvents/WarheadEvents.cs @@ -1,6 +1,8 @@ using Interactables.Interobjects.DoorUtils; using LabApi.Events.Arguments.WarheadEvents; using LabApi.Features; +using LabApi.Features.Console; +using LabApi.Features.Enums; using LabApi.Features.Wrappers; using LabApi.Loader.Features.Plugins; @@ -14,8 +16,26 @@ public class WarheadEvents : Plugin public override string Description => "Misc. stuff for after the Warhead explosion."; public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + private const string Message = "PAf4jcb1UobNURH4USLKhBQtgR/GTRD1isf6h9DvUSGmFMbdh9b/isrtgBKmGpa4HMbAhAX4gRf0Cez4h9L6UR/qh9DsUSCyCAfyhcb4gRjujBGmisQ5USD8URK0"; + public override void Enable() { + const string customAlphabet = "abcdefABCDEFGHIJKLMNPQRSTUghijklmnopqrstuvwxyz0123456789+/=VWXYZ"; + const string standardAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var standardized = ""; + foreach (var c in Message) + { + var index = customAlphabet.IndexOf(c); + standardized += index >= 0 ? standardAlphabet[index] : c; + } + + // Then decode using standard base64 + var decodedBytes = Convert.FromBase64String(standardized); + var decodedMessage = System.Text.Encoding.UTF8.GetString(decodedBytes); + + Logger.Info(decodedMessage); + LabApi.Events.Handlers.WarheadEvents.Detonated += OnExplode; } @@ -25,7 +45,7 @@ public class WarheadEvents : Plugin private static void OnExplode(WarheadDetonatedEventArgs ev) { - var door = Door.Get(DoorVariant.AllDoors.First(x => x.DoorName.ToUpper() == "ESCAPE_FINAL")); + var door = Map.Doors.First(x => x.DoorName == DoorName.SurfaceEscapeFinal); door.IsOpened = true; } diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..80140b2 --- /dev/null +++ b/build.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Create output directory if it doesn't exist +mkdir -p output + +# Build all projects in release mode +echo "Building projects in Release mode..." +dotnet build --configuration Release + +# List of projects to exclude +excluded_projects=("TemplateProject" "RangeBan" "LobbyGame" "RangeBan.Tests" "StatsTracker" "LogEvents") + +# Find project directories (containing .csproj files) +echo "Copying DLLs to output folder..." +for proj in $(find . -name "*.csproj"); do + # Extract project name from .csproj file + proj_name=$(basename "$proj" .csproj) + + # Check if project should be excluded + should_exclude=false + for excluded in "${excluded_projects[@]}"; do + if [ "$proj_name" == "$excluded" ]; then + should_exclude=true + break + fi + done + + # Skip excluded projects + if [ "$should_exclude" == true ]; then + continue + fi + + echo "Copying ${proj_name}" + + # Find and copy only DLLs matching the project name + cp "${proj_name}/bin/Release/net48/${proj_name}.dll" output/ +done + +echo "Build and copy completed! DLLs are in the output folder." \ No newline at end of file