diff --git a/CassieFacilityScan-EXILED2.sln b/CassieFacilityScan-EXILED2.sln new file mode 100644 index 0000000..ff866e9 --- /dev/null +++ b/CassieFacilityScan-EXILED2.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30611.23 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CassieFacilityScan", "CassieFacilityScan\CassieFacilityScan.csproj", "{2910A33D-86A9-44DB-ACFB-B8A1A5DFAEE0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2910A33D-86A9-44DB-ACFB-B8A1A5DFAEE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2910A33D-86A9-44DB-ACFB-B8A1A5DFAEE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2910A33D-86A9-44DB-ACFB-B8A1A5DFAEE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2910A33D-86A9-44DB-ACFB-B8A1A5DFAEE0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {07A2ABA1-34F5-4985-9A1A-34170E56FF00} + EndGlobalSection +EndGlobal diff --git a/CassieFacilityScan/CassieFacilityScan.cs b/CassieFacilityScan/CassieFacilityScan.cs new file mode 100644 index 0000000..bae9626 --- /dev/null +++ b/CassieFacilityScan/CassieFacilityScan.cs @@ -0,0 +1,52 @@ +using MEC; + +namespace CassieFacilityScan +{ + using System; + using Exiled.API.Enums; + using Exiled.API.Features; + using Server = Exiled.Events.Handlers.Server; + + public class CassieFacilityScan : Plugin + { + private static readonly Lazy LazyInstance = new Lazy(() => new CassieFacilityScan()); + public static CassieFacilityScan Instance => LazyInstance.Value; + + public override PluginPriority Priority { get; } = PluginPriority.Medium; + + private Handlers.Server server; + + private CassieFacilityScan() {} + + public override void OnEnabled() + { + base.OnEnabled(); + + RegisterEvents(); + } + + public override void OnDisabled() + { + base.OnDisabled(); + + UnregisterEvents(); + } + + public void RegisterEvents() + { + server = new Handlers.Server(); + + Server.RoundStarted += server.OnRoundStarted; + } + + public void UnregisterEvents() + { + Server.RoundStarted -= server.OnRoundStarted; + + server = null; + + // Kill the coroutines when disabled + Timing.KillCoroutines("cassiefacilityscan_timer"); + } + } +} diff --git a/CassieFacilityScan/CassieFacilityScan.csproj b/CassieFacilityScan/CassieFacilityScan.csproj new file mode 100644 index 0000000..2a63473 --- /dev/null +++ b/CassieFacilityScan/CassieFacilityScan.csproj @@ -0,0 +1,81 @@ + + + + + Debug + AnyCPU + {2910A33D-86A9-44DB-ACFB-B8A1A5DFAEE0} + Library + Properties + CassieFacilityScan + CassieFacilityScan + v4.8 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + + + + ..\..\EXILED\Assembly-CSharp.dll + + + ..\..\..\..\..\Games\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Assembly-CSharp-firstpass.dll + + + ..\..\EXILED\Assembly-CSharp_publicized.dll + + + ..\..\..\..\..\Games\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\CommandSystem.Core.dll + + + ..\..\EXILED\EXILED\Plugins\dependencies\Exiled.API.dll + + + ..\..\EXILED\EXILED\Plugins\Exiled.Events.dll + + + ..\..\EXILED\EXILED\Exiled.Loader.dll + + + ..\..\..\..\..\Games\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll + + + + + + + + + + + ..\..\..\..\..\Games\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll + + + + + + + + + + + + \ No newline at end of file diff --git a/CassieFacilityScan/Config.cs b/CassieFacilityScan/Config.cs new file mode 100644 index 0000000..973a831 --- /dev/null +++ b/CassieFacilityScan/Config.cs @@ -0,0 +1,48 @@ +using System.ComponentModel; + +namespace CassieFacilityScan +{ + using Exiled.API.Interfaces; + public sealed class Config : IConfig + { + public bool IsEnabled { get; set; } = true; + + [Description("Start of the scan before every class is listed.")] + public string ScanBegin { get; set; } = + "BELL_START ATTENTION . COMMENCING FACILITY SCAN .g4 . . . SCAN COMPLETED . DETECTED"; + + + [Description("Name of class d personnel count. (Use {s} for optional s, if count is greater than 1 or zero)")] + public string ClassDName { get; set; } = "CLASSD PERSONNEL"; + + [Description("Name of science personnel count. (Use {s} for optional s, if count is greater than 1 or zero)")] + public string ScientistName { get; set; } = "SCIENCE PERSONNEL"; + + [Description("Name of mtf unit count. (Use {s} for optional s, if count is greater than 1 or zero)")] + public string MtfName { get; set; } = "MTFUNIT{s}"; + + [Description("Name of scps. (Use {s} for optional s, if count is greater than 1 or zero)")] + public string ScpName { get; set; } = "NOT CONTAINED SCPSUBJECT{s}"; + + [Description("Name of choas insurgency count. (Use {s} for optional s, if count is greater than 1 or zero)")] + public string ChoasInsurgencyName { get; set; } = "CHAOSINSURGENCY"; + + [Description("Name of serpents hand count. (Use {s} for optional s, if count is greater than 1 or zero)")] + public string SerpentsHandName { get; set; } = "SERPENTS HAND"; + + [Description("End of the scan message after every class is listed.")] + public string ScanEnd { get; set; } = "BELL_END"; + + [Description("Boolean wether chaos insurgency and serpents hand should be combined into one count.")] + public bool CombineIntoUnauthorizedLifeForms { get; set; } = false; + + [Description("Name of unauthorized life forms (chaos insurgency and serpents hand) (Use {s} for optional s, if count is greater than 1 or zero)")] + public string UnauthorizedLifeFormsName { get; set; } = "UNAUTHORIZED LIFE FORM{s}"; + + [Description("Instead of saying 'no' when none of one class is detected, say 'zero'.")] + public bool SayZeroInsteadOfNo { get; set; } = false; + + [Description("Broadcast the message at start of the round.")] + public bool BroadcastAtStartOfRound { get; set; } = false; + } +} diff --git a/CassieFacilityScan/Extention.cs b/CassieFacilityScan/Extention.cs new file mode 100644 index 0000000..cd0bae6 --- /dev/null +++ b/CassieFacilityScan/Extention.cs @@ -0,0 +1,56 @@ +using System.Linq; + +namespace CassieFacilityScan +{ + using Exiled.API.Features; + using MEC; + using System.Collections.Generic; + public static class Extension + { + public static IEnumerator DelayedCassieMessage(string msg, bool makeHold, bool makeNoise, float delay) + { + yield return Timing.WaitForSeconds(delay); + Cassie.Message(msg, makeHold, makeNoise); + } + + public static string GenerateCassieMessage() + { + int classDCount = Player.Get(RoleType.ClassD).Count(); + int scientistCount = Player.Get(RoleType.Scientist).Count(); + int mtfCount = Player.Get(Team.MTF).Count(); + int scpCount = Player.Get(Team.SCP).Count(); + int chaosInsurgencyCount = Player.Get(Team.CHI).Count(); + int serpentsHandCount = Player.Get(Team.TUT).Count(); // Tutorial is Serpents Hand + + string message = $"{CassieFacilityScan.Instance.Config.ScanBegin} "; + + message += GenerateClassMessage(classDCount, CassieFacilityScan.Instance.Config.ClassDName); + message += GenerateClassMessage(scientistCount, CassieFacilityScan.Instance.Config.ScientistName); + message += GenerateClassMessage(mtfCount, CassieFacilityScan.Instance.Config.MtfName); + message += GenerateClassMessage(scpCount, CassieFacilityScan.Instance.Config.ScpName); + + if (CassieFacilityScan.Instance.Config.CombineIntoUnauthorizedLifeForms) + { + int unauthorizedLifeForms = chaosInsurgencyCount + serpentsHandCount; + message += GenerateClassMessage(unauthorizedLifeForms, + CassieFacilityScan.Instance.Config.UnauthorizedLifeFormsName); + } + else + { + message += GenerateClassMessage(chaosInsurgencyCount, CassieFacilityScan.Instance.Config.ChoasInsurgencyName); + message += GenerateClassMessage(serpentsHandCount, CassieFacilityScan.Instance.Config.SerpentsHandName); + } + + message += $"{CassieFacilityScan.Instance.Config.ScanEnd}"; + + Log.Info("Broadcasting facility scan message."); + return message; + } + + public static string GenerateClassMessage(int classCount, string classStringConfig) + { + return + $"{(classCount > 0 ? classCount.ToString() : (CassieFacilityScan.Instance.Config.SayZeroInsteadOfNo ? "0" : "NO"))} {classStringConfig.Replace("{s}", (classCount == 1 ? "" : "s"))} . "; + } + } +} \ No newline at end of file diff --git a/CassieFacilityScan/Handlers/Server.cs b/CassieFacilityScan/Handlers/Server.cs new file mode 100644 index 0000000..69a2489 --- /dev/null +++ b/CassieFacilityScan/Handlers/Server.cs @@ -0,0 +1,36 @@ +using System.Collections; +using Exiled.API.Features; +using MEC; + +namespace CassieFacilityScan.Handlers +{ + using Exiled.Events.EventArgs; + using System.Collections.Generic; + + class Server + { + public void OnRoundStarted() + { + // Kill old corountines before creating new one + Timing.KillCoroutines("cassiefacilityscan_timer"); + Timing.RunCoroutine(CassieFacilityScanMessage(), "cassiefacilityscan_timer"); + } + + public static IEnumerator CassieFacilityScanMessage() + { + yield return Timing.WaitForSeconds(0.1f); + + if (CassieFacilityScan.Instance.Config.BroadcastAtStartOfRound) + { + Timing.RunCoroutine(Extension.DelayedCassieMessage(Extension.GenerateCassieMessage(), false, false, 0), "cassiefacilityscan_timer"); + } + + while (RoundSummary.RoundInProgress()) + { + yield return Timing.WaitForSeconds(480f); + Timing.RunCoroutine(Extension.DelayedCassieMessage(Extension.GenerateCassieMessage(), false, false, 0), + "cassiefacilityscan_timer"); + } + } + } +} diff --git a/CassieFacilityScan/Properties/AssemblyInfo.cs b/CassieFacilityScan/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3d42995 --- /dev/null +++ b/CassieFacilityScan/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CassieFacilityScan")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CassieFacilityScan")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2910a33d-86a9-44db-acfb-b8a1a5dfaee0")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")]