324 lines
10 KiB
C#
324 lines
10 KiB
C#
using AdminToys;
|
|
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 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)
|
|
{
|
|
try
|
|
{
|
|
return player.CustomInfo.Contains("SerpentsHand");
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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 (Warhead.IsDetonationInProgress || Warhead.IsDetonated)
|
|
{
|
|
hadItem = true;
|
|
state.Points += 1;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
public IEnumerator<float> 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 static void SpawnSerpentWave()
|
|
{
|
|
var state = (SerpentsHandState)CustomClasses.Instance.ClassManager.GetSpawnState(typeof(SerpentsHandConfig));
|
|
|
|
var serpentsHandConfig = CustomClasses.Instance.ClassManager.GetConfig<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 || Warhead.IsDetonated;
|
|
public float ExtraChance;
|
|
public int Points;
|
|
public bool WillSpawn => _willSpawn && !Warhead.IsDetonated;
|
|
|
|
private bool _hasSpawned;
|
|
private bool _willSpawn;
|
|
public Vector3? SpawnLocation;
|
|
|
|
public override void Reset()
|
|
{
|
|
base.Reset();
|
|
_hasSpawned = false;
|
|
ExtraChance = 0f;
|
|
Points = 0;
|
|
_willSpawn = false;
|
|
SpawnLocation = null;
|
|
}
|
|
|
|
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 = 90f;
|
|
|
|
public readonly Vector3[] SpawnLocations = [new(0.22f, 300.96f, -0.31f), new(123.921f, 288.792f, 20.929f)];
|
|
public override string Color { get; init; } = "#32CD32";
|
|
public override string Name { get; init; } = "Serpents Hand";
|
|
}
|
|
|
|
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);
|
|
|
|
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<MovementBoost>(20, 30);
|
|
|
|
player.EnableEffect<SpawnProtected>(1, 20f);
|
|
}
|
|
|
|
public override void SendSpawnMessage(Player player, CustomClassConfig config)
|
|
{
|
|
player.SendBroadcast("You're a <color=#2E8B57>Serpent's Hand</color> member!", CustomClasses.BroadcastDuration);
|
|
}
|
|
}
|
|
|
|
[CommandHandler(typeof(RemoteAdminCommandHandler))]
|
|
[CommandHandler(typeof(ClientCommandHandler))]
|
|
public class SpawnSerpentsCommand : ICommand
|
|
{
|
|
public string Command => "spsh";
|
|
public string[] Aliases => [];
|
|
public string Description => "Makes sure serpents hand spawns";
|
|
|
|
public bool Execute(ArraySegment<string> arguments, ICommandSender sender, out string response)
|
|
{
|
|
var executor = Player.Get(sender);
|
|
if (executor == null)
|
|
{
|
|
response = "You must be a player to use this command!";
|
|
return false;
|
|
}
|
|
|
|
if (!executor.HasPermissions("customclasses.setcustomclass"))
|
|
{
|
|
response = "You do not have permission to use this command!";
|
|
return false;
|
|
}
|
|
|
|
SerpentsHandManager.SpawnSerpentWave();
|
|
|
|
response = "success";
|
|
return true;
|
|
}
|
|
} |