diff --git a/CustomClasses/BloodFueledManager.cs b/CustomClasses/BloodFueledManager.cs index ad7fd44..1921268 100644 --- a/CustomClasses/BloodFueledManager.cs +++ b/CustomClasses/BloodFueledManager.cs @@ -1,8 +1,11 @@ +using CustomPlayerEffects; +using InventorySystem.Items.Usables.Scp330; using LabApi.Events.Handlers; using LabApi.Features.Wrappers; using MEC; using PlayerRoles.FirstPersonControl; using PlayerRoles.PlayableScps.Scp939; +using static LabApi.Features.Wrappers.Server; using Logger = LabApi.Features.Console.Logger; using Random = System.Random; @@ -32,8 +35,6 @@ public class BloodFueledStaminaEffect : CustomPlayerEffect, IStaminaModifier public class BloodFueledManager { - private readonly CustomClasses _plugin; - public static bool IsBloodFueled(Player player) { try @@ -46,9 +47,8 @@ public class BloodFueledManager } } - public BloodFueledManager(CustomClasses plugin) + public BloodFueledManager() { - _plugin = plugin; PlayerEvents.Hurt += ev => { if (ev.DamageHandler is not Scp939DamageHandler damageHandler) return; @@ -56,6 +56,13 @@ public class BloodFueledManager if (attacker == null) return; if (!IsBloodFueled(attacker)) return; + var isAffectedByBloodCloud = Scp939AmnesticCloudInstance.ActiveInstances.Where(x=>x.Owner && x.Owner == ev.Attacker?.ReferenceHub).Any(x=>x.AffectedPlayers.Contains(ev.Player.ReferenceHub)); + + if (isAffectedByBloodCloud) + { + attacker.Heal(10); + attacker.StaminaRemaining += 0.1f; + } if (ev.Player.Health <= 0) { @@ -69,6 +76,34 @@ public class BloodFueledManager }; Timing.RunCoroutine(DrainBlood()); + + PlayerEvents.EnteringHazard += ev => + { + if (ev.Hazard is not AmnesticCloudHazard amnesticCloud) return; + if (amnesticCloud.Owner == null || !IsBloodFueled(amnesticCloud.Owner)) return; + + ev.Player.EnableEffect(1, float.PositiveInfinity); + }; + + PlayerEvents.StayingInHazard += ev => + { + if (ev.Hazard is not AmnesticCloudHazard amnesticCloud) return; + if (amnesticCloud.Owner == null || !IsBloodFueled(amnesticCloud.Owner)) return; + + foreach (var affectedPlayer in ev.AffectedPlayers) + { + // ReSharper disable once PossibleLossOfFraction + affectedPlayer.Heal(10 / MaxTps); + } + }; + + PlayerEvents.LeavingHazard += ev => + { + if (ev.Hazard is not AmnesticCloudHazard amnesticCloud) return; + if (amnesticCloud.Owner == null || !IsBloodFueled(amnesticCloud.Owner)) return; + + ev.Player.DisableEffect(); + }; } public static IEnumerator DrainBlood() @@ -99,8 +134,8 @@ public class BloodFueledHandler : CustomClassHandler { public override void HandleSpawn(Player player, CustomClassConfig config, Random random) { - player.SendBroadcast("You are the Blood Fueled!", CustomClasses.BroadcastDuration); - const string customInfo = "Blood Fueled"; + player.SendBroadcast("You are SCP-939-Blood Fueled \n Your stamina bar has been replaced by a blood meter. \n You refill it by damaging or killing Humans. \n Don't let it run out.", CustomClasses.BroadcastDuration); + const string customInfo = "Blood Fueled"; if (!Player.ValidateCustomInfo(customInfo, out var reason)) { Logger.Error($"Invalid custom info for Blood Fueled: {reason}"); diff --git a/CustomClasses/CustomClasses.cs b/CustomClasses/CustomClasses.cs index 521a32a..26b71f5 100644 --- a/CustomClasses/CustomClasses.cs +++ b/CustomClasses/CustomClasses.cs @@ -17,7 +17,6 @@ using LabApi.Loader.Features.Plugins; using MapGeneration; using MEC; using PlayerRoles; -using PlayerRoles.PlayableScps.Scp106; using Scp914.Processors; using UnityEngine; using Logger = LabApi.Features.Console.Logger; @@ -35,7 +34,7 @@ public sealed class CustomClasses : Plugin public readonly CustomClassManager ClassManager = new(); public SerpentsHandManager SerpentsHandManager; public NegromancerManager NegromancerManager; - public BloodFueledManager BloodFueledManager; + public BloodFueledManager BloodFueledManager = new(); /// public override string Name => "CustomClasses"; @@ -160,7 +159,6 @@ public sealed class CustomClasses : Plugin } NegromancerManager = new NegromancerManager(this); - BloodFueledManager = new BloodFueledManager(this); Instance = this; } @@ -223,8 +221,7 @@ public sealed class CustomClasses : Plugin { if (random.Next(0, 100) > SerpentsHandConfig.BaseChance + state.ExtraChance) { - state.SetSpawned(); - state.SetWillSpawn(); + SerpentsHandManager.SpawnSerpentWave(); ClassManager.TryHandleSpawn(spectator, ScoutConfig, typeof(ScoutConfig), () => { @@ -252,7 +249,7 @@ public sealed class CustomClasses : Plugin { 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."); @@ -370,7 +367,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 - 1), 0, (float)(_random.NextDouble() * 2 - 1)); + player.Position = position + new Vector3(0, 0.5f, 0) + new Vector3((float)(_random.NextDouble() * 2 - 1), 0, (float)(_random.NextDouble() * 2 - 1)); } /// diff --git a/CustomClasses/ExtendedClass.cs b/CustomClasses/ExtendedClass.cs new file mode 100644 index 0000000..e2970d0 --- /dev/null +++ b/CustomClasses/ExtendedClass.cs @@ -0,0 +1,8 @@ +using PlayerRoles; + +namespace CustomClasses; + +public abstract class ExtendedClass: PlayerRoleBase +{ + +} \ No newline at end of file diff --git a/CustomClasses/SerpentsHandManager.cs b/CustomClasses/SerpentsHandManager.cs index be3151a..76a98fd 100644 --- a/CustomClasses/SerpentsHandManager.cs +++ b/CustomClasses/SerpentsHandManager.cs @@ -1,3 +1,4 @@ +using AdminToys; using CommandSystem; using CustomPlayerEffects; using HintServiceMeow.Core.Enum; @@ -9,16 +10,29 @@ using LabApi.Events.Handlers; using LabApi.Features.Permissions; using LabApi.Features.Wrappers; using MEC; +using Mirror; using PlayerRoles; using UnityEngine; +using LightSourceToy = LabApi.Features.Wrappers.LightSourceToy; using Logger = LabApi.Features.Console.Logger; +using PrimitiveObjectToy = LabApi.Features.Wrappers.PrimitiveObjectToy; using Random = System.Random; namespace CustomClasses; public class SerpentsHandManager { - public static bool IsSerpentsHand(Player player) => player.CustomInfo.Contains("SerpentsHand"); + public static bool IsSerpentsHand(Player player) + { + try + { + return player.CustomInfo.Contains("SerpentsHand"); + } + catch + { + return false; + } + } private readonly CustomClasses _customClasses; public SerpentsHandManager(CustomClasses customClasses) @@ -114,8 +128,6 @@ public class SerpentsHandManager { yield return Timing.WaitForSeconds(1); - RoundSummary.singleton.ExtraTargets = Player.ReadyList.Count(IsSerpentsHand); - if (_customClasses.ClassManager.GetSpawnState(typeof(SerpentsHandConfig)) is not SerpentsHandState state) continue; foreach (var player in Player.ReadyList) @@ -138,20 +150,64 @@ public class SerpentsHandManager } // ReSharper disable once IteratorNeverReturns } + + public void SpawnSerpentWave() + { + var state = (SerpentsHandState)CustomClasses.Instance.ClassManager.GetSpawnState(typeof(SerpentsHandConfig)); + + var serpentsHandConfig = _customClasses.SerpentsHandConfig; + + state.SetSpawned(); + state.SetWillSpawn(); + + var possibleLocations = (Vector3[])serpentsHandConfig.SpawnLocations.Clone(); + + possibleLocations.ShuffleListSecure(); + + var spawnLocation = possibleLocations[0]; + + foreach (var possibleLocation in possibleLocations) + { + if (Player.ReadyList.Any(p => (p.Position - possibleLocation).SqrMagnitudeIgnoreY() < 400)) + { + continue; + } + + spawnLocation = possibleLocation; + break; + } + + state.SpawnLocation = spawnLocation; + + var light = LightSourceToy.Create(spawnLocation + new Vector3(0, 2, 0), Quaternion.identity); + light.Color = Color.blue; + light.Intensity = 3; + light.Range = 40; + + var spaceTimeHole = PrimitiveObjectToy.Create(spawnLocation + new Vector3(0, 2, 0), Quaternion.identity); + spaceTimeHole.Color = new Color(44.7f, 73.7f, 83.1f, 0.5f); + spaceTimeHole.Flags = PrimitiveFlags.Visible; + spaceTimeHole.Scale *= 2; + + Timing.CallDelayed(20, () => + { + spaceTimeHole.Destroy(); + light.Destroy(); + }); + } } public sealed record SerpentsHandState: SpawnState { - public bool HasSpawned => _hasSpawned || PanicDisable || Warhead.IsDetonated; + public bool HasSpawned => _hasSpawned || Warhead.IsDetonated; public float ExtraChance; public int Points; - public bool WillSpawn => _willSpawn && !PanicDisable && !Warhead.IsDetonated; + public bool WillSpawn => _willSpawn && !Warhead.IsDetonated; private bool _hasSpawned; private bool _willSpawn; - - public bool PanicDisable; - + public Vector3? SpawnLocation; + public override void Reset() { base.Reset(); @@ -159,6 +215,7 @@ public sealed record SerpentsHandState: SpawnState ExtraChance = 0f; Points = 0; _willSpawn = false; + SpawnLocation = null; } public void SetSpawned() @@ -183,8 +240,10 @@ public sealed class SerpentsHandConfig : CustomClassConfig 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 const float BaseChance = 90f; + + public readonly Vector3[] SpawnLocations = [new(0.22f, 300.96f, -0.31f), new(123.921f, 288.792f, 20.929f)]; } public class SerpentsHandHandler : SimpleAddItemHandler @@ -192,11 +251,13 @@ public class SerpentsHandHandler : SimpleAddItemHandler public override void HandleSpawn(Player player, CustomClassConfig config, Random random) { base.HandleSpawn(player, config, random); + + var spawnLocation = ((SerpentsHandState)CustomClasses.Instance.ClassManager.GetSpawnState( + typeof(SerpentsHandConfig))).SpawnLocation; + if (spawnLocation != + null) + CustomClasses.Instance.ClassManager.TeleportPlayerToAround(player, (Vector3)spawnLocation); - // 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); @@ -233,52 +294,37 @@ public class SerpentsHandHandler : SimpleAddItemHandler player.EnableEffect(20, 30); player.SendBroadcast("You're a Serpent's Hand member!", CustomClasses.BroadcastDuration); + + player.EnableEffect(1, 20f); } } - [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 class SpawnSerpentsCommand : ICommand { - public string Command => "panicdisableserpentshand"; + public string Command => "spsh"; public string[] Aliases => []; - public string Description => "Panic disable Serpents Hand."; + public string Description => "Makes sure serpents hand spawns"; public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) { - if (!Player.TryGet(sender, out var player)) + var executor = Player.Get(sender); + if (executor == null) { response = "You must be a player to use this command!"; return false; } - if (!player.HasPermissions("panicdisable.serpentshand") && player.UserId != "76561198372587687@steam") + if (!executor.HasPermissions("customclasses.setcustomclass")) { - response = "You must have the permission to use this command!"; + response = "You do not have permission to use this command!"; return false; } - var state = (SerpentsHandState)CustomClasses.Instance.ClassManager.GetSpawnState(typeof(SerpentsHandConfig)); - state.PanicDisable = true; + CustomClasses.Instance.SerpentsHandManager.SpawnSerpentWave(); - response = "Serpents Hand has been disabled."; + response = "success"; return true; } -} +} \ No newline at end of file diff --git a/build_deploy.sh b/build_deploy.sh new file mode 100755 index 0000000..71f7492 --- /dev/null +++ b/build_deploy.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +./build.sh +./deploy.sh