improve bloodfueled & serpents

This commit is contained in:
code002lover 2025-07-14 03:35:11 +02:00
parent f839619464
commit d53d71c6d9
5 changed files with 144 additions and 54 deletions

View File

@ -1,8 +1,11 @@
using CustomPlayerEffects;
using InventorySystem.Items.Usables.Scp330;
using LabApi.Events.Handlers; using LabApi.Events.Handlers;
using LabApi.Features.Wrappers; using LabApi.Features.Wrappers;
using MEC; using MEC;
using PlayerRoles.FirstPersonControl; using PlayerRoles.FirstPersonControl;
using PlayerRoles.PlayableScps.Scp939; using PlayerRoles.PlayableScps.Scp939;
using static LabApi.Features.Wrappers.Server;
using Logger = LabApi.Features.Console.Logger; using Logger = LabApi.Features.Console.Logger;
using Random = System.Random; using Random = System.Random;
@ -32,8 +35,6 @@ public class BloodFueledStaminaEffect : CustomPlayerEffect, IStaminaModifier
public class BloodFueledManager public class BloodFueledManager
{ {
private readonly CustomClasses _plugin;
public static bool IsBloodFueled(Player player) public static bool IsBloodFueled(Player player)
{ {
try try
@ -46,9 +47,8 @@ public class BloodFueledManager
} }
} }
public BloodFueledManager(CustomClasses plugin) public BloodFueledManager()
{ {
_plugin = plugin;
PlayerEvents.Hurt += ev => PlayerEvents.Hurt += ev =>
{ {
if (ev.DamageHandler is not Scp939DamageHandler damageHandler) return; if (ev.DamageHandler is not Scp939DamageHandler damageHandler) return;
@ -56,6 +56,13 @@ public class BloodFueledManager
if (attacker == null) return; if (attacker == null) return;
if (!IsBloodFueled(attacker)) 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) if (ev.Player.Health <= 0)
{ {
@ -69,6 +76,34 @@ public class BloodFueledManager
}; };
Timing.RunCoroutine(DrainBlood()); 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<Invigorated>(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<Invigorated>();
};
} }
public static IEnumerator<float> DrainBlood() public static IEnumerator<float> DrainBlood()
@ -99,8 +134,8 @@ public class BloodFueledHandler : CustomClassHandler
{ {
public override void HandleSpawn(Player player, CustomClassConfig config, Random random) public override void HandleSpawn(Player player, CustomClassConfig config, Random random)
{ {
player.SendBroadcast("You are the <color=#6e2e99>Blood Fueled</color>!", CustomClasses.BroadcastDuration); player.SendBroadcast("You are SCP-939-<color=#C50000>Blood Fueled</color> \n Your stamina bar has been replaced by a <color=#C50000>blood meter</color>. \n You refill it by <color=#C50000>damaging</color> or <color=#C50000>killing</color> Humans. \n <color=#C50000><b>Don't let it run out.</color></b>", CustomClasses.BroadcastDuration);
const string customInfo = "<color=#A0A0A0>Blood Fueled</color>"; const string customInfo = "<color=#C50000>Blood Fueled</color>";
if (!Player.ValidateCustomInfo(customInfo, out var reason)) if (!Player.ValidateCustomInfo(customInfo, out var reason))
{ {
Logger.Error($"Invalid custom info for Blood Fueled: {reason}"); Logger.Error($"Invalid custom info for Blood Fueled: {reason}");

View File

@ -17,7 +17,6 @@ using LabApi.Loader.Features.Plugins;
using MapGeneration; using MapGeneration;
using MEC; using MEC;
using PlayerRoles; using PlayerRoles;
using PlayerRoles.PlayableScps.Scp106;
using Scp914.Processors; using Scp914.Processors;
using UnityEngine; using UnityEngine;
using Logger = LabApi.Features.Console.Logger; using Logger = LabApi.Features.Console.Logger;
@ -35,7 +34,7 @@ public sealed class CustomClasses : Plugin
public readonly CustomClassManager ClassManager = new(); public readonly CustomClassManager ClassManager = new();
public SerpentsHandManager SerpentsHandManager; public SerpentsHandManager SerpentsHandManager;
public NegromancerManager NegromancerManager; public NegromancerManager NegromancerManager;
public BloodFueledManager BloodFueledManager; public BloodFueledManager BloodFueledManager = new();
/// <inheritdoc/> /// <inheritdoc/>
public override string Name => "CustomClasses"; public override string Name => "CustomClasses";
@ -160,7 +159,6 @@ public sealed class CustomClasses : Plugin
} }
NegromancerManager = new NegromancerManager(this); NegromancerManager = new NegromancerManager(this);
BloodFueledManager = new BloodFueledManager(this);
Instance = this; Instance = this;
} }
@ -223,8 +221,7 @@ public sealed class CustomClasses : Plugin
{ {
if (random.Next(0, 100) > SerpentsHandConfig.BaseChance + state.ExtraChance) if (random.Next(0, 100) > SerpentsHandConfig.BaseChance + state.ExtraChance)
{ {
state.SetSpawned(); SerpentsHandManager.SpawnSerpentWave();
state.SetWillSpawn();
ClassManager.TryHandleSpawn(spectator, ScoutConfig, typeof(ScoutConfig), () => ClassManager.TryHandleSpawn(spectator, ScoutConfig, typeof(ScoutConfig), () =>
{ {
@ -252,7 +249,7 @@ public sealed class CustomClasses : Plugin
{ {
if (ev.Wave != RespawnWaves.MiniChaosWave) return; if (ev.Wave != RespawnWaves.MiniChaosWave) return;
if (ClassManager.GetSpawnState(typeof(SerpentsHandConfig)) is not SerpentsHandState state) return; if (ClassManager.GetSpawnState(typeof(SerpentsHandConfig)) is not SerpentsHandState state) return;
if (!state.WillSpawn) 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."); 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
/// <param name="position">The base position.</param> /// <param name="position">The base position.</param>
public void TeleportPlayerToAround(Player player, Vector3 position) public void TeleportPlayerToAround(Player player, Vector3 position)
{ {
player.Position = position + new Vector3(0, 1, 0) + new Vector3((float)(_random.NextDouble() * 2 - 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));
} }
/// <summary> /// <summary>

View File

@ -0,0 +1,8 @@
using PlayerRoles;
namespace CustomClasses;
public abstract class ExtendedClass: PlayerRoleBase
{
}

View File

@ -1,3 +1,4 @@
using AdminToys;
using CommandSystem; using CommandSystem;
using CustomPlayerEffects; using CustomPlayerEffects;
using HintServiceMeow.Core.Enum; using HintServiceMeow.Core.Enum;
@ -9,16 +10,29 @@ using LabApi.Events.Handlers;
using LabApi.Features.Permissions; using LabApi.Features.Permissions;
using LabApi.Features.Wrappers; using LabApi.Features.Wrappers;
using MEC; using MEC;
using Mirror;
using PlayerRoles; using PlayerRoles;
using UnityEngine; using UnityEngine;
using LightSourceToy = LabApi.Features.Wrappers.LightSourceToy;
using Logger = LabApi.Features.Console.Logger; using Logger = LabApi.Features.Console.Logger;
using PrimitiveObjectToy = LabApi.Features.Wrappers.PrimitiveObjectToy;
using Random = System.Random; using Random = System.Random;
namespace CustomClasses; namespace CustomClasses;
public class SerpentsHandManager 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; private readonly CustomClasses _customClasses;
public SerpentsHandManager(CustomClasses customClasses) public SerpentsHandManager(CustomClasses customClasses)
@ -114,8 +128,6 @@ public class SerpentsHandManager
{ {
yield return Timing.WaitForSeconds(1); yield return Timing.WaitForSeconds(1);
RoundSummary.singleton.ExtraTargets = Player.ReadyList.Count(IsSerpentsHand);
if (_customClasses.ClassManager.GetSpawnState(typeof(SerpentsHandConfig)) is not SerpentsHandState state) continue; if (_customClasses.ClassManager.GetSpawnState(typeof(SerpentsHandConfig)) is not SerpentsHandState state) continue;
foreach (var player in Player.ReadyList) foreach (var player in Player.ReadyList)
@ -138,20 +150,64 @@ public class SerpentsHandManager
} }
// ReSharper disable once IteratorNeverReturns // 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 sealed record SerpentsHandState: SpawnState
{ {
public bool HasSpawned => _hasSpawned || PanicDisable || Warhead.IsDetonated; public bool HasSpawned => _hasSpawned || Warhead.IsDetonated;
public float ExtraChance; public float ExtraChance;
public int Points; public int Points;
public bool WillSpawn => _willSpawn && !PanicDisable && !Warhead.IsDetonated; public bool WillSpawn => _willSpawn && !Warhead.IsDetonated;
private bool _hasSpawned; private bool _hasSpawned;
private bool _willSpawn; private bool _willSpawn;
public Vector3? SpawnLocation;
public bool PanicDisable;
public override void Reset() public override void Reset()
{ {
base.Reset(); base.Reset();
@ -159,6 +215,7 @@ public sealed record SerpentsHandState: SpawnState
ExtraChance = 0f; ExtraChance = 0f;
Points = 0; Points = 0;
_willSpawn = false; _willSpawn = false;
SpawnLocation = null;
} }
public void SetSpawned() public void SetSpawned()
@ -183,8 +240,10 @@ public sealed class SerpentsHandConfig : CustomClassConfig
public override int MaxSpawns { get; set; } = int.MaxValue; public override int MaxSpawns { get; set; } = int.MaxValue;
public override RoleTypeId RequiredRole { get; set; } = RoleTypeId.Tutorial; public override RoleTypeId RequiredRole { get; set; } = RoleTypeId.Tutorial;
public override ItemType[] Items { get; set; } = [ItemType.Painkillers, ItemType.Medkit, ItemType.ArmorCombat]; 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 public class SerpentsHandHandler : SimpleAddItemHandler
@ -192,11 +251,13 @@ public class SerpentsHandHandler : SimpleAddItemHandler
public override void HandleSpawn(Player player, CustomClassConfig config, Random random) public override void HandleSpawn(Player player, CustomClassConfig config, Random random)
{ {
base.HandleSpawn(player, config, 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]; ItemType[] guns = [ItemType.GunAK, ItemType.GunE11SR, ItemType.GunCrossvec];
var gun = guns[random.Next(0, guns.Length-1)]; var gun = guns[random.Next(0, guns.Length-1)];
var gunPickup = Pickup.Create(gun, Vector3.one); var gunPickup = Pickup.Create(gun, Vector3.one);
@ -233,52 +294,37 @@ public class SerpentsHandHandler : SimpleAddItemHandler
player.EnableEffect<MovementBoost>(20, 30); player.EnableEffect<MovementBoost>(20, 30);
player.SendBroadcast("You're a <color=#2E8B57>Serpent's Hand</color> member!", CustomClasses.BroadcastDuration); player.SendBroadcast("You're a <color=#2E8B57>Serpent's Hand</color> member!", CustomClasses.BroadcastDuration);
player.EnableEffect<SpawnProtected>(1, 20f);
} }
} }
[CommandHandler(typeof(RemoteAdminCommandHandler))] [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<string> 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))] [CommandHandler(typeof(ClientCommandHandler))]
public class PanicDisableCommand : ICommand public class SpawnSerpentsCommand : ICommand
{ {
public string Command => "panicdisableserpentshand"; public string Command => "spsh";
public string[] Aliases => []; public string[] Aliases => [];
public string Description => "Panic disable Serpents Hand."; public string Description => "Makes sure serpents hand spawns";
public bool Execute(ArraySegment<string> arguments, ICommandSender sender, out string response) public bool Execute(ArraySegment<string> 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!"; response = "You must be a player to use this command!";
return false; 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; return false;
} }
var state = (SerpentsHandState)CustomClasses.Instance.ClassManager.GetSpawnState(typeof(SerpentsHandConfig)); CustomClasses.Instance.SerpentsHandManager.SpawnSerpentWave();
state.PanicDisable = true;
response = "Serpents Hand has been disabled."; response = "success";
return true; return true;
} }
} }

4
build_deploy.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
./build.sh
./deploy.sh